summaryrefslogtreecommitdiffstats
path: root/kmymoney2
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-07-04 22:38:03 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-07-04 22:38:03 +0000
commitdadc34655c3ab961b0b0b94a10eaaba710f0b5e8 (patch)
tree99e72842fe687baea16376a147619b6048d7e441 /kmymoney2
downloadkmymoney-dadc34655c3ab961b0b0b94a10eaaba710f0b5e8.tar.gz
kmymoney-dadc34655c3ab961b0b0b94a10eaaba710f0b5e8.zip
Added kmymoney
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kmymoney@1239792 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kmymoney2')
-rw-r--r--kmymoney2/Makefile.am171
-rw-r--r--kmymoney2/converter/Makefile.am24
-rw-r--r--kmymoney2/converter/convertertest.cpp211
-rw-r--r--kmymoney2/converter/convertertest.h45
-rw-r--r--kmymoney2/converter/imymoneyreader.h135
-rw-r--r--kmymoney2/converter/mymoneygncreader.cpp2463
-rw-r--r--kmymoney2/converter/mymoneygncreader.h904
-rw-r--r--kmymoney2/converter/mymoneyqifprofile.cpp1013
-rw-r--r--kmymoney2/converter/mymoneyqifprofile.h144
-rw-r--r--kmymoney2/converter/mymoneyqifreader.cpp2336
-rw-r--r--kmymoney2/converter/mymoneyqifreader.h394
-rw-r--r--kmymoney2/converter/mymoneyqifwriter.cpp254
-rw-r--r--kmymoney2/converter/mymoneyqifwriter.h138
-rw-r--r--kmymoney2/converter/mymoneystatementreader.cpp1354
-rw-r--r--kmymoney2/converter/mymoneystatementreader.h151
-rw-r--r--kmymoney2/converter/mymoneytemplate.cpp420
-rw-r--r--kmymoney2/converter/mymoneytemplate.h94
-rw-r--r--kmymoney2/converter/webpricequote.cpp1050
-rw-r--r--kmymoney2/converter/webpricequote.h252
-rw-r--r--kmymoney2/dialogs/Makefile.am22
-rw-r--r--kmymoney2/dialogs/investactivities.cpp624
-rw-r--r--kmymoney2/dialogs/investactivities.h158
-rw-r--r--kmymoney2/dialogs/investtransactioneditor.cpp1094
-rw-r--r--kmymoney2/dialogs/investtransactioneditor.h173
-rw-r--r--kmymoney2/dialogs/kaccountselectdlg.cpp192
-rw-r--r--kmymoney2/dialogs/kaccountselectdlg.h155
-rw-r--r--kmymoney2/dialogs/kaccountselectdlgdecl.ui215
-rw-r--r--kmymoney2/dialogs/kbackupdlg.cpp101
-rw-r--r--kmymoney2/dialogs/kbackupdlg.h44
-rw-r--r--kmymoney2/dialogs/kbackupdlgdecl.ui210
-rw-r--r--kmymoney2/dialogs/kbalancechartdlg.cpp227
-rw-r--r--kmymoney2/dialogs/kbalancechartdlg.h46
-rw-r--r--kmymoney2/dialogs/kbalancewarning.cpp67
-rw-r--r--kmymoney2/dialogs/kbalancewarning.h50
-rw-r--r--kmymoney2/dialogs/kcategoryreassigndlg.cpp106
-rw-r--r--kmymoney2/dialogs/kcategoryreassigndlg.h66
-rw-r--r--kmymoney2/dialogs/kcategoryreassigndlgdecl.ui175
-rw-r--r--kmymoney2/dialogs/kchooseimportexportdlg.cpp108
-rw-r--r--kmymoney2/dialogs/kchooseimportexportdlg.h47
-rw-r--r--kmymoney2/dialogs/kchooseimportexportdlgdecl.ui235
-rw-r--r--kmymoney2/dialogs/kconfirmmanualenterdlg.cpp202
-rw-r--r--kmymoney2/dialogs/kconfirmmanualenterdlg.h60
-rw-r--r--kmymoney2/dialogs/kconfirmmanualenterdlgdecl.ui160
-rw-r--r--kmymoney2/dialogs/kcsvprogressdlg.cpp252
-rw-r--r--kmymoney2/dialogs/kcsvprogressdlg.h68
-rw-r--r--kmymoney2/dialogs/kcsvprogressdlgdecl.ui535
-rw-r--r--kmymoney2/dialogs/kcurrencycalculator.cpp315
-rw-r--r--kmymoney2/dialogs/kcurrencycalculator.h88
-rw-r--r--kmymoney2/dialogs/kcurrencycalculatordecl.ui414
-rw-r--r--kmymoney2/dialogs/kcurrencyeditdlg.cpp291
-rw-r--r--kmymoney2/dialogs/kcurrencyeditdlg.h84
-rw-r--r--kmymoney2/dialogs/kcurrencyeditdlgdecl.ui304
-rw-r--r--kmymoney2/dialogs/keditequityentrydecl.ui306
-rw-r--r--kmymoney2/dialogs/keditequityentrydlg.cpp138
-rw-r--r--kmymoney2/dialogs/keditequityentrydlg.h69
-rw-r--r--kmymoney2/dialogs/keditloanwizard.cpp514
-rw-r--r--kmymoney2/dialogs/keditloanwizard.h89
-rw-r--r--kmymoney2/dialogs/keditscheduledlg.cpp558
-rw-r--r--kmymoney2/dialogs/keditscheduledlg.h103
-rw-r--r--kmymoney2/dialogs/keditscheduledlgdecl.ui532
-rw-r--r--kmymoney2/dialogs/kendingbalancedlg.cpp611
-rw-r--r--kmymoney2/dialogs/kendingbalancedlg.h147
-rw-r--r--kmymoney2/dialogs/kendingbalancedlgdecl.ui980
-rw-r--r--kmymoney2/dialogs/kenterscheduledlg.cpp327
-rw-r--r--kmymoney2/dialogs/kenterscheduledlg.h91
-rw-r--r--kmymoney2/dialogs/kenterscheduledlgdecl.ui330
-rw-r--r--kmymoney2/dialogs/kequitypriceupdatedlg.cpp588
-rw-r--r--kmymoney2/dialogs/kequitypriceupdatedlg.h81
-rw-r--r--kmymoney2/dialogs/kequitypriceupdatedlgdecl.ui179
-rw-r--r--kmymoney2/dialogs/kexportdlg.cpp284
-rw-r--r--kmymoney2/dialogs/kexportdlg.h180
-rw-r--r--kmymoney2/dialogs/kexportdlgdecl.ui507
-rw-r--r--kmymoney2/dialogs/kfindtransactiondlg.cpp843
-rw-r--r--kmymoney2/dialogs/kfindtransactiondlg.h203
-rw-r--r--kmymoney2/dialogs/kfindtransactiondlgdecl.ui1101
-rw-r--r--kmymoney2/dialogs/kgncimportoptionsdlg.cpp128
-rw-r--r--kmymoney2/dialogs/kgncimportoptionsdlg.h70
-rw-r--r--kmymoney2/dialogs/kgncimportoptionsdlgdecl.ui383
-rw-r--r--kmymoney2/dialogs/kgncpricesourcedlg.cpp106
-rw-r--r--kmymoney2/dialogs/kgncpricesourcedlg.h53
-rw-r--r--kmymoney2/dialogs/kgncpricesourcedlgdecl.ui248
-rw-r--r--kmymoney2/dialogs/kgpgkeyselectiondlg.cpp149
-rw-r--r--kmymoney2/dialogs/kgpgkeyselectiondlg.h66
-rw-r--r--kmymoney2/dialogs/kimportdlg.cpp228
-rw-r--r--kmymoney2/dialogs/kimportdlg.h118
-rw-r--r--kmymoney2/dialogs/kimportdlgdecl.ui246
-rw-r--r--kmymoney2/dialogs/kloadtemplatedlg.cpp55
-rw-r--r--kmymoney2/dialogs/kloadtemplatedlg.h46
-rw-r--r--kmymoney2/dialogs/kloadtemplatedlgdecl.ui106
-rw-r--r--kmymoney2/dialogs/kmergetransactionsdlg.cpp55
-rw-r--r--kmymoney2/dialogs/kmergetransactionsdlg.h52
-rw-r--r--kmymoney2/dialogs/kmymoneyfileinfodlg.cpp92
-rw-r--r--kmymoney2/dialogs/kmymoneyfileinfodlg.h44
-rw-r--r--kmymoney2/dialogs/kmymoneyfileinfodlgdecl.ui358
-rw-r--r--kmymoney2/dialogs/kmymoneypricedlg.cpp258
-rw-r--r--kmymoney2/dialogs/kmymoneypricedlg.h59
-rw-r--r--kmymoney2/dialogs/kmymoneypricedlgdecl.ui220
-rw-r--r--kmymoney2/dialogs/kmymoneysplittable.cpp999
-rw-r--r--kmymoney2/dialogs/kmymoneysplittable.h264
-rw-r--r--kmymoney2/dialogs/knewaccountdlg.cpp1209
-rw-r--r--kmymoney2/dialogs/knewaccountdlg.h143
-rw-r--r--kmymoney2/dialogs/knewaccountdlgdecl.ui1044
-rw-r--r--kmymoney2/dialogs/knewbankdlg.cpp105
-rw-r--r--kmymoney2/dialogs/knewbankdlg.h57
-rw-r--r--kmymoney2/dialogs/knewbankdlgdecl.ui268
-rw-r--r--kmymoney2/dialogs/knewbudgetdlg.cpp83
-rw-r--r--kmymoney2/dialogs/knewbudgetdlg.h59
-rw-r--r--kmymoney2/dialogs/knewbudgetdlgdecl.ui175
-rw-r--r--kmymoney2/dialogs/knewequityentrydecl.ui236
-rw-r--r--kmymoney2/dialogs/knewequityentrydlg.cpp99
-rw-r--r--kmymoney2/dialogs/knewequityentrydlg.h64
-rw-r--r--kmymoney2/dialogs/knewfiledlg.cpp138
-rw-r--r--kmymoney2/dialogs/knewfiledlg.h63
-rw-r--r--kmymoney2/dialogs/knewfiledlgdecl.ui328
-rw-r--r--kmymoney2/dialogs/knewinvestmentwizard.cpp314
-rw-r--r--kmymoney2/dialogs/knewinvestmentwizard.h94
-rw-r--r--kmymoney2/dialogs/knewinvestmentwizarddecl.ui591
-rw-r--r--kmymoney2/dialogs/knewloanwizard.cpp1088
-rw-r--r--kmymoney2/dialogs/knewloanwizard.h167
-rw-r--r--kmymoney2/dialogs/knewloanwizarddecl.ui5497
-rw-r--r--kmymoney2/dialogs/konlinequoteconfigurationdecl.ui199
-rw-r--r--kmymoney2/dialogs/konlinequoteconfigurationdlg.cpp51
-rw-r--r--kmymoney2/dialogs/konlinequoteconfigurationdlg.h49
-rw-r--r--kmymoney2/dialogs/kpayeereassigndlg.cpp81
-rw-r--r--kmymoney2/dialogs/kpayeereassigndlg.h74
-rw-r--r--kmymoney2/dialogs/kpayeereassigndlgdecl.ui186
-rw-r--r--kmymoney2/dialogs/kplugindlg.ui154
-rw-r--r--kmymoney2/dialogs/krecentfileitem.cpp62
-rw-r--r--kmymoney2/dialogs/krecentfileitem.h56
-rw-r--r--kmymoney2/dialogs/kreconciledlg.cpp463
-rw-r--r--kmymoney2/dialogs/kreconciledlg.h90
-rw-r--r--kmymoney2/dialogs/kreconciledlgdecl.ui709
-rw-r--r--kmymoney2/dialogs/kreportconfigurationfilterdlg.cpp687
-rw-r--r--kmymoney2/dialogs/kreportconfigurationfilterdlg.h78
-rw-r--r--kmymoney2/dialogs/ksecuritylisteditor.cpp220
-rw-r--r--kmymoney2/dialogs/ksecuritylisteditor.h58
-rw-r--r--kmymoney2/dialogs/ksecuritylisteditordecl.ui262
-rw-r--r--kmymoney2/dialogs/kselectdatabasedlg.cpp232
-rw-r--r--kmymoney2/dialogs/kselectdatabasedlg.h64
-rw-r--r--kmymoney2/dialogs/kselectdatabasedlgdecl.ui250
-rw-r--r--kmymoney2/dialogs/kselecttransactionsdlg.cpp178
-rw-r--r--kmymoney2/dialogs/kselecttransactionsdlg.h73
-rw-r--r--kmymoney2/dialogs/kselecttransactionsdlgdecl.ui174
-rw-r--r--kmymoney2/dialogs/ksortoptiondlg.ui129
-rw-r--r--kmymoney2/dialogs/ksortoptiondlg.ui.h53
-rw-r--r--kmymoney2/dialogs/ksplitcorrectiondlg.ui245
-rw-r--r--kmymoney2/dialogs/ksplittransactiondlg.cpp449
-rw-r--r--kmymoney2/dialogs/ksplittransactiondlg.h174
-rw-r--r--kmymoney2/dialogs/ksplittransactiondlgdecl.ui424
-rw-r--r--kmymoney2/dialogs/kstartdlg.cpp243
-rw-r--r--kmymoney2/dialogs/kstartdlg.h84
-rw-r--r--kmymoney2/dialogs/kupdatestockpricedlg.cpp119
-rw-r--r--kmymoney2/dialogs/kupdatestockpricedlg.h77
-rw-r--r--kmymoney2/dialogs/kupdatestockpricedlgdecl.ui257
-rw-r--r--kmymoney2/dialogs/mymoneyqifprofileeditor.cpp483
-rw-r--r--kmymoney2/dialogs/mymoneyqifprofileeditor.h96
-rw-r--r--kmymoney2/dialogs/mymoneyqifprofileeditordecl.ui905
-rw-r--r--kmymoney2/dialogs/settings/Makefile.am25
-rw-r--r--kmymoney2/dialogs/settings/ksettingscolors.cpp37
-rw-r--r--kmymoney2/dialogs/settings/ksettingscolors.h40
-rw-r--r--kmymoney2/dialogs/settings/ksettingscolorsdecl.ui406
-rw-r--r--kmymoney2/dialogs/settings/ksettingsfonts.cpp37
-rw-r--r--kmymoney2/dialogs/settings/ksettingsfonts.h40
-rw-r--r--kmymoney2/dialogs/settings/ksettingsfontsdecl.ui131
-rw-r--r--kmymoney2/dialogs/settings/ksettingsforecast.cpp37
-rw-r--r--kmymoney2/dialogs/settings/ksettingsforecast.h41
-rw-r--r--kmymoney2/dialogs/settings/ksettingsforecastdecl.ui268
-rw-r--r--kmymoney2/dialogs/settings/ksettingsgeneral.cpp63
-rw-r--r--kmymoney2/dialogs/settings/ksettingsgeneral.h44
-rw-r--r--kmymoney2/dialogs/settings/ksettingsgeneraldecl.ui646
-rw-r--r--kmymoney2/dialogs/settings/ksettingsgpg.cpp200
-rw-r--r--kmymoney2/dialogs/settings/ksettingsgpg.h54
-rw-r--r--kmymoney2/dialogs/settings/ksettingsgpgdecl.ui238
-rw-r--r--kmymoney2/dialogs/settings/ksettingshome.cpp173
-rw-r--r--kmymoney2/dialogs/settings/ksettingshome.h52
-rw-r--r--kmymoney2/dialogs/settings/ksettingshomedecl.ui231
-rw-r--r--kmymoney2/dialogs/settings/ksettingsonlinequotes.cpp219
-rw-r--r--kmymoney2/dialogs/settings/ksettingsonlinequotes.h59
-rw-r--r--kmymoney2/dialogs/settings/ksettingsonlinequotesdecl.ui234
-rw-r--r--kmymoney2/dialogs/settings/ksettingsplugins.cpp66
-rw-r--r--kmymoney2/dialogs/settings/ksettingsplugins.h47
-rw-r--r--kmymoney2/dialogs/settings/ksettingsregister.cpp75
-rw-r--r--kmymoney2/dialogs/settings/ksettingsregister.h45
-rw-r--r--kmymoney2/dialogs/settings/ksettingsregisterdecl.ui549
-rw-r--r--kmymoney2/dialogs/settings/ksettingsschedules.cpp37
-rw-r--r--kmymoney2/dialogs/settings/ksettingsschedules.h41
-rw-r--r--kmymoney2/dialogs/settings/ksettingsschedulesdecl.ui145
-rw-r--r--kmymoney2/dialogs/transactioneditor.cpp2156
-rw-r--r--kmymoney2/dialogs/transactioneditor.h416
-rw-r--r--kmymoney2/dialogs/transactionmatcher.cpp361
-rw-r--r--kmymoney2/dialogs/transactionmatcher.h145
-rw-r--r--kmymoney2/export.h37
-rw-r--r--kmymoney2/hi128-app-kmymoney2.pngbin0 -> 21061 bytes
-rw-r--r--kmymoney2/hi16-app-kmymoney2.pngbin0 -> 981 bytes
-rw-r--r--kmymoney2/hi32-app-kmymoney2.pngbin0 -> 2692 bytes
-rw-r--r--kmymoney2/hi48-app-kmymoney2.pngbin0 -> 5041 bytes
-rw-r--r--kmymoney2/hi64-app-kmymoney2.pngbin0 -> 7782 bytes
-rw-r--r--kmymoney2/html/Makefile.am23
-rw-r--r--kmymoney2/html/home.html59
-rw-r--r--kmymoney2/html/home_de.html58
-rw-r--r--kmymoney2/html/home_es.html58
-rw-r--r--kmymoney2/html/home_fr.html61
-rw-r--r--kmymoney2/html/home_gl.html57
-rw-r--r--kmymoney2/html/home_it.html59
-rw-r--r--kmymoney2/html/home_nl.html58
-rw-r--r--kmymoney2/html/home_pt.html57
-rw-r--r--kmymoney2/html/home_pt_BR.html58
-rw-r--r--kmymoney2/html/home_ro.html58
-rw-r--r--kmymoney2/html/home_ru.html56
-rw-r--r--kmymoney2/html/home_tr.html57
-rw-r--r--kmymoney2/html/images/Makefile.am20
-rw-r--r--kmymoney2/html/images/about_kde.pngbin0 -> 3044 bytes
-rw-r--r--kmymoney2/html/images/arrow.pngbin0 -> 434 bytes
-rw-r--r--kmymoney2/html/images/backarrow.pngbin0 -> 428 bytes
-rw-r--r--kmymoney2/html/images/background.pngbin0 -> 249479 bytes
-rw-r--r--kmymoney2/html/images/bc.pngbin0 -> 174 bytes
-rw-r--r--kmymoney2/html/images/bg-texture.pngbin0 -> 2902 bytes
-rw-r--r--kmymoney2/html/images/bl.pngbin0 -> 644 bytes
-rw-r--r--kmymoney2/html/images/bottomleft.pngbin0 -> 872 bytes
-rw-r--r--kmymoney2/html/images/bottomright.pngbin0 -> 309 bytes
-rw-r--r--kmymoney2/html/images/br.pngbin0 -> 650 bytes
-rw-r--r--kmymoney2/html/images/center.pngbin0 -> 156 bytes
-rw-r--r--kmymoney2/html/images/currencyflourish.pngbin0 -> 18477 bytes
-rw-r--r--kmymoney2/html/images/filenew.pngbin0 -> 1533 bytes
-rw-r--r--kmymoney2/html/images/kmymoneydata.pngbin0 -> 2482 bytes
-rw-r--r--kmymoney2/html/images/konqueror.pngbin0 -> 2923 bytes
-rw-r--r--kmymoney2/html/images/lc.pngbin0 -> 167 bytes
-rw-r--r--kmymoney2/html/images/manual.pngbin0 -> 1642 bytes
-rw-r--r--kmymoney2/html/images/messagebox_info.pngbin0 -> 1514 bytes
-rw-r--r--kmymoney2/html/images/original-trans_logo.pngbin0 -> 9012 bytes
-rw-r--r--kmymoney2/html/images/rc.pngbin0 -> 185 bytes
-rw-r--r--kmymoney2/html/images/rightborder.pngbin0 -> 153 bytes
-rw-r--r--kmymoney2/html/images/shadow.pngbin0 -> 7606 bytes
-rw-r--r--kmymoney2/html/images/spacer.gifbin0 -> 43 bytes
-rw-r--r--kmymoney2/html/images/spacer.pngbin0 -> 148 bytes
-rw-r--r--kmymoney2/html/images/tc.pngbin0 -> 180 bytes
-rw-r--r--kmymoney2/html/images/title-center.pngbin0 -> 186 bytes
-rw-r--r--kmymoney2/html/images/title-left.pngbin0 -> 349 bytes
-rw-r--r--kmymoney2/html/images/title-right.pngbin0 -> 345 bytes
-rw-r--r--kmymoney2/html/images/tl.pngbin0 -> 595 bytes
-rw-r--r--kmymoney2/html/images/top-shadow.pngbin0 -> 279 bytes
-rw-r--r--kmymoney2/html/images/topleft.pngbin0 -> 18188 bytes
-rw-r--r--kmymoney2/html/images/topright.pngbin0 -> 180 bytes
-rw-r--r--kmymoney2/html/images/tr.pngbin0 -> 625 bytes
-rw-r--r--kmymoney2/html/images/trans_logo.pngbin0 -> 12151 bytes
-rw-r--r--kmymoney2/html/kmymoney2.css370
-rw-r--r--kmymoney2/html/welcome.css171
-rw-r--r--kmymoney2/html/whats_new.html97
-rw-r--r--kmymoney2/html/whats_new_de.html97
-rw-r--r--kmymoney2/html/whats_new_es.html99
-rw-r--r--kmymoney2/html/whats_new_fr.html104
-rw-r--r--kmymoney2/html/whats_new_gl.html65
-rw-r--r--kmymoney2/html/whats_new_it.html97
-rw-r--r--kmymoney2/html/whats_new_nl.html63
-rw-r--r--kmymoney2/html/whats_new_pt_BR.html98
-rw-r--r--kmymoney2/html/whats_new_ro.html97
-rw-r--r--kmymoney2/html/whats_new_ru.html76
-rw-r--r--kmymoney2/html/whats_new_tr.html63
-rw-r--r--kmymoney2/icons/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/128x128/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_asset.pngbin0 -> 12907 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_cash.pngbin0 -> 14945 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_checking.pngbin0 -> 8624 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_closed.pngbin0 -> 466 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_credit-card.pngbin0 -> 9758 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_expense.pngbin0 -> 7271 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_income.pngbin0 -> 7570 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_investments.pngbin0 -> 4746 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_liability.pngbin0 -> 8573 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_loan.pngbin0 -> 5855 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account-types_savings.pngbin0 -> 15137 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account.pngbin0 -> 7053 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/account_add.pngbin0 -> 8553 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/accounts.pngbin0 -> 7053 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/budget.pngbin0 -> 9342 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/categories.pngbin0 -> 7212 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/forcast.pngbin0 -> 15629 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/institution_add.pngbin0 -> 5347 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/institutions.pngbin0 -> 3405 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/investments.pngbin0 -> 10865 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/ledger.pngbin0 -> 1945 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/onlinebanking.pngbin0 -> 8328 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/payee.pngbin0 -> 15103 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/reconcile.pngbin0 -> 11718 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/report.pngbin0 -> 7758 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/schedule.pngbin0 -> 7601 bytes
-rw-r--r--kmymoney2/icons/Tango/128x128/apps/transaction_find.pngbin0 -> 10178 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_asset.pngbin0 -> 966 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_cash.pngbin0 -> 789 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_checking.pngbin0 -> 719 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_closed.pngbin0 -> 160 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_credit-card.pngbin0 -> 673 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_expense.pngbin0 -> 673 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_income.pngbin0 -> 677 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_investments.pngbin0 -> 654 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_liability.pngbin0 -> 791 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_loan.pngbin0 -> 700 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account-types_savings.pngbin0 -> 863 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account.pngbin0 -> 825 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/account_add.pngbin0 -> 908 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/accounts.pngbin0 -> 825 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/backup.pngbin0 -> 868 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/bank.pngbin0 -> 825 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/budget.pngbin0 -> 813 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/categories.pngbin0 -> 716 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/close_window.pngbin0 -> 659 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/delete.pngbin0 -> 627 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/forcast.pngbin0 -> 938 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/hide_categories.pngbin0 -> 804 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/hide_reconciled.pngbin0 -> 512 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/institution_add.pngbin0 -> 741 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/institutions.pngbin0 -> 600 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/investments.pngbin0 -> 835 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/ledger.pngbin0 -> 485 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/onlinebanking.pngbin0 -> 855 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/payee.pngbin0 -> 850 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/personal_data.pngbin0 -> 883 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/reconcile.pngbin0 -> 762 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/report.pngbin0 -> 781 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/schedule.pngbin0 -> 806 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/split_transaction.pngbin0 -> 376 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/transaction_find.pngbin0 -> 740 bytes
-rw-r--r--kmymoney2/icons/Tango/16x16/actions/view_info.pngbin0 -> 816 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_asset.pngbin0 -> 1356 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_cash.pngbin0 -> 1221 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_checking.pngbin0 -> 1040 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_closed.pngbin0 -> 167 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_credit-card.pngbin0 -> 995 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_expense.pngbin0 -> 952 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_income.pngbin0 -> 963 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_investments.pngbin0 -> 915 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_liability.pngbin0 -> 1110 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_loan.pngbin0 -> 978 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account-types_savings.pngbin0 -> 1387 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account.pngbin0 -> 1181 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/account_add.pngbin0 -> 1331 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/accounts.pngbin0 -> 1181 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/attention.pngbin0 -> 881 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/backup.pngbin0 -> 1181 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/bank.pngbin0 -> 1181 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/budget.pngbin0 -> 1207 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/categories.pngbin0 -> 993 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/close_window.pngbin0 -> 929 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/delete.pngbin0 -> 939 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/forcast.pngbin0 -> 1385 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/hide_categories.pngbin0 -> 1138 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/hide_reconciled.pngbin0 -> 664 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/institution_add.pngbin0 -> 1284 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/institutions.pngbin0 -> 1090 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/investments.pngbin0 -> 1232 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/ledger.pngbin0 -> 802 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/onlinebanking.pngbin0 -> 1259 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/payee.pngbin0 -> 1254 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/personal_data.pngbin0 -> 1261 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/reconcile.pngbin0 -> 1148 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/report.pngbin0 -> 1176 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/schedule.pngbin0 -> 1136 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/transaction_find.pngbin0 -> 1069 bytes
-rw-r--r--kmymoney2/icons/Tango/22x22/actions/view_info.pngbin0 -> 1176 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_asset.pngbin0 -> 2245 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_cash.pngbin0 -> 2086 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_checking.pngbin0 -> 1616 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_closed.pngbin0 -> 180 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_credit-card.pngbin0 -> 1653 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_expense.pngbin0 -> 1354 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_income.pngbin0 -> 1429 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_investments.pngbin0 -> 1208 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_liability.pngbin0 -> 1676 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_loan.pngbin0 -> 1410 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account-types_savings.pngbin0 -> 2326 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account.pngbin0 -> 1737 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/account_add.pngbin0 -> 2028 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/accounts.pngbin0 -> 1737 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/budget.pngbin0 -> 1749 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/categories.pngbin0 -> 1472 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/forcast.pngbin0 -> 2276 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/institution_add.pngbin0 -> 1659 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/institutions.pngbin0 -> 1159 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/investments.pngbin0 -> 1871 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/ledger.pngbin0 -> 710 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/onlinebanking.pngbin0 -> 1817 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/payee.pngbin0 -> 2104 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/reconcile.pngbin0 -> 1829 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/report.pngbin0 -> 1599 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/schedule.pngbin0 -> 1680 bytes
-rw-r--r--kmymoney2/icons/Tango/32x32/apps/transaction_find.pngbin0 -> 1696 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_asset.pngbin0 -> 3816 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_cash.pngbin0 -> 3760 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_checking.pngbin0 -> 2559 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_closed.pngbin0 -> 214 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_credit-card.pngbin0 -> 2704 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_expense.pngbin0 -> 2143 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_income.pngbin0 -> 2183 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_investments.pngbin0 -> 1606 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_liability.pngbin0 -> 2803 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_loan.pngbin0 -> 1927 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account-types_savings.pngbin0 -> 4209 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account.pngbin0 -> 2298 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/account_add.pngbin0 -> 2967 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/accounts.pngbin0 -> 2298 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/budget.pngbin0 -> 2704 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/categories.pngbin0 -> 2405 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/forcast.pngbin0 -> 4019 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/institution_add.pngbin0 -> 1889 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/institutions.pngbin0 -> 1150 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/investments.pngbin0 -> 2983 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/ledger.pngbin0 -> 694 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/onlinebanking.pngbin0 -> 2860 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/payee.pngbin0 -> 3855 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/reconcile.pngbin0 -> 3096 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/report.pngbin0 -> 2305 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/schedule.pngbin0 -> 2592 bytes
-rw-r--r--kmymoney2/icons/Tango/48x48/apps/transaction_find.pngbin0 -> 2850 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_asset.pngbin0 -> 5518 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_cash.pngbin0 -> 5818 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_checking.pngbin0 -> 3738 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_closed.pngbin0 -> 282 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_credit-card.pngbin0 -> 4057 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_expense.pngbin0 -> 3120 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_income.pngbin0 -> 3137 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_investments.pngbin0 -> 2387 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_liability.pngbin0 -> 4038 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_loan.pngbin0 -> 2900 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account-types_savings.pngbin0 -> 6430 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account.pngbin0 -> 3709 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/account_add.pngbin0 -> 4403 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/accounts.pngbin0 -> 3709 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/budget.pngbin0 -> 4138 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/categories.pngbin0 -> 3358 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/forcast.pngbin0 -> 6057 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/institution_add.pngbin0 -> 3043 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/institutions.pngbin0 -> 2209 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/investments.pngbin0 -> 4513 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/ledger.pngbin0 -> 1200 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/onlinebanking.pngbin0 -> 4134 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/payee.pngbin0 -> 5829 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/reconcile.pngbin0 -> 4764 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/report.pngbin0 -> 3473 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/schedule.pngbin0 -> 3689 bytes
-rw-r--r--kmymoney2/icons/Tango/64x64/apps/transaction_find.pngbin0 -> 4199 bytes
-rw-r--r--kmymoney2/icons/Tango/Makefile.am1
-rw-r--r--kmymoney2/icons/Tango/scalable/Makefile.am6
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_asset.svgzbin0 -> 8237 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_cash.svgzbin0 -> 3999 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_checking.svgzbin0 -> 3686 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_closed.svgzbin0 -> 946 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_credit-card.svgzbin0 -> 2791 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_expense.svgzbin0 -> 2289 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_income.svgzbin0 -> 2221 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_investments.svgzbin0 -> 4324 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_liability.svgzbin0 -> 3575 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_loan.svgzbin0 -> 3044 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account-types_savings.svgzbin0 -> 4420 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account.svgzbin0 -> 2570 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/account_add.svgzbin0 -> 3006 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/accounts.svgzbin0 -> 2570 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/backup.svgzbin0 -> 3802 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/bank.svgzbin0 -> 2570 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/budget.svgzbin0 -> 5382 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/categories.svgzbin0 -> 5964 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/forcast.svgzbin0 -> 3617 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/hide_categories.svgzbin0 -> 6523 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/hide_reconciled.svgzbin0 -> 1335 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/institution_add.svgzbin0 -> 2710 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/institutions.svgzbin0 -> 2078 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/investments.svgzbin0 -> 4324 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/ledger.svgzbin0 -> 3113 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/onlinebanking.svgzbin0 -> 4377 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/payee.svgzbin0 -> 4041 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/personal_data.svgzbin0 -> 5714 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/reconcile.svgzbin0 -> 5152 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/report.svgzbin0 -> 4317 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/schedule.svgzbin0 -> 5223 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/transaction_find.svgzbin0 -> 5203 bytes
-rw-r--r--kmymoney2/icons/Tango/scalable/view_info.svgzbin0 -> 6909 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/Makefile.am8
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/Makefile.am17
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/account-type_asset.pngbin0 -> 948 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/account-type_expense.pngbin0 -> 820 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/account-type_income.pngbin0 -> 834 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/account-type_liability.pngbin0 -> 900 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/account_add.pngbin0 -> 478 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/account_open.pngbin0 -> 903 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/backup.pngbin0 -> 854 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/bank.pngbin0 -> 840 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/categories.pngbin0 -> 462 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/close_window.pngbin0 -> 659 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/delete.pngbin0 -> 627 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/hide_categories.pngbin0 -> 874 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/hide_reconciled.pngbin0 -> 421 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/institution_add.pngbin0 -> 885 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/ledger.pngbin0 -> 267 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/pay_edit.pngbin0 -> 300 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/personal_data.pngbin0 -> 762 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/reconcile.pngbin0 -> 589 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/split_transaction.pngbin0 -> 376 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/transaction.pngbin0 -> 151 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/transaction_export.pngbin0 -> 580 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/transaction_find.pngbin0 -> 659 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/transaction_import.pngbin0 -> 588 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/unreconciled.pngbin0 -> 279 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/update_prices.pngbin0 -> 775 bytes
-rw-r--r--kmymoney2/icons/hicolor/16x16/actions/view_info.pngbin0 -> 751 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/Makefile.am8
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/Makefile.am17
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_asset.pngbin0 -> 1280 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_closed.pngbin0 -> 409 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_expense.pngbin0 -> 1107 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_income.pngbin0 -> 1142 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_liability.pngbin0 -> 1223 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_online.pngbin0 -> 296 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account-types_reconcile.pngbin0 -> 377 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account_add.pngbin0 -> 695 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/account_open.pngbin0 -> 1301 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/attention.pngbin0 -> 881 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/backup.pngbin0 -> 1358 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/bank.pngbin0 -> 1362 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/categories.pngbin0 -> 650 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/cleared.pngbin0 -> 209 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/close_window.pngbin0 -> 929 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/delete.pngbin0 -> 939 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/hide_categories.pngbin0 -> 982 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/hide_reconciled.pngbin0 -> 543 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/institution_add.pngbin0 -> 1331 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/ledger.pngbin0 -> 296 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/pay_edit.pngbin0 -> 352 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/personal_data.pngbin0 -> 1166 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/reconcile.pngbin0 -> 888 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/report-bar.pngbin0 -> 1170 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/report-line.pngbin0 -> 1346 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/report-pie.pngbin0 -> 1320 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/report-solid.pngbin0 -> 1309 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/report-text.pngbin0 -> 734 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/set_as.pngbin0 -> 209 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/transaction.pngbin0 -> 160 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/transaction_export.pngbin0 -> 728 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/transaction_find.pngbin0 -> 970 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/transaction_import.pngbin0 -> 737 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/unreconciled.pngbin0 -> 324 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/update_prices.pngbin0 -> 1220 bytes
-rw-r--r--kmymoney2/icons/hicolor/22x22/actions/view_info.pngbin0 -> 1082 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/Makefile.am8
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/Makefile.am18
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_asset.pngbin0 -> 3140 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_cash.pngbin0 -> 2231 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_checking.pngbin0 -> 2319 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_credit-card.pngbin0 -> 2773 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_investments.pngbin0 -> 2607 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_liability.pngbin0 -> 2702 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_loan.pngbin0 -> 1885 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_reconciled.pngbin0 -> 435 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/account-types_savings.pngbin0 -> 2934 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/accounts.pngbin0 -> 2003 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/budget.pngbin0 -> 1709 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/categories.pngbin0 -> 2124 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/forcast.pngbin0 -> 1912 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/home.pngbin0 -> 2539 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/institutions.pngbin0 -> 2439 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/investments.pngbin0 -> 3031 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/ledger.pngbin0 -> 1685 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/onlinebanking.pngbin0 -> 2574 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/payee.pngbin0 -> 2468 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/report.pngbin0 -> 1970 bytes
-rw-r--r--kmymoney2/icons/hicolor/32x32/apps/schedule.pngbin0 -> 2489 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/Makefile.am8
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/Makefile.am18
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_asset.pngbin0 -> 5816 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_cash.pngbin0 -> 4122 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_checking.pngbin0 -> 4231 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_credit-card.pngbin0 -> 5229 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_investment.pngbin0 -> 4869 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_liability.pngbin0 -> 4940 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_loan.pngbin0 -> 3448 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/account-types_savings.pngbin0 -> 5475 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/accounts.pngbin0 -> 3433 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/budget.pngbin0 -> 2747 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/categories.pngbin0 -> 3788 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/forcast.pngbin0 -> 3194 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/home.pngbin0 -> 3719 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/institutions.pngbin0 -> 4475 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/investments.pngbin0 -> 5664 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/ledger.pngbin0 -> 2812 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/onlinebanking.pngbin0 -> 4666 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/payee.pngbin0 -> 4404 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/report.pngbin0 -> 3620 bytes
-rw-r--r--kmymoney2/icons/hicolor/48x48/apps/schedule.pngbin0 -> 4515 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/Makefile.am8
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/Makefile.am18
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_asset.pngbin0 -> 9026 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_cash.pngbin0 -> 6340 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_checking.pngbin0 -> 6606 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_credit-card.pngbin0 -> 8253 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_investments.pngbin0 -> 7318 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_liability.pngbin0 -> 7611 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_loan.pngbin0 -> 4998 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/account-types_savings.pngbin0 -> 8608 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/accounts.pngbin0 -> 5036 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/budget.pngbin0 -> 4105 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/categories.pngbin0 -> 5832 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/forcast.pngbin0 -> 4723 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/home.pngbin0 -> 5212 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/institutions.pngbin0 -> 6703 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/investments.pngbin0 -> 8841 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/ledger.pngbin0 -> 3825 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/onlinebanking.pngbin0 -> 7126 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/payee.pngbin0 -> 6733 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/report.pngbin0 -> 5372 bytes
-rw-r--r--kmymoney2/icons/hicolor/64x64/apps/schedule.pngbin0 -> 6748 bytes
-rw-r--r--kmymoney2/icons/hicolor/Makefile.am8
-rw-r--r--kmymoney2/icons/oxygen/128x128/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-add.pngbin0 -> 23643 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_asset.pngbin0 -> 5734 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_cash.pngbin0 -> 19437 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_checking.pngbin0 -> 15248 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_closed.pngbin0 -> 7243 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_credit-card.pngbin0 -> 14397 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_investments.pngbin0 -> 9801 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_liability.pngbin0 -> 5860 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/account-types_loan.pngbin0 -> 19370 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/accounts.pngbin0 -> 19872 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/budget.pngbin0 -> 19318 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/categories.pngbin0 -> 6132 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/forcast.pngbin0 -> 20922 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/institutions.pngbin0 -> 12482 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/investments.pngbin0 -> 9801 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/ledger.pngbin0 -> 23055 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/onlinebanking.pngbin0 -> 18336 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/payee.pngbin0 -> 13851 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/reconcile.pngbin0 -> 12540 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/report.pngbin0 -> 14762 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/schedule.pngbin0 -> 5879 bytes
-rw-r--r--kmymoney2/icons/oxygen/128x128/apps/transaction_find.pngbin0 -> 26352 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_asset.pngbin0 -> 679 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_cash.pngbin0 -> 822 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_checking.pngbin0 -> 812 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_closed.pngbin0 -> 570 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_credit-card.pngbin0 -> 772 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_expense.pngbin0 -> 699 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_income.pngbin0 -> 699 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_investments.pngbin0 -> 897 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_liability.pngbin0 -> 679 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_loan.pngbin0 -> 853 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/account-types_savings.pngbin0 -> 890 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/accounts.pngbin0 -> 918 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/budget.pngbin0 -> 960 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/forcast.pngbin0 -> 900 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/institutions.pngbin0 -> 736 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/investments.pngbin0 -> 897 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/ledger.pngbin0 -> 996 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/onlinebanking.pngbin0 -> 906 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/payee.pngbin0 -> 782 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/report.pngbin0 -> 833 bytes
-rw-r--r--kmymoney2/icons/oxygen/16x16/actions/schedule.pngbin0 -> 745 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/account-types_cash.pngbin0 -> 1265 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/account-types_checking.pngbin0 -> 1232 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/account-types_credit-card.pngbin0 -> 1181 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/account-types_investments.pngbin0 -> 1286 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/account-types_loan.pngbin0 -> 1342 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/account-types_savings.pngbin0 -> 1345 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/accounts.pngbin0 -> 1470 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/budget.pngbin0 -> 1553 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/forcast.pngbin0 -> 1414 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/institutions.pngbin0 -> 919 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/investments.pngbin0 -> 1286 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/ledger.pngbin0 -> 1592 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/onlinebanking.pngbin0 -> 1387 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/payee.pngbin0 -> 1135 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/report.pngbin0 -> 1249 bytes
-rw-r--r--kmymoney2/icons/oxygen/22x22/actions/schedule.pngbin0 -> 1056 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/account-types_closed.pngbin0 -> 1290 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/account-types_expense.pngbin0 -> 1514 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/account-types_income.pngbin0 -> 1598 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/account_add.pngbin0 -> 3000 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/accounts.pngbin0 -> 2434 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/budget.pngbin0 -> 2630 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/categories.pngbin0 -> 1119 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/forcast.pngbin0 -> 2435 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/institution_add.pngbin0 -> 2297 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/institutions.pngbin0 -> 2109 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/investments.pngbin0 -> 1834 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/ledger.pngbin0 -> 2874 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/onlinebanking.pngbin0 -> 2221 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/payee.pngbin0 -> 1619 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/reconcile.pngbin0 -> 1985 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/report.pngbin0 -> 1463 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/schedule.pngbin0 -> 1623 bytes
-rw-r--r--kmymoney2/icons/oxygen/32x32/apps/transaction_find.pngbin0 -> 2938 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/account-types_closed.pngbin0 -> 2151 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/account-types_expense.pngbin0 -> 2537 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/account-types_income.pngbin0 -> 2671 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/account_add.pngbin0 -> 5747 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/accounts.pngbin0 -> 4629 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/budget.pngbin0 -> 4780 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/categories.pngbin0 -> 1903 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/forcast.pngbin0 -> 4621 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/institution_add.pngbin0 -> 4050 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/institutions.pngbin0 -> 3618 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/investments.pngbin0 -> 2797 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/ledger.pngbin0 -> 5396 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/onlinebanking.pngbin0 -> 3854 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/payee.pngbin0 -> 2846 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/reconcile.pngbin0 -> 3326 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/report.pngbin0 -> 2581 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/schedule.pngbin0 -> 2259 bytes
-rw-r--r--kmymoney2/icons/oxygen/48x48/apps/transaction_find.pngbin0 -> 5577 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/account-add.pngbin0 -> 8687 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/account-types_closed.pngbin0 -> 3089 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/accounts.pngbin0 -> 7164 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/budget.pngbin0 -> 7170 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/categories.pngbin0 -> 2619 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/forcast.pngbin0 -> 7166 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/institutions.pngbin0 -> 5198 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/investments.pngbin0 -> 3742 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/ledger.pngbin0 -> 8247 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/onlinebanking.pngbin0 -> 5970 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/payee.pngbin0 -> 4181 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/reconcile.pngbin0 -> 4966 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/report.pngbin0 -> 4439 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/schedule.pngbin0 -> 2909 bytes
-rw-r--r--kmymoney2/icons/oxygen/64x64/apps/transaction_find.pngbin0 -> 8899 bytes
-rw-r--r--kmymoney2/icons/oxygen/Makefile.am1
-rw-r--r--kmymoney2/icons/oxygen/scalable/Makefile.am6
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-add.svgzbin0 -> 19998 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_asset.svgzbin0 -> 2434 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_cash.svgzbin0 -> 20327 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_checking.svgzbin0 -> 22305 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_closed.svgzbin0 -> 1962 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_credit-card.svgzbin0 -> 17049 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_expense.svgzbin0 -> 4237 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_income.svgzbin0 -> 4014 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_investments.svgzbin0 -> 41543 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_liability.svgzbin0 -> 2242 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_loan.svgzbin0 -> 7411 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/account-types_savings.svgzbin0 -> 7522 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/accounts.svgzbin0 -> 10302 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/budget.svgzbin0 -> 64305 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/categories.svgzbin0 -> 5302 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/forcast.svgzbin0 -> 24877 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/hide_categories.svgzbin0 -> 7163 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/hide_reconciled.svgzbin0 -> 1344 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/institution_add.svgzbin0 -> 9980 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/institutions.svgzbin0 -> 7888 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/investments.svgzbin0 -> 41543 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/ledger.svgzbin0 -> 15912 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/onlinebanking.svgzbin0 -> 264427 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/payee.svgzbin0 -> 27572 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/personal_data.svgzbin0 -> 8993 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/reconcile.svgzbin0 -> 6528 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/report.svgzbin0 -> 8487 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/schedule.svgzbin0 -> 156180 bytes
-rw-r--r--kmymoney2/icons/oxygen/scalable/transaction_find.svgzbin0 -> 23822 bytes
-rw-r--r--kmymoney2/kmymoney2.cpp6209
-rw-r--r--kmymoney2/kmymoney2.desktop23
-rw-r--r--kmymoney2/kmymoney2.h1306
-rw-r--r--kmymoney2/kmymoney2.kcfg381
-rw-r--r--kmymoney2/kmymoney2ui.rc260
-rw-r--r--kmymoney2/kmymoney_wizard.pngbin0 -> 1470 bytes
-rw-r--r--kmymoney2/kmymoneyglobalsettings.cpp96
-rw-r--r--kmymoney2/kmymoneyglobalsettings.h46
-rw-r--r--kmymoney2/kmymoneysettings.kcfgc4
-rw-r--r--kmymoney2/kmymoneytest.cpp231
-rw-r--r--kmymoney2/kmymoneyutils.cpp480
-rw-r--r--kmymoney2/kmymoneyutils.h382
-rw-r--r--kmymoney2/kstartuplogo.cpp113
-rw-r--r--kmymoney2/kstartuplogo.h62
-rw-r--r--kmymoney2/lo16-app-kmymoney2.pngbin0 -> 772 bytes
-rw-r--r--kmymoney2/lo32-app-kmymoney2.pngbin0 -> 2692 bytes
-rw-r--r--kmymoney2/main.cpp315
-rw-r--r--kmymoney2/mimetype_kmy_128x128.pngbin0 -> 16882 bytes
-rw-r--r--kmymoney2/mimetype_kmy_16x16.pngbin0 -> 896 bytes
-rw-r--r--kmymoney2/mimetype_kmy_32x32.pngbin0 -> 2334 bytes
-rw-r--r--kmymoney2/mimetype_kmy_48x48.pngbin0 -> 4206 bytes
-rw-r--r--kmymoney2/mimetype_kmy_64x64.pngbin0 -> 6396 bytes
-rw-r--r--kmymoney2/misc/Makefile.am19
-rw-r--r--kmymoney2/misc/financequote.pl117
-rw-r--r--kmymoney2/mymoney/Makefile.am50
-rw-r--r--kmymoney2/mymoney/autotest.h24
-rw-r--r--kmymoney2/mymoney/mymoneyaccount.cpp744
-rw-r--r--kmymoney2/mymoney/mymoneyaccount.h692
-rw-r--r--kmymoney2/mymoney/mymoneyaccounttest.cpp589
-rw-r--r--kmymoney2/mymoney/mymoneyaccounttest.h70
-rw-r--r--kmymoney2/mymoney/mymoneybudget.cpp354
-rw-r--r--kmymoney2/mymoney/mymoneybudget.h269
-rw-r--r--kmymoney2/mymoney/mymoneycategory.cpp170
-rw-r--r--kmymoney2/mymoney/mymoneycategory.h68
-rw-r--r--kmymoney2/mymoney/mymoneyexception.cpp35
-rw-r--r--kmymoney2/mymoney/mymoneyexception.h115
-rw-r--r--kmymoney2/mymoney/mymoneyexceptiontest.cpp51
-rw-r--r--kmymoney2/mymoney/mymoneyexceptiontest.h47
-rw-r--r--kmymoney2/mymoney/mymoneyfile.cpp2332
-rw-r--r--kmymoney2/mymoney/mymoneyfile.h1470
-rw-r--r--kmymoney2/mymoney/mymoneyfiletest.cpp1550
-rw-r--r--kmymoney2/mymoney/mymoneyfiletest.h128
-rw-r--r--kmymoney2/mymoney/mymoneyfinancialcalculator.cpp348
-rw-r--r--kmymoney2/mymoney/mymoneyfinancialcalculator.h317
-rw-r--r--kmymoney2/mymoney/mymoneyfinancialcalculatortest.cpp189
-rw-r--r--kmymoney2/mymoney/mymoneyfinancialcalculatortest.h72
-rw-r--r--kmymoney2/mymoney/mymoneyforecast.cpp1340
-rw-r--r--kmymoney2/mymoney/mymoneyforecast.h408
-rw-r--r--kmymoney2/mymoney/mymoneyforecasttest.cpp977
-rw-r--r--kmymoney2/mymoney/mymoneyforecasttest.h96
-rw-r--r--kmymoney2/mymoney/mymoneyinstitution.cpp182
-rw-r--r--kmymoney2/mymoney/mymoneyinstitution.h206
-rw-r--r--kmymoney2/mymoney/mymoneyinstitutiontest.cpp296
-rw-r--r--kmymoney2/mymoney/mymoneyinstitutiontest.h61
-rw-r--r--kmymoney2/mymoney/mymoneyinvesttransaction.cpp42
-rw-r--r--kmymoney2/mymoney/mymoneyinvesttransaction.h43
-rw-r--r--kmymoney2/mymoney/mymoneykeyvaluecontainer.cpp120
-rw-r--r--kmymoney2/mymoney/mymoneykeyvaluecontainer.h139
-rw-r--r--kmymoney2/mymoney/mymoneykeyvaluecontainertest.cpp189
-rw-r--r--kmymoney2/mymoney/mymoneykeyvaluecontainertest.h61
-rw-r--r--kmymoney2/mymoney/mymoneymoney.cpp794
-rw-r--r--kmymoney2/mymoney/mymoneymoney.h612
-rw-r--r--kmymoney2/mymoney/mymoneymoneytest.cpp591
-rw-r--r--kmymoney2/mymoney/mymoneymoneytest.h99
-rw-r--r--kmymoney2/mymoney/mymoneyobject.cpp74
-rw-r--r--kmymoney2/mymoney/mymoneyobject.h129
-rw-r--r--kmymoney2/mymoney/mymoneyobjectcontainer.cpp218
-rw-r--r--kmymoney2/mymoney/mymoneyobjectcontainer.h99
-rw-r--r--kmymoney2/mymoney/mymoneyobjecttest.cpp73
-rw-r--r--kmymoney2/mymoney/mymoneyobjecttest.h50
-rw-r--r--kmymoney2/mymoney/mymoneyobserver.cpp30
-rw-r--r--kmymoney2/mymoney/mymoneyobserver.h55
-rw-r--r--kmymoney2/mymoney/mymoneyobservertest.h106
-rw-r--r--kmymoney2/mymoney/mymoneypayee.cpp220
-rw-r--r--kmymoney2/mymoney/mymoneypayee.h206
-rw-r--r--kmymoney2/mymoney/mymoneypayeetest.cpp76
-rw-r--r--kmymoney2/mymoney/mymoneypayeetest.h41
-rw-r--r--kmymoney2/mymoney/mymoneyprice.cpp113
-rw-r--r--kmymoney2/mymoney/mymoneyprice.h158
-rw-r--r--kmymoney2/mymoney/mymoneypricetest.cpp90
-rw-r--r--kmymoney2/mymoney/mymoneypricetest.h48
-rw-r--r--kmymoney2/mymoney/mymoneyreport.cpp787
-rw-r--r--kmymoney2/mymoney/mymoneyreport.h497
-rw-r--r--kmymoney2/mymoney/mymoneyscheduled.cpp1372
-rw-r--r--kmymoney2/mymoney/mymoneyscheduled.h695
-rw-r--r--kmymoney2/mymoney/mymoneyscheduletest.cpp1909
-rw-r--r--kmymoney2/mymoney/mymoneyscheduletest.h106
-rw-r--r--kmymoney2/mymoney/mymoneysecurity.cpp180
-rw-r--r--kmymoney2/mymoney/mymoneysecurity.h150
-rw-r--r--kmymoney2/mymoney/mymoneysecuritytest.cpp210
-rw-r--r--kmymoney2/mymoney/mymoneysecuritytest.h58
-rw-r--r--kmymoney2/mymoney/mymoneysplit.cpp272
-rw-r--r--kmymoney2/mymoney/mymoneysplit.h307
-rw-r--r--kmymoney2/mymoney/mymoneysplittest.cpp306
-rw-r--r--kmymoney2/mymoney/mymoneysplittest.h67
-rw-r--r--kmymoney2/mymoney/mymoneystatement.cpp299
-rw-r--r--kmymoney2/mymoney/mymoneystatement.h145
-rw-r--r--kmymoney2/mymoney/mymoneysubject.cpp58
-rw-r--r--kmymoney2/mymoney/mymoneysubject.h59
-rw-r--r--kmymoney2/mymoney/mymoneytransaction.cpp484
-rw-r--r--kmymoney2/mymoney/mymoneytransaction.h353
-rw-r--r--kmymoney2/mymoney/mymoneytransactionfilter.cpp860
-rw-r--r--kmymoney2/mymoney/mymoneytransactionfilter.h578
-rw-r--r--kmymoney2/mymoney/mymoneytransactiontest.cpp628
-rw-r--r--kmymoney2/mymoney/mymoneytransactiontest.h96
-rw-r--r--kmymoney2/mymoney/mymoneyutils.cpp339
-rw-r--r--kmymoney2/mymoney/mymoneyutils.h192
-rw-r--r--kmymoney2/mymoney/storage/Makefile.am20
-rw-r--r--kmymoney2/mymoney/storage/imymoneyserialize.cpp31
-rw-r--r--kmymoney2/mymoney/storage/imymoneyserialize.h374
-rw-r--r--kmymoney2/mymoney/storage/imymoneystorage.cpp38
-rw-r--r--kmymoney2/mymoney/storage/imymoneystorage.h886
-rw-r--r--kmymoney2/mymoney/storage/imymoneystorageformat.cpp31
-rw-r--r--kmymoney2/mymoney/storage/imymoneystorageformat.h75
-rw-r--r--kmymoney2/mymoney/storage/mymoneydatabasemgr.cpp1880
-rw-r--r--kmymoney2/mymoney/storage/mymoneydatabasemgr.h1038
-rw-r--r--kmymoney2/mymoney/storage/mymoneydatabasemgrtest.cpp1996
-rw-r--r--kmymoney2/mymoney/storage/mymoneydatabasemgrtest.h143
-rw-r--r--kmymoney2/mymoney/storage/mymoneymap.h328
-rw-r--r--kmymoney2/mymoney/storage/mymoneymaptest.cpp38
-rw-r--r--kmymoney2/mymoney/storage/mymoneymaptest.h47
-rw-r--r--kmymoney2/mymoney/storage/mymoneyseqaccessmgr.cpp1944
-rw-r--r--kmymoney2/mymoney/storage/mymoneyseqaccessmgr.h1232
-rw-r--r--kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.cpp1705
-rw-r--r--kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.h131
-rw-r--r--kmymoney2/mymoney/storage/mymoneystorageanon.cpp294
-rw-r--r--kmymoney2/mymoney/storage/mymoneystorageanon.h113
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragebin.h49
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragedump.cpp446
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragedump.h56
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragesql.cpp4511
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragesql.h807
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragexml.cpp908
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragexml.h156
-rw-r--r--kmymoney2/pics/CMakeLists.txt16
-rw-r--r--kmymoney2/pics/Makefile.am3
-rw-r--r--kmymoney2/pics/check-16.pngbin0 -> 352 bytes
-rw-r--r--kmymoney2/pics/check-20.pngbin0 -> 405 bytes
-rw-r--r--kmymoney2/pics/frozen.pngbin0 -> 851 bytes
-rw-r--r--kmymoney2/pics/kmm-frozen.pngbin0 -> 1049 bytes
-rw-r--r--kmymoney2/pics/lock-16.pngbin0 -> 345 bytes
-rw-r--r--kmymoney2/pics/paperclip-diag.pngbin0 -> 531 bytes
-rw-r--r--kmymoney2/pics/paperclip-diag16.pngbin0 -> 432 bytes
-rw-r--r--kmymoney2/pics/paperclip-vert.pngbin0 -> 336 bytes
-rw-r--r--kmymoney2/pics/reconciled-frozen.pngbin0 -> 573 bytes
-rw-r--r--kmymoney2/pics/reconciled-frozen2.pngbin0 -> 645 bytes
-rw-r--r--kmymoney2/pics/reconciled.pngbin0 -> 298 bytes
-rw-r--r--kmymoney2/pics/split-1.pngbin0 -> 376 bytes
-rw-r--r--kmymoney2/pics/split-2.pngbin0 -> 257 bytes
-rw-r--r--kmymoney2/pics/startlogo.pngbin0 -> 105509 bytes
-rw-r--r--kmymoney2/pics/titlelabel_background.pngbin0 -> 24095 bytes
-rw-r--r--kmymoney2/plugins/Makefile.am24
-rw-r--r--kmymoney2/plugins/importinterface.cpp34
-rw-r--r--kmymoney2/plugins/importinterface.h63
-rw-r--r--kmymoney2/plugins/interfaces/Makefile.am13
-rw-r--r--kmymoney2/plugins/interfaces/kmmimportinterface.cpp41
-rw-r--r--kmymoney2/plugins/interfaces/kmmimportinterface.h60
-rw-r--r--kmymoney2/plugins/interfaces/kmmstatementinterface.cpp56
-rw-r--r--kmymoney2/plugins/interfaces/kmmstatementinterface.h77
-rw-r--r--kmymoney2/plugins/interfaces/kmmviewinterface.cpp60
-rw-r--r--kmymoney2/plugins/interfaces/kmmviewinterface.h79
-rw-r--r--kmymoney2/plugins/kmymoneyimporterplugin.desktop6
-rw-r--r--kmymoney2/plugins/kmymoneyplugin.cpp91
-rw-r--r--kmymoney2/plugins/kmymoneyplugin.desktop6
-rw-r--r--kmymoney2/plugins/kmymoneyplugin.h214
-rw-r--r--kmymoney2/plugins/ofximport/Makefile.am33
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/Makefile.am16
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp223
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h86
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui109
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui488
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp445
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h106
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp112
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h58
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui483
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp725
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h128
-rw-r--r--kmymoney2/plugins/ofximport/kmm_ofximport.desktop12
-rw-r--r--kmymoney2/plugins/ofximport/kmm_ofximport.rc10
-rw-r--r--kmymoney2/plugins/ofximport/ofximporterplugin.cpp688
-rw-r--r--kmymoney2/plugins/ofximport/ofximporterplugin.h145
-rw-r--r--kmymoney2/plugins/ofximport/ofxpartner.cpp429
-rw-r--r--kmymoney2/plugins/ofximport/ofxpartner.h102
-rw-r--r--kmymoney2/plugins/pluginloader.cpp163
-rw-r--r--kmymoney2/plugins/pluginloader.h76
-rw-r--r--kmymoney2/plugins/statementinterface.cpp34
-rw-r--r--kmymoney2/plugins/statementinterface.h72
-rw-r--r--kmymoney2/plugins/viewinterface.cpp34
-rw-r--r--kmymoney2/plugins/viewinterface.h123
-rw-r--r--kmymoney2/reports/Makefile.am16
-rw-r--r--kmymoney2/reports/kreportchartview.cpp210
-rw-r--r--kmymoney2/reports/kreportchartview.h95
-rw-r--r--kmymoney2/reports/kreportsviewtest.h91
-rw-r--r--kmymoney2/reports/listtable.cpp633
-rw-r--r--kmymoney2/reports/listtable.h121
-rw-r--r--kmymoney2/reports/objectinfotable.cpp368
-rw-r--r--kmymoney2/reports/objectinfotable.h75
-rw-r--r--kmymoney2/reports/pivotgrid.cpp161
-rw-r--r--kmymoney2/reports/pivotgrid.h151
-rw-r--r--kmymoney2/reports/pivotgridtest.cpp198
-rw-r--r--kmymoney2/reports/pivotgridtest.h47
-rw-r--r--kmymoney2/reports/pivottable.cpp2604
-rw-r--r--kmymoney2/reports/pivottable.h356
-rw-r--r--kmymoney2/reports/pivottabletest.cpp1021
-rw-r--r--kmymoney2/reports/pivottabletest.h75
-rw-r--r--kmymoney2/reports/querytable.cpp1522
-rw-r--r--kmymoney2/reports/querytable.h142
-rw-r--r--kmymoney2/reports/querytabletest.cpp694
-rw-r--r--kmymoney2/reports/querytabletest.h53
-rw-r--r--kmymoney2/reports/reportaccount.cpp355
-rw-r--r--kmymoney2/reports/reportaccount.h238
-rw-r--r--kmymoney2/reports/reportdebug.h83
-rw-r--r--kmymoney2/reports/reportstestcommon.cpp494
-rw-r--r--kmymoney2/reports/reportstestcommon.h133
-rw-r--r--kmymoney2/reports/reporttable.h54
-rw-r--r--kmymoney2/templates/C/Makefile.am5
-rw-r--r--kmymoney2/templates/C/brokerage.kmt31
-rw-r--r--kmymoney2/templates/C/business.kmt103
-rw-r--r--kmymoney2/templates/C/carloan.kmt27
-rw-r--r--kmymoney2/templates/C/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/C/checkbook.kmt27
-rw-r--r--kmymoney2/templates/C/childcare.kmt20
-rw-r--r--kmymoney2/templates/C/common.kmt92
-rw-r--r--kmymoney2/templates/C/default_categories-template.kmt144
-rw-r--r--kmymoney2/templates/C/eduloan.kmt27
-rw-r--r--kmymoney2/templates/C/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/C/full.kmt136
-rw-r--r--kmymoney2/templates/C/homeloan.kmt26
-rw-r--r--kmymoney2/templates/C/homeown.kmt26
-rw-r--r--kmymoney2/templates/C/old-default_accounts.kmt198
-rw-r--r--kmymoney2/templates/C/otherloan.kmt26
-rw-r--r--kmymoney2/templates/C/renter.kmt23
-rw-r--r--kmymoney2/templates/C/retiremt.kmt21
-rw-r--r--kmymoney2/templates/C/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/C/spouseretire.kmt21
-rw-r--r--kmymoney2/templates/CMakeLists.txt11
-rw-r--r--kmymoney2/templates/Makefile.am3
-rw-r--r--kmymoney2/templates/cpp_template31
-rw-r--r--kmymoney2/templates/de_AT/Makefile.am5
-rw-r--r--kmymoney2/templates/de_AT/auto.kmt33
-rw-r--r--kmymoney2/templates/de_AT/autoloan.kmt29
-rw-r--r--kmymoney2/templates/de_AT/brokerage.kmt34
-rw-r--r--kmymoney2/templates/de_AT/business.kmt99
-rw-r--r--kmymoney2/templates/de_AT/common.kmt102
-rw-r--r--kmymoney2/templates/de_AT/houseown.kmt37
-rw-r--r--kmymoney2/templates/de_AT/investment.kmt37
-rw-r--r--kmymoney2/templates/de_AT/kids.kmt25
-rw-r--r--kmymoney2/templates/de_CH/Makefile.am5
-rw-r--r--kmymoney2/templates/de_CH/brokerage.kmt34
-rw-r--r--kmymoney2/templates/de_CH/chkmu.kmt512
-rw-r--r--kmymoney2/templates/de_CH/common.kmt97
-rw-r--r--kmymoney2/templates/de_CH/kids.kmt25
-rw-r--r--kmymoney2/templates/de_CH/otherasset.kmt22
-rw-r--r--kmymoney2/templates/de_CH/otherloan.kmt22
-rw-r--r--kmymoney2/templates/de_DE/Makefile.am5
-rw-r--r--kmymoney2/templates/de_DE/auto.kmt33
-rw-r--r--kmymoney2/templates/de_DE/autoloan.kmt29
-rw-r--r--kmymoney2/templates/de_DE/brokerage.kmt34
-rw-r--r--kmymoney2/templates/de_DE/common.kmt97
-rw-r--r--kmymoney2/templates/de_DE/default_accounts.kmt263
-rw-r--r--kmymoney2/templates/de_DE/full.kmt144
-rw-r--r--kmymoney2/templates/de_DE/houseown.kmt37
-rw-r--r--kmymoney2/templates/de_DE/investment.kmt37
-rw-r--r--kmymoney2/templates/de_DE/kids.kmt25
-rw-r--r--kmymoney2/templates/de_DE/otherasset.kmt22
-rw-r--r--kmymoney2/templates/de_DE/otherloan.kmt22
-rw-r--r--kmymoney2/templates/de_DE/skr03.kmt138
-rw-r--r--kmymoney2/templates/de_DE/skr04.kmt1196
-rw-r--r--kmymoney2/templates/de_DE/studium.kmt30
-rw-r--r--kmymoney2/templates/dk/Makefile.am5
-rw-r--r--kmymoney2/templates/dk/car.kmt28
-rw-r--r--kmymoney2/templates/dk/common.kmt87
-rw-r--r--kmymoney2/templates/dk/homeloan.kmt27
-rw-r--r--kmymoney2/templates/dk/homeown.kmt27
-rw-r--r--kmymoney2/templates/el_GR/Makefile.am5
-rw-r--r--kmymoney2/templates/el_GR/brokerage.kmt31
-rw-r--r--kmymoney2/templates/el_GR/carloan.kmt27
-rw-r--r--kmymoney2/templates/el_GR/common.kmt94
-rw-r--r--kmymoney2/templates/en_GB/Makefile.am5
-rw-r--r--kmymoney2/templates/en_GB/brokerage.kmt31
-rw-r--r--kmymoney2/templates/en_GB/business.kmt103
-rw-r--r--kmymoney2/templates/en_GB/carloan.kmt27
-rw-r--r--kmymoney2/templates/en_GB/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/en_GB/checkbook.kmt27
-rw-r--r--kmymoney2/templates/en_GB/childcare.kmt20
-rw-r--r--kmymoney2/templates/en_GB/common.kmt92
-rw-r--r--kmymoney2/templates/en_GB/default_accounts.kmt301
-rw-r--r--kmymoney2/templates/en_GB/eduloan.kmt27
-rw-r--r--kmymoney2/templates/en_GB/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/en_GB/full.kmt136
-rw-r--r--kmymoney2/templates/en_GB/homeloan.kmt26
-rw-r--r--kmymoney2/templates/en_GB/homeown.kmt26
-rw-r--r--kmymoney2/templates/en_GB/otherloan.kmt26
-rw-r--r--kmymoney2/templates/en_GB/renter.kmt23
-rw-r--r--kmymoney2/templates/en_GB/retiremt.kmt21
-rw-r--r--kmymoney2/templates/en_GB/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/en_GB/spouseretire.kmt21
-rw-r--r--kmymoney2/templates/en_GB/uk-vat.kmt90
-rw-r--r--kmymoney2/templates/en_US/0.6-default_accounts.kmt426
-rw-r--r--kmymoney2/templates/en_US/0.8-default_accounts.kmt164
-rw-r--r--kmymoney2/templates/en_US/Base-Blank.kmt11
-rw-r--r--kmymoney2/templates/en_US/Base-Detailed.kmt82
-rw-r--r--kmymoney2/templates/en_US/Base-Simple.kmt25
-rw-r--r--kmymoney2/templates/en_US/CMakeLists.txt17
-rw-r--r--kmymoney2/templates/en_US/House.kmt20
-rw-r--r--kmymoney2/templates/en_US/Makefile.am5
-rw-r--r--kmymoney2/templates/en_US/Pets.kmt17
-rw-r--r--kmymoney2/templates/en_US/Retirement.kmt20
-rw-r--r--kmymoney2/templates/en_US/ScheduleA_itemized-deductions.kmt51
-rw-r--r--kmymoney2/templates/en_US/ScheduleBandD.kmt24
-rw-r--r--kmymoney2/templates/en_US/ScheduleC_business.kmt71
-rw-r--r--kmymoney2/templates/en_US/ScheduleE_rental-property.kmt43
-rw-r--r--kmymoney2/templates/en_US/ScheduleF_farming.kmt49
-rw-r--r--kmymoney2/templates/en_US/kids.kmt26
-rw-r--r--kmymoney2/templates/es_AR/Makefile.am5
-rw-r--r--kmymoney2/templates/es_AR/brokerage.kmt31
-rw-r--r--kmymoney2/templates/es_AR/carloan.kmt27
-rw-r--r--kmymoney2/templates/es_AR/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/es_AR/childcare.kmt20
-rw-r--r--kmymoney2/templates/es_AR/common.kmt97
-rw-r--r--kmymoney2/templates/es_AR/currency.kmt20
-rw-r--r--kmymoney2/templates/es_AR/default_accounts.kmt120
-rw-r--r--kmymoney2/templates/es_AR/eduloan.kmt27
-rw-r--r--kmymoney2/templates/es_AR/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/es_AR/homeloan.kmt27
-rw-r--r--kmymoney2/templates/es_AR/homeown.kmt26
-rw-r--r--kmymoney2/templates/es_AR/otherloan.kmt27
-rw-r--r--kmymoney2/templates/es_AR/renter.kmt23
-rw-r--r--kmymoney2/templates/es_AR/retiremt.kmt22
-rw-r--r--kmymoney2/templates/es_AR/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/es_AR/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/es_ES/Makefile.am5
-rw-r--r--kmymoney2/templates/es_ES/brokerage.kmt31
-rw-r--r--kmymoney2/templates/es_ES/carloan.kmt27
-rw-r--r--kmymoney2/templates/es_ES/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/es_ES/childcare.kmt20
-rw-r--r--kmymoney2/templates/es_ES/common.kmt94
-rw-r--r--kmymoney2/templates/es_ES/currency.kmt20
-rw-r--r--kmymoney2/templates/es_ES/default_accounts.kmt120
-rw-r--r--kmymoney2/templates/es_ES/eduloan.kmt27
-rw-r--r--kmymoney2/templates/es_ES/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/es_ES/homeloan.kmt27
-rw-r--r--kmymoney2/templates/es_ES/homeown.kmt26
-rw-r--r--kmymoney2/templates/es_ES/otherloan.kmt27
-rw-r--r--kmymoney2/templates/es_ES/renter.kmt23
-rw-r--r--kmymoney2/templates/es_ES/retiremt.kmt22
-rw-r--r--kmymoney2/templates/es_ES/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/es_ES/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/es_MX/Makefile.am5
-rw-r--r--kmymoney2/templates/es_MX/brokerage.kmt31
-rw-r--r--kmymoney2/templates/es_MX/carloan.kmt27
-rw-r--r--kmymoney2/templates/es_MX/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/es_MX/childcare.kmt20
-rw-r--r--kmymoney2/templates/es_MX/common.kmt100
-rw-r--r--kmymoney2/templates/es_MX/currency.kmt20
-rw-r--r--kmymoney2/templates/es_MX/eduloan.kmt27
-rw-r--r--kmymoney2/templates/es_MX/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/es_MX/homeloan.kmt27
-rw-r--r--kmymoney2/templates/es_MX/homeown.kmt26
-rw-r--r--kmymoney2/templates/es_MX/otherloan.kmt27
-rw-r--r--kmymoney2/templates/es_MX/renter.kmt23
-rw-r--r--kmymoney2/templates/es_MX/retiremt.kmt22
-rw-r--r--kmymoney2/templates/es_MX/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/es_MX/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/fr_CA/Makefile.am5
-rw-r--r--kmymoney2/templates/fr_CA/actifsfixes.kmt24
-rw-r--r--kmymoney2/templates/fr_CA/automobile.kmt41
-rw-r--r--kmymoney2/templates/fr_CA/basecommune.kmt83
-rw-r--r--kmymoney2/templates/fr_CA/cdmarchemon.kmt29
-rw-r--r--kmymoney2/templates/fr_CA/chequier.kmt27
-rw-r--r--kmymoney2/templates/fr_CA/conjointretraite.kmt27
-rw-r--r--kmymoney2/templates/fr_CA/conjointrev.kmt36
-rw-r--r--kmymoney2/templates/fr_CA/courtage.kmt36
-rw-r--r--kmymoney2/templates/fr_CA/etudeemprunt.kmt27
-rw-r--r--kmymoney2/templates/fr_CA/garderie.kmt20
-rw-r--r--kmymoney2/templates/fr_CA/locataire.kmt23
-rw-r--r--kmymoney2/templates/fr_CA/proprietaire.kmt39
-rw-r--r--kmymoney2/templates/fr_CA/retraite.kmt27
-rw-r--r--kmymoney2/templates/fr_CA/revenus.kmt36
-rw-r--r--kmymoney2/templates/fr_CH/Makefile.am5
-rw-r--r--kmymoney2/templates/fr_CH/brokerage.kmt31
-rw-r--r--kmymoney2/templates/fr_CH/business.kmt103
-rw-r--r--kmymoney2/templates/fr_CH/carloan.kmt27
-rw-r--r--kmymoney2/templates/fr_CH/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/fr_CH/childcare.kmt20
-rw-r--r--kmymoney2/templates/fr_CH/common.kmt94
-rw-r--r--kmymoney2/templates/fr_CH/currency.kmt20
-rw-r--r--kmymoney2/templates/fr_CH/eduloan.kmt27
-rw-r--r--kmymoney2/templates/fr_CH/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/fr_CH/homeloan.kmt27
-rw-r--r--kmymoney2/templates/fr_CH/homeown.kmt26
-rw-r--r--kmymoney2/templates/fr_CH/otherloan.kmt27
-rw-r--r--kmymoney2/templates/fr_CH/renter.kmt23
-rw-r--r--kmymoney2/templates/fr_CH/retiremt.kmt22
-rw-r--r--kmymoney2/templates/fr_CH/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/fr_CH/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/fr_FR/Makefile.am5
-rw-r--r--kmymoney2/templates/fr_FR/brokerage.kmt31
-rw-r--r--kmymoney2/templates/fr_FR/business.kmt103
-rw-r--r--kmymoney2/templates/fr_FR/carloan.kmt27
-rw-r--r--kmymoney2/templates/fr_FR/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/fr_FR/childcare.kmt20
-rw-r--r--kmymoney2/templates/fr_FR/common.kmt94
-rw-r--r--kmymoney2/templates/fr_FR/comptes_par_default.kmt200
-rw-r--r--kmymoney2/templates/fr_FR/currency.kmt20
-rw-r--r--kmymoney2/templates/fr_FR/eduloan.kmt27
-rw-r--r--kmymoney2/templates/fr_FR/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/fr_FR/homeloan.kmt27
-rw-r--r--kmymoney2/templates/fr_FR/homeown.kmt26
-rw-r--r--kmymoney2/templates/fr_FR/otherloan.kmt27
-rw-r--r--kmymoney2/templates/fr_FR/renter.kmt23
-rw-r--r--kmymoney2/templates/fr_FR/retiremt.kmt22
-rw-r--r--kmymoney2/templates/fr_FR/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/fr_FR/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/gl_ES/Makefile.am5
-rw-r--r--kmymoney2/templates/gl_ES/default_accounts.kmt121
-rw-r--r--kmymoney2/templates/header_template30
-rw-r--r--kmymoney2/templates/hu_HU/Makefile.am5
-rw-r--r--kmymoney2/templates/hu_HU/brokerage.kmt31
-rw-r--r--kmymoney2/templates/hu_HU/business.kmt103
-rw-r--r--kmymoney2/templates/hu_HU/carloan.kmt27
-rw-r--r--kmymoney2/templates/hu_HU/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/hu_HU/checkbook.kmt27
-rw-r--r--kmymoney2/templates/hu_HU/childcare.kmt20
-rw-r--r--kmymoney2/templates/hu_HU/common.kmt91
-rw-r--r--kmymoney2/templates/hu_HU/eduloan.kmt27
-rw-r--r--kmymoney2/templates/hu_HU/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/hu_HU/homeloan.kmt27
-rw-r--r--kmymoney2/templates/hu_HU/homeown.kmt26
-rw-r--r--kmymoney2/templates/hu_HU/otherloan.kmt27
-rw-r--r--kmymoney2/templates/hu_HU/renter.kmt23
-rw-r--r--kmymoney2/templates/hu_HU/retiremt.kmt22
-rw-r--r--kmymoney2/templates/hu_HU/spouseinc.kmt28
-rw-r--r--kmymoney2/templates/hu_HU/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/it/Makefile.am5
-rw-r--r--kmymoney2/templates/it/brokerage.kmt31
-rw-r--r--kmymoney2/templates/it/carloan.kmt27
-rw-r--r--kmymoney2/templates/it/checkbook.kmt27
-rw-r--r--kmymoney2/templates/it/childcare.kmt20
-rw-r--r--kmymoney2/templates/it/common.kmt92
-rw-r--r--kmymoney2/templates/it/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/it/homeloan.kmt27
-rw-r--r--kmymoney2/templates/it/homeown.kmt26
-rw-r--r--kmymoney2/templates/it/otherloan.kmt27
-rw-r--r--kmymoney2/templates/it/renter.kmt20
-rw-r--r--kmymoney2/templates/it/retiremt.kmt22
-rw-r--r--kmymoney2/templates/it/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/it/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/jp/Makefile.am5
-rw-r--r--kmymoney2/templates/jp/brokerage.kmt31
-rw-r--r--kmymoney2/templates/jp/business.kmt103
-rw-r--r--kmymoney2/templates/jp/carloan.kmt27
-rw-r--r--kmymoney2/templates/jp/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/jp/checkbook.kmt27
-rw-r--r--kmymoney2/templates/jp/childcare.kmt20
-rw-r--r--kmymoney2/templates/jp/common.kmt92
-rw-r--r--kmymoney2/templates/jp/eduloan.kmt27
-rw-r--r--kmymoney2/templates/jp/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/jp/homeloan.kmt26
-rw-r--r--kmymoney2/templates/jp/homeown.kmt26
-rw-r--r--kmymoney2/templates/jp/otherloan.kmt26
-rw-r--r--kmymoney2/templates/jp/renter.kmt23
-rw-r--r--kmymoney2/templates/jp/retiremt.kmt21
-rw-r--r--kmymoney2/templates/jp/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/jp/spouseretire.kmt21
-rw-r--r--kmymoney2/templates/nl_NL/Makefile.am5
-rw-r--r--kmymoney2/templates/nl_NL/default_accounts.kmt209
-rw-r--r--kmymoney2/templates/pt_BR/Makefile.am5
-rw-r--r--kmymoney2/templates/pt_BR/brokerage.kmt31
-rw-r--r--kmymoney2/templates/pt_BR/carloan.kmt27
-rw-r--r--kmymoney2/templates/pt_BR/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/pt_BR/childcare.kmt20
-rw-r--r--kmymoney2/templates/pt_BR/common.kmt92
-rw-r--r--kmymoney2/templates/pt_BR/currency.kmt20
-rw-r--r--kmymoney2/templates/pt_BR/default_accounts.kmt183
-rw-r--r--kmymoney2/templates/pt_BR/eduloan.kmt27
-rw-r--r--kmymoney2/templates/pt_BR/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/pt_BR/homeloan.kmt27
-rw-r--r--kmymoney2/templates/pt_BR/homeown.kmt24
-rw-r--r--kmymoney2/templates/pt_BR/otherloan.kmt27
-rw-r--r--kmymoney2/templates/pt_BR/renter.kmt21
-rw-r--r--kmymoney2/templates/pt_BR/retiremt.kmt22
-rw-r--r--kmymoney2/templates/pt_BR/spouseinc.kmt25
-rw-r--r--kmymoney2/templates/pt_BR/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/pt_PT/Makefile.am5
-rw-r--r--kmymoney2/templates/pt_PT/brokerage.kmt31
-rw-r--r--kmymoney2/templates/pt_PT/carloan.kmt27
-rw-r--r--kmymoney2/templates/pt_PT/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/pt_PT/childcare.kmt20
-rw-r--r--kmymoney2/templates/pt_PT/common.kmt93
-rw-r--r--kmymoney2/templates/pt_PT/eduloan.kmt27
-rw-r--r--kmymoney2/templates/pt_PT/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/pt_PT/homeloan.kmt27
-rw-r--r--kmymoney2/templates/pt_PT/homeown.kmt26
-rw-r--r--kmymoney2/templates/pt_PT/otherloan.kmt27
-rw-r--r--kmymoney2/templates/pt_PT/renter.kmt23
-rw-r--r--kmymoney2/templates/pt_PT/retiremt.kmt22
-rw-r--r--kmymoney2/templates/pt_PT/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/pt_PT/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/ro_RO/Makefile.am5
-rw-r--r--kmymoney2/templates/ro_RO/carloan.kmt27
-rw-r--r--kmymoney2/templates/ro_RO/common.kmt86
-rw-r--r--kmymoney2/templates/ro_RO/default_categories-template.kmt143
-rw-r--r--kmymoney2/templates/ro_RO/homeloan.kmt26
-rw-r--r--kmymoney2/templates/ru_RU/Makefile.am5
-rw-r--r--kmymoney2/templates/ru_RU/default_accounts.kmt79
-rw-r--r--kmymoney2/templates/sk/Makefile.am5
-rw-r--r--kmymoney2/templates/sk/brokerage.kmt31
-rw-r--r--kmymoney2/templates/sk/carloan.kmt27
-rw-r--r--kmymoney2/templates/sk/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/sk/childcare.kmt20
-rw-r--r--kmymoney2/templates/sk/common.kmt94
-rw-r--r--kmymoney2/templates/sk/currency.kmt20
-rw-r--r--kmymoney2/templates/sk/eduloan.kmt27
-rw-r--r--kmymoney2/templates/sk/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/sk/homeloan.kmt27
-rw-r--r--kmymoney2/templates/sk/homeown.kmt26
-rw-r--r--kmymoney2/templates/sk/otherloan.kmt27
-rw-r--r--kmymoney2/templates/sk/renter.kmt23
-rw-r--r--kmymoney2/templates/sk/retiremt.kmt22
-rw-r--r--kmymoney2/templates/sk/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/sk/spouseretire.kmt22
-rw-r--r--kmymoney2/templates/tr_TR/Makefile.am5
-rw-r--r--kmymoney2/templates/tr_TR/TEKDUZ.kmt227
-rw-r--r--kmymoney2/templates/tr_TR/brokerage.kmt31
-rw-r--r--kmymoney2/templates/tr_TR/carloan.kmt27
-rw-r--r--kmymoney2/templates/tr_TR/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/tr_TR/checkbook.kmt27
-rw-r--r--kmymoney2/templates/tr_TR/common.kmt92
-rw-r--r--kmymoney2/templates/tr_TR/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/tr_TR/homeloan.kmt27
-rw-r--r--kmymoney2/templates/zh_CN/Makefile.am5
-rw-r--r--kmymoney2/templates/zh_CN/brokerage.kmt31
-rw-r--r--kmymoney2/templates/zh_CN/business.kmt103
-rw-r--r--kmymoney2/templates/zh_CN/carloan.kmt27
-rw-r--r--kmymoney2/templates/zh_CN/cdmoneymkt.kmt29
-rw-r--r--kmymoney2/templates/zh_CN/checkbook.kmt27
-rw-r--r--kmymoney2/templates/zh_CN/childcare.kmt20
-rw-r--r--kmymoney2/templates/zh_CN/common.kmt92
-rw-r--r--kmymoney2/templates/zh_CN/default_accounts.kmt162
-rw-r--r--kmymoney2/templates/zh_CN/eduloan.kmt27
-rw-r--r--kmymoney2/templates/zh_CN/fixedassets.kmt24
-rw-r--r--kmymoney2/templates/zh_CN/full.kmt136
-rw-r--r--kmymoney2/templates/zh_CN/homeloan.kmt26
-rw-r--r--kmymoney2/templates/zh_CN/homeown.kmt26
-rw-r--r--kmymoney2/templates/zh_CN/otherloan.kmt26
-rw-r--r--kmymoney2/templates/zh_CN/renter.kmt23
-rw-r--r--kmymoney2/templates/zh_CN/retiremt.kmt21
-rw-r--r--kmymoney2/templates/zh_CN/spouseinc.kmt29
-rw-r--r--kmymoney2/templates/zh_CN/spouseretire.kmt21
-rw-r--r--kmymoney2/templates/zh_HK/Makefile.am5
-rw-r--r--kmymoney2/templates/zh_HK/business.kmt103
-rw-r--r--kmymoney2/templates/zh_TW/Makefile.am5
-rw-r--r--kmymoney2/templates/zh_TW/business.kmt103
-rw-r--r--kmymoney2/tips131
-rw-r--r--kmymoney2/views/Makefile.am25
-rw-r--r--kmymoney2/views/kaccountsview.cpp625
-rw-r--r--kmymoney2/views/kaccountsview.h209
-rw-r--r--kmymoney2/views/kaccountsviewdecl.ui204
-rw-r--r--kmymoney2/views/kbudgetview.cpp767
-rw-r--r--kmymoney2/views/kbudgetview.h221
-rw-r--r--kmymoney2/views/kbudgetviewdecl.ui348
-rw-r--r--kmymoney2/views/kcategoriesview.cpp313
-rw-r--r--kmymoney2/views/kcategoriesview.h147
-rw-r--r--kmymoney2/views/kcategoriesviewdecl.ui153
-rw-r--r--kmymoney2/views/kforecastview.cpp673
-rw-r--r--kmymoney2/views/kforecastview.h138
-rw-r--r--kmymoney2/views/kforecastviewdecl.ui614
-rw-r--r--kmymoney2/views/kgloballedgerview.cpp1461
-rw-r--r--kmymoney2/views/kgloballedgerview.h403
-rw-r--r--kmymoney2/views/khomeview.cpp1940
-rw-r--r--kmymoney2/views/khomeview.h158
-rw-r--r--kmymoney2/views/kinstitutionsview.cpp353
-rw-r--r--kmymoney2/views/kinstitutionsview.h128
-rw-r--r--kmymoney2/views/kinstitutionsviewdecl.ui82
-rw-r--r--kmymoney2/views/kinvestmentlistitem.cpp294
-rw-r--r--kmymoney2/views/kinvestmentlistitem.h95
-rw-r--r--kmymoney2/views/kinvestmentview.cpp322
-rw-r--r--kmymoney2/views/kinvestmentview.h136
-rw-r--r--kmymoney2/views/kinvestmentviewdecl.ui83
-rw-r--r--kmymoney2/views/kmymoneyfile.cpp114
-rw-r--r--kmymoney2/views/kmymoneyfile.h61
-rw-r--r--kmymoney2/views/kmymoneytransaction.cpp53
-rw-r--r--kmymoney2/views/kmymoneytransaction.h61
-rw-r--r--kmymoney2/views/kmymoneyview.cpp2248
-rw-r--r--kmymoney2/views/kmymoneyview.h625
-rw-r--r--kmymoney2/views/kpayeesview.cpp1108
-rw-r--r--kmymoney2/views/kpayeesview.h325
-rw-r--r--kmymoney2/views/kpayeesviewdecl.ui666
-rwxr-xr-xkmymoney2/views/kreportsview.cpp1510
-rwxr-xr-xkmymoney2/views/kreportsview.h262
-rw-r--r--kmymoney2/views/kscheduledlistitem.cpp231
-rw-r--r--kmymoney2/views/kscheduledlistitem.h107
-rw-r--r--kmymoney2/views/kscheduledview.cpp494
-rw-r--r--kmymoney2/views/kscheduledview.h149
-rw-r--r--kmymoney2/views/kscheduledviewdecl.ui161
-rw-r--r--kmymoney2/widgets/Makefile.am95
-rw-r--r--kmymoney2/widgets/kaccounttemplateselector.cpp279
-rw-r--r--kmymoney2/widgets/kaccounttemplateselector.h57
-rw-r--r--kmymoney2/widgets/kaccounttemplateselectordecl.cpp111
-rw-r--r--kmymoney2/widgets/kaccounttemplateselectordecl.ui188
-rw-r--r--kmymoney2/widgets/kbudgetvalues.cpp341
-rw-r--r--kmymoney2/widgets/kbudgetvalues.h84
-rw-r--r--kmymoney2/widgets/kbudgetvaluesdecl.cpp257
-rw-r--r--kmymoney2/widgets/kbudgetvaluesdecl.ui400
-rw-r--r--kmymoney2/widgets/kguiutils.cpp178
-rw-r--r--kmymoney2/widgets/kguiutils.h94
-rw-r--r--kmymoney2/widgets/klistviewsearchline.cpp507
-rw-r--r--kmymoney2/widgets/klistviewsearchline.h258
-rw-r--r--kmymoney2/widgets/kmymoney.widgets54
-rw-r--r--kmymoney2/widgets/kmymoneyaccountcombo.cpp218
-rw-r--r--kmymoney2/widgets/kmymoneyaccountcombo.h112
-rw-r--r--kmymoney2/widgets/kmymoneyaccountcompletion.cpp106
-rw-r--r--kmymoney2/widgets/kmymoneyaccountcompletion.h63
-rw-r--r--kmymoney2/widgets/kmymoneyaccountselector.cpp544
-rw-r--r--kmymoney2/widgets/kmymoneyaccountselector.h187
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttree.cpp147
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttree.h109
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttreebase.cpp825
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttreebase.h475
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttreebudget.cpp84
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttreebudget.h112
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttreeforecast.cpp401
-rw-r--r--kmymoney2/widgets/kmymoneyaccounttreeforecast.h168
-rw-r--r--kmymoney2/widgets/kmymoneybriefschedule.cpp191
-rw-r--r--kmymoney2/widgets/kmymoneybriefschedule.h68
-rw-r--r--kmymoney2/widgets/kmymoneycalculator.cpp448
-rw-r--r--kmymoney2/widgets/kmymoneycalculator.h249
-rw-r--r--kmymoney2/widgets/kmymoneycalendar.cpp661
-rw-r--r--kmymoney2/widgets/kmymoneycalendar.h262
-rw-r--r--kmymoney2/widgets/kmymoneycategory.cpp203
-rw-r--r--kmymoney2/widgets/kmymoneycategory.h196
-rw-r--r--kmymoney2/widgets/kmymoneychecklistitem.cpp151
-rw-r--r--kmymoney2/widgets/kmymoneychecklistitem.h93
-rw-r--r--kmymoney2/widgets/kmymoneycombo.cpp778
-rw-r--r--kmymoney2/widgets/kmymoneycombo.h467
-rw-r--r--kmymoney2/widgets/kmymoneycompletion.cpp304
-rw-r--r--kmymoney2/widgets/kmymoneycompletion.h122
-rw-r--r--kmymoney2/widgets/kmymoneycurrencyselector.cpp166
-rw-r--r--kmymoney2/widgets/kmymoneycurrencyselector.h90
-rw-r--r--kmymoney2/widgets/kmymoneydateinput.cpp348
-rw-r--r--kmymoney2/widgets/kmymoneydateinput.h123
-rw-r--r--kmymoney2/widgets/kmymoneydatetbl.cpp698
-rw-r--r--kmymoney2/widgets/kmymoneydatetbl.h189
-rw-r--r--kmymoney2/widgets/kmymoneyedit.cpp559
-rw-r--r--kmymoney2/widgets/kmymoneyedit.h243
-rw-r--r--kmymoney2/widgets/kmymoneyforecastlistviewitem.cpp75
-rw-r--r--kmymoney2/widgets/kmymoneyforecastlistviewitem.h65
-rw-r--r--kmymoney2/widgets/kmymoneygpgconfig.cpp130
-rw-r--r--kmymoney2/widgets/kmymoneygpgconfig.h62
-rw-r--r--kmymoney2/widgets/kmymoneygpgconfigdecl.ui197
-rw-r--r--kmymoney2/widgets/kmymoneylineedit.cpp152
-rw-r--r--kmymoney2/widgets/kmymoneylineedit.h135
-rw-r--r--kmymoney2/widgets/kmymoneylistviewitem.cpp135
-rw-r--r--kmymoney2/widgets/kmymoneylistviewitem.h88
-rw-r--r--kmymoney2/widgets/kmymoneyonlinequoteconfig.cpp214
-rw-r--r--kmymoney2/widgets/kmymoneyonlinequoteconfig.h59
-rw-r--r--kmymoney2/widgets/kmymoneyonlinequoteconfigdecl.ui231
-rw-r--r--kmymoney2/widgets/kmymoneypriceview.cpp343
-rw-r--r--kmymoney2/widgets/kmymoneypriceview.h87
-rw-r--r--kmymoney2/widgets/kmymoneyreportconfigtab1decl.ui123
-rw-r--r--kmymoney2/widgets/kmymoneyreportconfigtab2decl.ui282
-rw-r--r--kmymoney2/widgets/kmymoneyreportconfigtab3decl.ui437
-rw-r--r--kmymoney2/widgets/kmymoneyreportconfigtabchartdecl.ui214
-rw-r--r--kmymoney2/widgets/kmymoneyreportcontroldecl.ui150
-rw-r--r--kmymoney2/widgets/kmymoneyscheduledcalendar.cpp92
-rw-r--r--kmymoney2/widgets/kmymoneyscheduledcalendar.h87
-rw-r--r--kmymoney2/widgets/kmymoneyscheduleddatetbl.cpp530
-rw-r--r--kmymoney2/widgets/kmymoneyscheduleddatetbl.h73
-rw-r--r--kmymoney2/widgets/kmymoneyselector.cpp709
-rw-r--r--kmymoney2/widgets/kmymoneyselector.h387
-rw-r--r--kmymoney2/widgets/kmymoneytitlelabel.cpp104
-rw-r--r--kmymoney2/widgets/kmymoneytitlelabel.h78
-rw-r--r--kmymoney2/widgets/kmymoneywizard.cpp376
-rw-r--r--kmymoney2/widgets/kmymoneywizard.h539
-rw-r--r--kmymoney2/widgets/kmymoneywizard_p.h54
-rw-r--r--kmymoney2/widgets/kschedulebriefwidget.ui351
-rwxr-xr-xkmymoney2/widgets/makekdewidgets.in197
-rw-r--r--kmymoney2/widgets/register.cpp2438
-rw-r--r--kmymoney2/widgets/register.h605
-rw-r--r--kmymoney2/widgets/registeritem.cpp116
-rw-r--r--kmymoney2/widgets/registeritem.h226
-rw-r--r--kmymoney2/widgets/registersearchline.cpp301
-rw-r--r--kmymoney2/widgets/registersearchline.h151
-rw-r--r--kmymoney2/widgets/scheduledtransaction.cpp53
-rw-r--r--kmymoney2/widgets/scheduledtransaction.h86
-rw-r--r--kmymoney2/widgets/selectedtransaction.cpp69
-rw-r--r--kmymoney2/widgets/selectedtransaction.h87
-rw-r--r--kmymoney2/widgets/sortoptionlistitem.h390
-rw-r--r--kmymoney2/widgets/stdtransactiondownloaded.cpp70
-rw-r--r--kmymoney2/widgets/stdtransactiondownloaded.h130
-rw-r--r--kmymoney2/widgets/stdtransactionmatched.cpp217
-rw-r--r--kmymoney2/widgets/stdtransactionmatched.h103
-rw-r--r--kmymoney2/widgets/transaction.cpp2189
-rw-r--r--kmymoney2/widgets/transaction.h420
-rw-r--r--kmymoney2/widgets/transactioneditorcontainer.cpp29
-rw-r--r--kmymoney2/widgets/transactioneditorcontainer.h58
-rw-r--r--kmymoney2/widgets/transactionform.cpp467
-rw-r--r--kmymoney2/widgets/transactionform.h223
-rw-r--r--kmymoney2/widgets/transactionsortoption.ui287
-rw-r--r--kmymoney2/widgets/transactionsortoption.ui.h243
-rw-r--r--kmymoney2/wizards/Makefile.am5
-rw-r--r--kmymoney2/wizards/newaccountwizard/Makefile.am20
-rw-r--r--kmymoney2/wizards/newaccountwizard/kaccountsummarypagedecl.ui80
-rw-r--r--kmymoney2/wizards/newaccountwizard/kaccounttypepagedecl.ui289
-rw-r--r--kmymoney2/wizards/newaccountwizard/kbrokeragepagedecl.ui172
-rw-r--r--kmymoney2/wizards/newaccountwizard/kgeneralloaninfopagedecl.ui358
-rw-r--r--kmymoney2/wizards/newaccountwizard/khierarchypagedecl.ui82
-rw-r--r--kmymoney2/wizards/newaccountwizard/kinstitutionpagedecl.ui156
-rw-r--r--kmymoney2/wizards/newaccountwizard/kloandetailspagedecl.ui288
-rw-r--r--kmymoney2/wizards/newaccountwizard/kloanpaymentpagedecl.ui184
-rw-r--r--kmymoney2/wizards/newaccountwizard/kloanpayoutpagedecl.ui198
-rw-r--r--kmymoney2/wizards/newaccountwizard/kloanschedulepagedecl.ui160
-rw-r--r--kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp1691
-rw-r--r--kmymoney2/wizards/newaccountwizard/knewaccountwizard.h182
-rw-r--r--kmymoney2/wizards/newaccountwizard/knewaccountwizard_p.h327
-rw-r--r--kmymoney2/wizards/newaccountwizard/kschedulepagedecl.ui187
-rw-r--r--kmymoney2/wizards/newuserwizard/Makefile.am18
-rw-r--r--kmymoney2/wizards/newuserwizard/kaccountpagedecl.ui268
-rw-r--r--kmymoney2/wizards/newuserwizard/kcurrencypagedecl.ui82
-rw-r--r--kmymoney2/wizards/newuserwizard/kfilepagedecl.ui86
-rw-r--r--kmymoney2/wizards/newuserwizard/kgeneralpagedecl.ui258
-rw-r--r--kmymoney2/wizards/newuserwizard/kintropagedecl.ui66
-rw-r--r--kmymoney2/wizards/newuserwizard/knewuserwizard.cpp363
-rw-r--r--kmymoney2/wizards/newuserwizard/knewuserwizard.h123
-rw-r--r--kmymoney2/wizards/newuserwizard/knewuserwizard_p.h140
-rw-r--r--kmymoney2/wizards/newuserwizard/kpasswordpagedecl.ui33
-rw-r--r--kmymoney2/wizards/newuserwizard/kpreferencepagedecl.ui96
-rw-r--r--kmymoney2/wizards/wizardpages/Makefile.am18
-rw-r--r--kmymoney2/wizards/wizardpages/accounts.cpp39
-rw-r--r--kmymoney2/wizards/wizardpages/accounts.h42
-rw-r--r--kmymoney2/wizards/wizardpages/accountsdecl.ui54
-rw-r--r--kmymoney2/wizards/wizardpages/currency.cpp66
-rw-r--r--kmymoney2/wizards/wizardpages/currency.h45
-rw-r--r--kmymoney2/wizards/wizardpages/currencydecl.ui96
-rw-r--r--kmymoney2/wizards/wizardpages/userinfo.cpp52
-rw-r--r--kmymoney2/wizards/wizardpages/userinfo.h44
-rw-r--r--kmymoney2/wizards/wizardpages/userinfodecl.ui225
-rw-r--r--kmymoney2/x-kmymoney2.desktop13
1513 files changed, 204352 insertions, 0 deletions
diff --git a/kmymoney2/Makefile.am b/kmymoney2/Makefile.am
new file mode 100644
index 0000000..ca20182
--- /dev/null
+++ b/kmymoney2/Makefile.am
@@ -0,0 +1,171 @@
+KDE_OPTIONS = noautodist
+
+bin_PROGRAMS = kmymoney2
+
+kmymoney2_SOURCES = kmymoneyutils.cpp kstartuplogo.cpp kmymoney2.cpp main.cpp kmymoney2.stub kmymoney2.skel kmymoneysettings.kcfgc kmymoneyglobalsettings.cpp
+
+kmymoney2_LDADD = $(top_builddir)/kmymoney2/views/libviews.a $(top_builddir)/kmymoney2/reports/libreports.a $(top_builddir)/kmymoney2/wizards/newuserwizard/libnewuserwizard.a $(top_builddir)/kmymoney2/wizards/newaccountwizard/libnewaccountwizard.a $(top_builddir)/kmymoney2/wizards/wizardpages/libwizardpages.a $(top_builddir)/kmymoney2/dialogs/libdialogs.a $(top_builddir)/kmymoney2/dialogs/settings/libsettings.a $(top_builddir)/kmymoney2/widgets/libwidgets.a $(top_builddir)/kmymoney2/converter/libconverter.a $(top_builddir)/kmymoney2/mymoney/storage/libstorage.a $(top_builddir)/kmymoney2/mymoney/libkmm_mymoney.la $(top_builddir)/libkgpgfile/libkgpgfile.la $(top_builddir)/kmymoney2/plugins/interfaces/libinterfaces.a $(top_builddir)/kmymoney2/plugins/libkmm_plugin.la $(top_builddir)/libkdchart/libkmm_kdchart.la dialogs/libdialogs.a $(LIB_KABC) $(LIB_KHTML) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT)
+
+SUBDIRS = mymoney widgets dialogs wizards views converter pics icons html templates plugins reports misc
+
+EXTRA_DIST = kmymoney2ui.rc kmymoney2.desktop lo16-app-kmymoney2.png lo32-app-kmymoney2.png kmymoney_wizard.png mimetype_kmy_16x16.png mimetype_kmy_32x32.png mimetype_kmy_48x48.png mimetype_kmy_64x64.png mimetype_kmy_128x128.png x-kmymoney2.desktop hi16-app-kmymoney2.png hi32-app-kmymoney2.png hi48-app-kmymoney2.png hi64-app-kmymoney2.png hi128-app-kmymoney2.png tips kmymoney2.kcfg kmymoneysettings.kcfgc
+
+# make sure, automatically generated files exist
+BUILT_SOURCES = kmymoneysettings.h $(top_builddir)/kmymoney/kmymoneysettings.h
+
+# we have to make sure, that the symbolic link exists
+$(top_builddir)/kmymoney/kmymoneysettings.h: kmymoneysettings.h
+ if test -h $@; then rm $@; fi
+ ln -s `pwd`/kmymoneysettings.h $@
+
+kde_kcfg_DATA = kmymoney2.kcfg
+
+instdir=$(includedir)/kmymoney
+inst_HEADERS = export.h kmymoneyutils.h kmymoneyglobalsettings.h
+noinst_HEADERS = kmymoney2.h kstartuplogo.h
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/kmymoney2/
+ $(INSTALL_DATA) $(srcdir)/kmymoney2ui.rc $(DESTDIR)$(kde_datadir)/kmymoney2/kmymoney2ui.rc
+ $(mkinstalldirs) $(DESTDIR)$(xdg_appsdir)
+ $(INSTALL_DATA) $(srcdir)/kmymoney2.desktop $(DESTDIR)$(xdg_appsdir)/kmymoney2.desktop
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/locolor/16x16/apps/
+ $(INSTALL_DATA) $(srcdir)/lo16-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/locolor/16x16/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/locolor/32x32/apps/
+ $(INSTALL_DATA) $(srcdir)/lo32-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/locolor/32x32/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/16x16/mimetypes/
+ $(INSTALL_DATA) $(srcdir)/mimetype_kmy_16x16.png $(DESTDIR)$(kde_icondir)/hicolor/16x16/mimetypes/kmy.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/32x32/mimetypes/
+ $(INSTALL_DATA) $(srcdir)/mimetype_kmy_32x32.png $(DESTDIR)$(kde_icondir)/hicolor/32x32/mimetypes/kmy.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/48x48/mimetypes/
+ $(INSTALL_DATA) $(srcdir)/mimetype_kmy_48x48.png $(DESTDIR)$(kde_icondir)/hicolor/48x48/mimetypes/kmy.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/64x64/mimetypes/
+ $(INSTALL_DATA) $(srcdir)/mimetype_kmy_64x64.png $(DESTDIR)$(kde_icondir)/hicolor/64x64/mimetypes/kmy.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/128x128/mimetypes/
+ $(INSTALL_DATA) $(srcdir)/mimetype_kmy_128x128.png $(DESTDIR)$(kde_icondir)/hicolor/128x128/mimetypes/kmy.png
+ $(mkinstalldirs) $(kde_mimedir)/application/
+ $(INSTALL_DATA) $(srcdir)/x-kmymoney2.desktop $(kde_mimedir)/application/x-kmymoney2.desktop
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/16x16/apps/
+ $(INSTALL_DATA) $(srcdir)/hi16-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/hicolor/16x16/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/32x32/apps/
+ $(INSTALL_DATA) $(srcdir)/hi32-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/hicolor/32x32/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/48x48/apps/
+ $(INSTALL_DATA) $(srcdir)/hi48-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/hicolor/48x48/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/64x64/apps/
+ $(INSTALL_DATA) $(srcdir)/hi64-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/hicolor/64x64/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_icondir)/hicolor/128x128/apps/
+ $(INSTALL_DATA) $(srcdir)/hi128-app-kmymoney2.png $(DESTDIR)$(kde_icondir)/hicolor/128x128/apps/kmymoney2.png
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/kmymoney2/
+ $(INSTALL_DATA) $(srcdir)/tips $(DESTDIR)$(kde_datadir)/kmymoney2/tips
+
+
+uninstall-local:
+ -rm -f $(DESTDIR)$(kde_datadir)/kmymoney2/kmymoney2ui.rc
+ -rm -f $(DESTDIR)$(xdg_appsdir)/kmymoney2.desktop
+ -rm -f $(DESTDIR)$(kde_icondir)/locolor/16x16/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_icondir)/locolor/32x32/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/16x16/mimetypes/kmy.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/32x32/mimetypes/kmy.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/48x48/mimetypes/kmy.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/64x64/mimetypes/kmy.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/128x128/mimetypes/kmy.png
+ -rm -f $(DESTDIR)$(kde_mimedir)/application/x-kmymoney2.desktop
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/16x16/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/32x32/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/48x48/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/64x64/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_icondir)/hicolor/128x128/apps/kmymoney2.png
+ -rm -f $(DESTDIR)$(kde_datadir)/kmymoney2/tips
+
+####### kdevelop will overwrite this part!!! (end)############
+# this 10 paths are KDE specific. Use them:
+# kde_htmldir Where your docs should go to. (contains lang subdirs)
+# kde_appsdir Where your application file (.kdelnk) should go to.
+# kde_icondir Where your icon should go to.
+# kde_minidir Where your mini icon should go to.
+# kde_datadir Where you install application data. (Use a subdir)
+# kde_locale Where translation files should go to.(contains lang subdirs)
+# kde_cgidir Where cgi-bin executables should go to.
+# kde_confdir Where config files should go to.
+# kde_mimedir Where mimetypes should go to.
+# kde_toolbardir Where general toolbar icons should go to.
+# kde_wallpaperdir Where general wallpapers should go to.
+
+DISTCLEANFILES=kmymoney2 *.html *.csv old.asc stripped.txt kmm_test_driver
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes) -I$(top_srcdir) -I. -I$(top_builddir)/kmymoney2/dialogs -I$(top_srcdir)/libkdchart
+
+METASOURCES = AUTO
+
+# the library search path.
+kmymoney2_LDFLAGS = $(all_libraries) $(kde_RPATH) -export-dynamic
+
+# Uncomment the following two lines if you add a ui.rc file for your application to make use of
+# KDE
+rcdir = $(kde_datadir)/kmymoney2
+rc_DATA = kmymoney2ui.rc
+
+#WARNING: if you use a ui.rc file above, use:
+
+# messages: rc.cpp
+
+# instead of
+
+# messages:
+
+# Remove *.moc.* files from the list of files searched for messages.
+# Don't know, if that has any negative effect, but it avoids to include
+# automatically generated names which usually not need to be translated
+# from clobbering the pot file. (ipwizard@user.sourceforge.net, 07/16/2003)
+messages: rc.cpp
+ if test -f tips; then \
+ $(PREPARETIPS) > _tips.cpp; \
+ fi;
+ LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o \
+ -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o \
+ -name \*.C | grep -v -E \*\.moc\.\*`; \
+ if test -n "$$LIST"; then \
+ $(XGETTEXT) $$LIST -o $(podir)/kmymoney2.pot; \
+ fi
+ if test -f _tips.cpp; then \
+ rm _tips.cpp; \
+ fi
+
+#
+# since some people might think, the application is called kmymoney, we
+# create a link to kmymoney2 after overall installation
+#
+install-exec-hook:
+ @$(NORMAL_INSTALL)
+ @list='kmymoney2'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo "Creating symbolic link from kmymoney -> ./kmymoney2"; \
+ rm -f $(DESTDIR)$(bindir)/kmymoney; \
+ cd $(DESTDIR)$(bindir); \
+ ln -s ./$$f kmymoney; \
+ else :; fi; \
+ done
+
+uninstall-hook:
+ -rm -f $(DESTDIR)$(bindir)/kmymoney
+
+dist-hook:
+ -rm -rf $(distdir)/kmymoneysettings.cpp
+
+if CPPUNIT
+TESTS = kmymoneytest
+
+check_PROGRAMS = kmymoneytest
+
+kmymoneytest_SOURCES = kmymoneytest.cpp kmymoneyutils.cpp kmymoneyglobalsettings.cpp
+kmymoneytest_LDADD = ./mymoney/storage/libstoragetest.a ./mymoney/libmymoneytest.a ./converter/libconvertertest.a ./reports/libreportstest.a $(kmymoney2_LDADD) kmymoneysettings.$(OBJEXT)
+
+# the library search path.
+kmymoneytest_LDFLAGS = $(all_libraries) $(kde_RPATH) $(CPPUNIT_LIBS)
+endif
+
diff --git a/kmymoney2/converter/Makefile.am b/kmymoney2/converter/Makefile.am
new file mode 100644
index 0000000..b54449e
--- /dev/null
+++ b/kmymoney2/converter/Makefile.am
@@ -0,0 +1,24 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I. -I$(top_srcdir)/kmymoney2 -I$(top_builddir)/kmymoney2
+
+instdir=$(includedir)/kmymoney
+
+noinst_LIBRARIES = libconverter.a
+libconverter_a_METASOURCES = AUTO
+
+libconverter_a_SOURCES = mymoneyqifreader.cpp mymoneyqifwriter.cpp mymoneyqifprofile.cpp mymoneytemplate.cpp mymoneystatementreader.cpp webpricequote.cpp mymoneygncreader.cpp
+
+EXTRA_DIST =
+
+inst_HEADERS = mymoneytemplate.h
+
+noinst_HEADERS = imymoneyreader.h mymoneyqifprofile.h mymoneyqifreader.h mymoneyqifwriter.h mymoneystatementreader.h webpricequote.h mymoneygncreader.h convertertest.h
+
+if CPPUNIT
+check_LIBRARIES = libconvertertest.a
+
+libconvertertest_a_SOURCES = convertertest.cpp
+endif
+
+
diff --git a/kmymoney2/converter/convertertest.cpp b/kmymoney2/converter/convertertest.cpp
new file mode 100644
index 0000000..aef63d9
--- /dev/null
+++ b/kmymoney2/converter/convertertest.cpp
@@ -0,0 +1,211 @@
+/***************************************************************************
+ convertertest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qdom.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "convertertest.h"
+
+// uses helper functions from reports tests
+#include "../reports/reportstestcommon.h"
+using namespace test;
+
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/mymoneystatement.h>
+#include "../mymoney/storage/mymoneystoragexml.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+
+#define private public
+#include "../converter/webpricequote.h"
+#undef private
+
+ConverterTest::ConverterTest()
+{
+}
+
+using namespace convertertest;
+
+void ConverterTest::setUp () {
+
+ storage = new MyMoneySeqAccessMgr;
+ file = MyMoneyFile::instance();
+ file->attachStorage(storage);
+
+ MyMoneyFileTransaction ft;
+
+ file->addCurrency(MyMoneySecurity("CAD", "Canadian Dollar", "C$"));
+ file->addCurrency(MyMoneySecurity("USD", "US Dollar", "$"));
+ file->addCurrency(MyMoneySecurity("JPY", "Japanese Yen", QChar(0x00A5), 100, 1));
+ file->addCurrency(MyMoneySecurity("GBP", "British Pound", "#"));
+ file->setBaseCurrency(file->currency("USD"));
+
+ MyMoneyPayee payeeTest("Test Payee");
+ file->addPayee(payeeTest);
+ MyMoneyPayee payeeTest2("Thomas Baumgart");
+ file->addPayee(payeeTest2);
+
+ acAsset = (MyMoneyFile::instance()->asset().id());
+ acLiability = (MyMoneyFile::instance()->liability().id());
+ acExpense = (MyMoneyFile::instance()->expense().id());
+ acIncome = (MyMoneyFile::instance()->income().id());
+ acChecking = makeAccount("Checking Account",MyMoneyAccount::Checkings,moConverterCheckingOpen,QDate(2004,5,15),acAsset);
+ acCredit = makeAccount("Credit Card",MyMoneyAccount::CreditCard,moConverterCreditOpen,QDate(2004,7,15),acLiability);
+ acSolo = makeAccount("Solo",MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acParent = makeAccount("Parent",MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acChild = makeAccount("Child",MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent);
+ acForeign = makeAccount("Foreign",MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+
+ MyMoneyInstitution i("Bank of the World","","","","","","");
+ file->addInstitution(i);
+ inBank = i.id();
+ ft.commit();
+}
+
+void ConverterTest::tearDown ()
+{
+ file->detachStorage(storage);
+ delete storage;
+}
+
+void ConverterTest::testWebQuotes()
+{
+#ifdef PERFORM_ONLINE_TESTS
+ try
+ {
+ WebPriceQuote q;
+ QuoteReceiver qr(&q);
+
+ q.launch("DIS");
+
+// kdDebug(2) << "ConverterTest::testWebQuotes(): quote for " << q.m_symbol << " on " << qr.m_date.toString() << " is " << qr.m_price.toString() << " errors(" << qr.m_errors.count() << "): " << qr.m_errors.join(" /// ") << endl;
+
+ // No errors allowed
+ CPPUNIT_ASSERT(qr.m_errors.count() == 0);
+
+ // Quote date should be within the last week, or something bad is going on.
+ CPPUNIT_ASSERT(qr.m_date <= QDate::currentDate());
+ CPPUNIT_ASSERT(qr.m_date >= QDate::currentDate().addDays(-7));
+
+ // Quote value should at least be positive
+ CPPUNIT_ASSERT(qr.m_price.isPositive());
+
+ q.launch("MF8AAUKS.L","Yahoo UK");
+
+// kdDebug(2) << "ConverterTest::testWebQuotes(): quote for " << q.m_symbol << " on " << qr.m_date.toString() << " is " << qr.m_price.toString() << " errors(" << qr.m_errors.count() << "): " << qr.m_errors.join(" /// ") << endl;
+
+ CPPUNIT_ASSERT(qr.m_errors.count() == 0);
+ CPPUNIT_ASSERT(qr.m_date <= QDate::currentDate().addDays(1));
+ CPPUNIT_ASSERT(qr.m_date >= QDate::currentDate().addDays(-7));
+ CPPUNIT_ASSERT(qr.m_price.isPositive());
+
+ q.launch("EUR > USD","Yahoo Currency");
+
+// kdDebug(2) << "ConverterTest::testWebQuotes(): quote for " << q.m_symbol << " on " << qr.m_date.toString() << " is " << qr.m_price.toString() << " errors(" << qr.m_errors.count() << "): " << qr.m_errors.join(" /// ") << endl;
+
+ CPPUNIT_ASSERT(qr.m_errors.count() == 0);
+ CPPUNIT_ASSERT(qr.m_date <= QDate::currentDate().addDays(1));
+ CPPUNIT_ASSERT(qr.m_date >= QDate::currentDate().addDays(-7));
+ CPPUNIT_ASSERT(qr.m_price.isPositive());
+
+ q.launch("50492","Globe & Mail");
+
+// kdDebug(2) << "ConverterTest::testWebQuotes(): quote for " << q.m_symbol << " on " << qr.m_date.toString() << " is " << qr.m_price.toString() << " errors(" << qr.m_errors.count() << "): " << qr.m_errors.join(" /// ") << endl;
+
+ CPPUNIT_ASSERT(qr.m_errors.count() == 0);
+ CPPUNIT_ASSERT(qr.m_date <= QDate::currentDate().addDays(1));
+ CPPUNIT_ASSERT(qr.m_date >= QDate::currentDate().addDays(-7));
+ CPPUNIT_ASSERT(qr.m_price.isPositive());
+
+ q.launch("TDB647","MSN.CA");
+
+// kdDebug(2) << "ConverterTest::testWebQuotes(): quote for " << q.m_symbol << " on " << qr.m_date.toString() << " is " << qr.m_price.toString() << " errors(" << qr.m_errors.count() << "): " << qr.m_errors.join(" /// ") << endl;
+
+ CPPUNIT_ASSERT(qr.m_errors.count() == 0);
+ CPPUNIT_ASSERT(qr.m_date <= QDate::currentDate().addDays(1));
+ CPPUNIT_ASSERT(qr.m_date >= QDate::currentDate().addDays(-7));
+ CPPUNIT_ASSERT(qr.m_price.isPositive());
+
+ }
+ catch (MyMoneyException* e)
+ {
+ CPPUNIT_FAIL(e->what());
+ }
+#endif
+}
+
+void ConverterTest::testDateFormat()
+{
+ try
+ {
+ MyMoneyDateFormat format("%mm-%dd-%yyyy");
+
+ CPPUNIT_ASSERT(format.convertString("1-5-2005") == QDate(2005,1,5));
+ CPPUNIT_ASSERT(format.convertString("jan-15-2005") == QDate(2005,1,15));
+ CPPUNIT_ASSERT(format.convertString("august-25-2005") == QDate(2005,8,25));
+
+ format = MyMoneyDateFormat("%mm/%dd/%yy");
+
+ CPPUNIT_ASSERT(format.convertString("1/5/05") == QDate(2005,1,5));
+ CPPUNIT_ASSERT(format.convertString("jan/15/05") == QDate(2005,1,15));
+ CPPUNIT_ASSERT(format.convertString("august/25/05") == QDate(2005,8,25));
+
+ format = MyMoneyDateFormat("%d\\.%m\\.%yy");
+
+ CPPUNIT_ASSERT(format.convertString("1.5.05") == QDate(2005,5,1));
+ CPPUNIT_ASSERT(format.convertString("15.jan.05") == QDate(2005,1,15));
+ CPPUNIT_ASSERT(format.convertString("25.august.05") == QDate(2005,8,25));
+
+ format = MyMoneyDateFormat("%yyyy\\\\%dddd\\\\%mmmmmmmmmmm");
+
+ CPPUNIT_ASSERT(format.convertString("2005\\31\\12") == QDate(2005,12,31));
+ CPPUNIT_ASSERT(format.convertString("2005\\15\\jan") == QDate(2005,1,15));
+ CPPUNIT_ASSERT(format.convertString("2005\\25\\august") == QDate(2005,8,25));
+
+ format = MyMoneyDateFormat("%m %dd, %yyyy");
+
+ CPPUNIT_ASSERT(format.convertString("jan 15, 2005") == QDate(2005,1,15));
+ CPPUNIT_ASSERT(format.convertString("august 25, 2005") == QDate(2005,8,25));
+ CPPUNIT_ASSERT(format.convertString("january 1st, 2005") == QDate(2005,1,1));
+
+ format = MyMoneyDateFormat("%m %d %y");
+
+ CPPUNIT_ASSERT(format.convertString("12/31/50",false,2000) == QDate(1950,12,31));
+ CPPUNIT_ASSERT(format.convertString("1/1/90",false,2000) == QDate(1990,1,1));
+ CPPUNIT_ASSERT(format.convertString("december 31st, 5",false) == QDate(2005,12,31));
+ }
+ catch (MyMoneyException* e)
+ {
+ CPPUNIT_FAIL(e->what());
+ }
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/converter/convertertest.h b/kmymoney2/converter/convertertest.h
new file mode 100644
index 0000000..98d4289
--- /dev/null
+++ b/kmymoney2/converter/convertertest.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ convertertest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.jones@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CONVERTERTEST_H
+#define CONVERTERTEST_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+class ConverterTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(ConverterTest);
+ CPPUNIT_TEST(testWebQuotes);
+ CPPUNIT_TEST(testDateFormat);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ MyMoneyAccount *m;
+
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyFile* file;
+
+public:
+ ConverterTest();
+ void setUp ();
+ void tearDown ();
+ void testWebQuotes();
+ void testDateFormat();
+};
+
+#endif // CONVERTERTEST_H
diff --git a/kmymoney2/converter/imymoneyreader.h b/kmymoney2/converter/imymoneyreader.h
new file mode 100644
index 0000000..6222af5
--- /dev/null
+++ b/kmymoney2/converter/imymoneyreader.h
@@ -0,0 +1,135 @@
+ /***************************************************************************
+ imymoneyreader.h - description
+ -------------------
+ begin : Wed Feb 25 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMYMONEYREADER_H
+#define IMYMONEYREADER_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <ktempfile.h>
+#include <kprocess.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "../mymoney/mymoneyaccount.h"
+
+/**
+ * @author Kevin Tambascio
+ */
+
+class IMyMoneyReader : public QObject
+{
+public:
+ IMyMoneyReader() {}
+ virtual ~IMyMoneyReader() {}
+
+ Q_OBJECT
+
+ /**
+ * This method is used to store the filename into the object.
+ * The file should exist. If it does and an external filter
+ * program is specified with the current selected profile,
+ * the file is send through this filter and the result
+ * is stored in the m_tempFile file.
+ *
+ * @param name path and name of the file to be imported
+ */
+ virtual void setFilename(const QString& name)=0;
+
+ /**
+ * This method is used to store the name of the profile into the object.
+ * The selected profile will be loaded if it exists. If an external
+ * filter program is specified with the current selected profile,
+ * the file is send through this filter and the result
+ * is stored in the m_tempFile file.
+ *
+ * @param name QString reference to the name of the profile
+ */
+ virtual void setProfile(const QString& name)=0;
+
+ /**
+ * This method actually starts the import of data from the selected file
+ * into the MyMoney engine.
+ *
+ * This method also starts the user defined import filter program
+ * defined in the QIF profile(when a QIF file is selected). If none is
+ * defined, the file is read as is (actually the UNIX command
+ * 'cat -' is used as the filter).
+ *
+ * If data from the filter program is available, the slot
+ * slotReceivedDataFromFilter() will be called.
+ *
+ * Make sure to connect the signal importFinished() to detect when
+ * the import actually ended. Call the method finishImport() to clean
+ * things up and get the overall result of the import.
+ *
+ * @retval true the import was started successfully
+ * @retval false the import could not be started.
+ */
+ virtual const bool startImport(void)=0;
+
+ /**
+ * This method must be called once the signal importFinished() has
+ * been emitted. It will clean up the reader state and determines
+ * the actual return code of the import.
+ *
+ * @retval true Import was successful.
+ * @retval false Import failed because the filter program terminated
+ * abnormally or the user aborted the import process.
+ */
+ virtual const bool finishImport(void)=0;
+
+ /**
+ * This method is used to modify the auto payee creation flag.
+ * If this flag is set, records for payees that are not currently
+ * found in the engine will be automatically created with no
+ * further user interaction required. If this flag is no set,
+ * the user will be asked if the payee should be created or not.
+ * If the MyMoneyQifReader object is created auto payee creation
+ * is turned off.
+ *
+ * @param create flag if this feature should be turned on (@p true)
+ * or turned off (@p false)
+ */
+ virtual void setAutoCreatePayee(const bool create)=0;
+ virtual void setAskPayeeCategory(const bool ask)=0;
+
+ virtual const MyMoneyAccount& account() const { return m_account; };
+ virtual void setProgressCallback(void(*callback)(int, int, const QString&)) { m_progressCallback = callback; }
+
+private:
+ MyMoneyAccount m_account;
+ void (*m_progressCallback)(int, int, const QString&);
+ QString m_filename;
+
+};
+
+#endif
diff --git a/kmymoney2/converter/mymoneygncreader.cpp b/kmymoney2/converter/mymoneygncreader.cpp
new file mode 100644
index 0000000..40933e3
--- /dev/null
+++ b/kmymoney2/converter/mymoneygncreader.cpp
@@ -0,0 +1,2463 @@
+/***************************************************************************
+ mymoneygncreader - description
+ -------------------
+begin : Wed Mar 3 2004
+copyright : (C) 2000-2004 by Michael Edwardes
+email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qfile.h>
+#include <qmap.h>
+#include <qobject.h>
+#include <qfiledialog.h>
+#include <qinputdialog.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#ifndef _GNCFILEANON
+ #include <klocale.h>
+ #include <kconfig.h>
+ #include <kmessagebox.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// Third party Includes
+
+// ------------------------------------------------------------Box21----------------
+// Project Includes
+#include "mymoneygncreader.h"
+#ifndef _GNCFILEANON
+ #include "config.h"
+ #include "../mymoney/storage/imymoneystorage.h"
+ #include "../kmymoneyutils.h"
+ #include "../mymoney/mymoneyfile.h"
+ #include "../mymoney/mymoneyprice.h"
+ #include "../dialogs/kgncimportoptionsdlg.h"
+ #include "../dialogs/kgncpricesourcedlg.h"
+ #include "../dialogs/keditscheduledlg.h"
+ #include "../widgets/kmymoneyedit.h"
+ #define TRY try {
+ #define CATCH } catch (MyMoneyException *e) {
+ #define PASS } catch (MyMoneyException *e) { throw e; }
+#else
+ #include "mymoneymoney.h"
+ #include <qtextedit.h>
+ #define i18n QObject::tr
+ #define TRY
+ #define CATCH
+ #define PASS
+ #define MYMONEYEXCEPTION QString
+ #define MyMoneyException QString
+ #define PACKAGE "KMyMoney"
+#endif // _GNCFILEANON
+
+// init static variables
+double MyMoneyGncReader::m_fileHideFactor = 0.0;
+double GncObject::m_moneyHideFactor;
+
+// user options
+void MyMoneyGncReader::setOptions () {
+#ifndef _GNCFILEANON
+ KGncImportOptionsDlg dlg; // display the dialog to allow the user to set own options
+ if (dlg.exec()) {
+ // set users input options
+ m_dropSuspectSchedules = dlg.scheduleOption();
+ m_investmentOption = dlg.investmentOption();
+ m_useFinanceQuote = dlg.quoteOption();
+ m_useTxNotes = dlg.txNotesOption();
+ m_decoder = dlg.decodeOption();
+ gncdebug = dlg.generalDebugOption();
+ xmldebug = dlg.xmlDebugOption();
+ bAnonymize = dlg.anonymizeOption();
+ } else {
+ // user declined, so set some sensible defaults
+ m_dropSuspectSchedules = false;
+ // investment option - 0, create investment a/c per stock a/c, 1 = single new investment account, 2 = prompt for each stock
+ // option 2 doesn't really work too well at present
+ m_investmentOption = 0;
+ m_useFinanceQuote = false;
+ m_useTxNotes = false;
+ m_decoder = 0;
+ gncdebug = false; // general debug messages
+ xmldebug = false; // xml trace
+ bAnonymize = false; // anonymize input
+ }
+ // no dialog option for the following; it will set base currency, and print actual XML data
+ developerDebug = false;
+ // set your fave currency here to save getting that enormous dialog each time you run a test
+ // especially if you have to scroll down to USD...
+ if (developerDebug) m_storage->setValue ("kmm-baseCurrency", "GBP");
+#endif // _GNCFILEANON
+}
+
+GncObject::GncObject () {
+ m_v.setAutoDelete (true);
+}
+
+// Check that the current element is of a version we are coded for
+void GncObject::checkVersion (const QString& elName, const QXmlAttributes& elAttrs, const map_elementVersions& map) {
+ TRY
+ if (map.contains(elName)) { // if it's not in the map, there's nothing to check
+ if (!map[elName].contains(elAttrs.value("version"))) {
+ QString em = i18n("%1: Sorry. This importer cannot handle version %2 of element %3")
+ .arg(__func__).arg(elAttrs.value("version")).arg(elName);
+ throw new MYMONEYEXCEPTION (em);
+ }
+ }
+ return ;
+ PASS
+}
+
+// Check if this element is in the current object's sub element list
+GncObject *GncObject::isSubElement (const QString& elName, const QXmlAttributes& elAttrs) {
+ TRY
+ uint i;
+ GncObject *next = 0;
+ for (i = 0; i < m_subElementListCount; i++) {
+ if (elName == m_subElementList[i]) {
+ m_state = i;
+ next = startSubEl(); // go create the sub object
+ if (next != 0) {
+ next->initiate(elName, elAttrs); // initialize it
+ next->m_elementName = elName; // save it's name so we can identify the end
+ }
+ break;
+ }
+ }
+ return (next);
+ PASS
+}
+
+// Check if this element is in the current object's data element list
+bool GncObject::isDataElement (const QString &elName, const QXmlAttributes& elAttrs) {
+ TRY
+ uint i;
+ for (i = 0; i < m_dataElementListCount; i++) {
+ if (elName == m_dataElementList[i]) {
+ m_state = i;
+ dataEl(elAttrs); // go set the pointer so the data can be stored
+ return (true);
+ }
+ }
+ m_dataPtr = 0; // we don't need this, so make sure we don't store extraneous data
+ return (false);
+ PASS
+}
+
+// return the variable string, decoded if required
+QString GncObject::var (int i) const {
+ return (pMain->m_decoder == 0
+ ? *(m_v.at(i))
+ : pMain->m_decoder->toUnicode (*(m_v.at(i))));
+}
+
+void GncObject::adjustHideFactor () {
+ m_moneyHideFactor = pMain->m_fileHideFactor * (1.0 + (int)(200.0 * rand()/(RAND_MAX+1.0))) / 100.0;
+}
+
+// data anonymizer
+QString GncObject::hide (QString data, unsigned int anonClass) {
+ TRY
+ if (!pMain->bAnonymize) return (data); // no anonymizing required
+ // counters used to generate names for anonymizer
+ static int nextAccount;
+ static int nextEquity;
+ static int nextPayee;
+ static int nextSched;
+ static QMap<QString, QString> anonPayees; // to check for duplicate payee names
+ static QMap<QString, QString> anonStocks; // for reference to equities
+
+ QString result (data);
+ QMap<QString, QString>::Iterator it;
+ MyMoneyMoney in, mresult;
+ switch (anonClass) {
+ case ASIS: break; // this is not personal data
+ case SUPPRESS: result = ""; break; // this is personal and is not essential
+ case NXTACC: result = i18n("Account%1").arg(++nextAccount, -6); break; // generate account name
+ case NXTEQU: // generate/return an equity name
+ it = anonStocks.find (data);
+ if (it == anonStocks.end()) {
+ result = i18n("Stock%1").arg(++nextEquity, -6);
+ anonStocks.insert (data, result);
+ } else {
+ result = (*it).data();
+ }
+ break;
+ case NXTPAY: // genearet/return a payee name
+ it = anonPayees.find (data);
+ if (it == anonPayees.end()) {
+ result = i18n("Payee%1").arg(++nextPayee, -6);
+ anonPayees.insert (data, result);
+ } else {
+ result = (*it).data();
+ }
+ break;
+ case NXTSCHD: result = i18n("Schedule%1").arg(++nextSched, -6); break; // generate a schedule name
+ case MONEY1:
+ in = MyMoneyMoney(data);
+ if (data == "-1/0") in = MyMoneyMoney (0); // spurious gnucash data - causes a crash sometimes
+ mresult = MyMoneyMoney(m_moneyHideFactor) * in;
+ mresult.convert(10000);
+ result = mresult.toString();
+ break;
+ case MONEY2:
+ in = MyMoneyMoney(data);
+ if (data == "-1/0") in = MyMoneyMoney (0);
+ mresult = MyMoneyMoney(m_moneyHideFactor) * in;
+ mresult.convert(10000);
+ mresult.setThousandSeparator (' ');
+ result = mresult.formatMoney("", 2);
+ break;
+ }
+ return (result);
+ PASS
+}
+
+// dump current object data values // only called if gncdebug set
+void GncObject::debugDump () {
+ uint i;
+ qDebug ("Object %s", m_elementName.latin1());
+ for (i = 0; i < m_dataElementListCount; i++) {
+ qDebug ("%s = %s", m_dataElementList[i].latin1(), m_v.at(i)->latin1());
+ }
+}
+//*****************************************************************
+GncFile::GncFile () {
+ static const QString subEls[] = {"gnc:book", "gnc:count-data", "gnc:commodity", "price",
+ "gnc:account", "gnc:transaction", "gnc:template-transactions",
+ "gnc:schedxaction"
+ };
+ m_subElementList = subEls;
+ m_subElementListCount = END_FILE_SELS;
+ m_dataElementListCount = 0;
+ m_processingTemplates = false;
+ m_bookFound = false;
+}
+
+GncFile::~GncFile () {}
+
+GncObject *GncFile::startSubEl() {
+ TRY
+ if (pMain->xmldebug) qDebug ("File start subel m_state %d", m_state);
+ GncObject *next = 0;
+ switch (m_state) {
+ case BOOK:
+ if (m_bookFound) throw new MYMONEYEXCEPTION (i18n("This version of the importer cannot handle multi-book files."));
+ m_bookFound = true;
+ break;
+ case COUNT: next = new GncCountData; break;
+ case CMDTY: next = new GncCommodity; break;
+ case PRICE: next = new GncPrice; break;
+ case ACCT:
+ // accounts within the template section are ignored
+ if (!m_processingTemplates) next = new GncAccount;
+ break;
+ case TX: next = new GncTransaction (m_processingTemplates); break;
+ case TEMPLATES: m_processingTemplates = true; break;
+ case SCHEDULES: m_processingTemplates = false; next = new GncSchedule; break;
+ default: throw new MYMONEYEXCEPTION ("GncFile rcvd invalid state");
+ }
+ return (next);
+ PASS
+}
+
+void GncFile::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("File end subel");
+ if (!m_processingTemplates) delete subObj; // template txs must be saved awaiting schedules
+ m_dataPtr = 0;
+ return ;
+}
+//****************************************** GncDate *********************************************
+GncDate::GncDate () {
+ m_subElementListCount = 0;
+ static const QString dEls[] = {"ts:date", "gdate"};
+ m_dataElementList = dEls;
+ m_dataElementListCount = END_Date_DELS;
+ static const unsigned int anonClasses[] = {ASIS, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+}
+
+GncDate::~GncDate() {}
+//*************************************GncCmdtySpec***************************************
+GncCmdtySpec::GncCmdtySpec () {
+ m_subElementListCount = 0;
+ static const QString dEls[] = {"cmdty:space", "cmdty:id"};
+ m_dataElementList = dEls;
+ m_dataElementListCount = END_CmdtySpec_DELS;
+ static const unsigned int anonClasses[] = {ASIS, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+}
+
+GncCmdtySpec::~GncCmdtySpec () {}
+
+QString GncCmdtySpec::hide(QString data, unsigned int) {
+ // hide equity names, but not currency names
+ unsigned int newClass = ASIS;
+ switch (m_state) {
+ case CMDTYID:
+ if (!isCurrency()) newClass = NXTEQU;
+ }
+ return (GncObject::hide (data, newClass));
+}
+//************* GncKvp********************************************
+GncKvp::GncKvp () {
+ m_subElementListCount = END_Kvp_SELS;
+ static const QString subEls[] = {"slot"}; // kvp's may be nested
+ m_subElementList = subEls;
+ m_dataElementListCount = END_Kvp_DELS;
+ static const QString dataEls[] = {"slot:key", "slot:value"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_kvpList.setAutoDelete (true);
+}
+
+GncKvp::~GncKvp () {}
+
+void GncKvp::dataEl (const QXmlAttributes& elAttrs) {
+ switch (m_state) {
+ case VALUE:
+ m_kvpType = elAttrs.value("type");
+ }
+ m_dataPtr = m_v.at(m_state);
+ if (key().contains ("formula")) {
+ m_anonClass = MONEY2;
+ } else {
+ m_anonClass = ASIS;
+ }
+ return ;
+}
+
+GncObject *GncKvp::startSubEl() {
+ if (pMain->xmldebug) qDebug ("Kvp start subel m_state %d", m_state);
+ TRY
+ GncObject *next = 0;
+ switch (m_state) {
+ case KVP: next = new GncKvp; break;
+ default: throw new MYMONEYEXCEPTION ("GncKvp rcvd invalid m_state ");
+ }
+ return (next);
+ PASS
+}
+
+void GncKvp::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("Kvp end subel");
+ m_kvpList.append (subObj);
+ m_dataPtr = 0;
+ return ;
+}
+//*********************************GncLot*********************************************
+GncLot::GncLot() {
+ m_subElementListCount = 0;
+ m_dataElementListCount = 0;
+}
+
+GncLot::~GncLot() {}
+
+//*********************************GncCountData***************************************
+GncCountData::GncCountData() {
+ m_subElementListCount = 0;
+ m_dataElementListCount = 0;
+ m_v.append (new QString ("")); // only 1 data item
+}
+
+GncCountData::~GncCountData () {}
+
+void GncCountData::initiate (const QString&, const QXmlAttributes& elAttrs) {
+ m_countType = elAttrs.value ("cd:type");
+ m_dataPtr = m_v.at(0);
+ return ;
+}
+
+void GncCountData::terminate () {
+ int i = m_v.at(0)->toInt();
+ if (m_countType == "commodity") {
+ pMain->setGncCommodityCount(i); return ;
+ }
+ if (m_countType == "account") {
+ pMain->setGncAccountCount(i); return ;
+ }
+ if (m_countType == "transaction") {
+ pMain->setGncTransactionCount(i); return ;
+ }
+ if (m_countType == "schedxaction") {
+ pMain->setGncScheduleCount(i); return ;
+ }
+ if (i != 0) {
+ if (m_countType == "budget") pMain->setBudgetsFound(true);
+ else if (m_countType.left(7) == "gnc:Gnc") pMain->setSmallBusinessFound(true);
+ else if (pMain->xmldebug) qDebug ("Unknown count type %s", m_countType.latin1());
+ }
+ return ;
+}
+//*********************************GncCommodity***************************************
+GncCommodity::GncCommodity () {
+ m_subElementListCount = 0;
+ static const QString dEls[] = {"cmdty:space", "cmdty:id", "cmdty:name", "cmdty:fraction"};
+ m_dataElementList = dEls;
+ m_dataElementListCount = END_Commodity_DELS;
+ static const unsigned int anonClasses[] = {ASIS, NXTEQU, SUPPRESS, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+}
+
+GncCommodity::~GncCommodity () {}
+
+void GncCommodity::terminate() {
+ TRY
+ pMain->convertCommodity (this);
+ return ;
+ PASS
+}
+//************* GncPrice********************************************
+GncPrice::GncPrice () {
+ static const QString subEls[] = {"price:commodity", "price:currency", "price:time"};
+ m_subElementList = subEls;
+ m_subElementListCount = END_Price_SELS;
+ m_dataElementListCount = END_Price_DELS;
+ static const QString dataEls[] = {"price:value"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_vpCommodity = NULL;
+ m_vpCurrency = NULL;
+ m_vpPriceDate = NULL;
+}
+
+GncPrice::~GncPrice () {
+ delete m_vpCommodity; delete m_vpCurrency; delete m_vpPriceDate;
+}
+
+GncObject *GncPrice::startSubEl() {
+ TRY
+ GncObject *next = 0;
+ switch (m_state) {
+ case CMDTY: next = new GncCmdtySpec; break;
+ case CURR: next = new GncCmdtySpec; break;
+ case PRICEDATE: next = new GncDate; break;
+ default: throw new MYMONEYEXCEPTION ("GncPrice rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncPrice::endSubEl(GncObject *subObj) {
+ TRY
+ switch (m_state) {
+ case CMDTY: m_vpCommodity = static_cast<GncCmdtySpec *>(subObj); break;
+ case CURR: m_vpCurrency = static_cast<GncCmdtySpec *>(subObj); break;
+ case PRICEDATE: m_vpPriceDate = static_cast<GncDate *>(subObj); break;
+ default: throw new MYMONEYEXCEPTION ("GncPrice rcvd invalid m_state");
+ }
+ return;
+ PASS
+}
+
+void GncPrice::terminate() {
+ TRY
+ pMain->convertPrice (this);
+ return ;
+ PASS
+}
+//************* GncAccount********************************************
+GncAccount::GncAccount () {
+ m_subElementListCount = END_Account_SELS;
+ static const QString subEls[] = {"act:commodity", "slot", "act:lots"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_Account_DELS;
+ static const QString dataEls[] = {"act:id", "act:name", "act:description",
+ "act:type", "act:parent"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, NXTACC, SUPPRESS, ASIS, ASIS};
+ m_anonClassList = anonClasses;
+ m_kvpList.setAutoDelete (true);
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_vpCommodity = NULL;
+}
+
+GncAccount::~GncAccount () {
+ delete m_vpCommodity;
+}
+
+GncObject *GncAccount::startSubEl() {
+ TRY
+ if (pMain->xmldebug) qDebug ("Account start subel m_state %d", m_state);
+ GncObject *next = 0;
+ switch (m_state) {
+ case CMDTY: next = new GncCmdtySpec; break;
+ case KVP: next = new GncKvp; break;
+ case LOTS: next = new GncLot();
+ pMain->setLotsFound(true); // we don't handle lots; just set flag to report
+ break;
+ default: throw new MYMONEYEXCEPTION ("GncAccount rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncAccount::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("Account end subel");
+ switch (m_state) {
+ case CMDTY: m_vpCommodity = static_cast<GncCmdtySpec *>(subObj); break;
+ case KVP: m_kvpList.append (subObj);
+ }
+ return ;
+}
+
+void GncAccount::terminate() {
+ TRY
+ pMain->convertAccount (this);
+ return ;
+ PASS
+}
+//************* GncTransaction********************************************
+GncTransaction::GncTransaction (bool processingTemplates) {
+ m_subElementListCount = END_Transaction_SELS;
+ static const QString subEls[] = {"trn:currency", "trn:date-posted", "trn:date-entered",
+ "trn:split", "slot"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_Transaction_DELS;
+ static const QString dataEls[] = {"trn:id", "trn:num", "trn:description"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, SUPPRESS, NXTPAY};
+ m_anonClassList = anonClasses;
+ adjustHideFactor();
+ m_template = processingTemplates;
+ m_splitList.setAutoDelete (true);
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_vpCurrency = NULL;
+ m_vpDateEntered = m_vpDatePosted = NULL;
+}
+
+GncTransaction::~GncTransaction () {
+ delete m_vpCurrency; delete m_vpDatePosted; delete m_vpDateEntered;
+}
+
+GncObject *GncTransaction::startSubEl() {
+ TRY
+ if (pMain->xmldebug) qDebug ("Transaction start subel m_state %d", m_state);
+ GncObject *next = 0;
+ switch (m_state) {
+ case CURRCY: next = new GncCmdtySpec; break;
+ case POSTED:
+ case ENTERED:
+ next = new GncDate; break;
+ case SPLIT:
+ if (isTemplate()) {
+ next = new GncTemplateSplit;
+ } else {
+ next = new GncSplit;
+ }
+ break;
+ case KVP: next = new GncKvp; break;
+ default: throw new MYMONEYEXCEPTION ("GncTransaction rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncTransaction::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("Transaction end subel");
+ switch (m_state) {
+ case CURRCY: m_vpCurrency = static_cast<GncCmdtySpec *>(subObj); break;
+ case POSTED: m_vpDatePosted = static_cast<GncDate *>(subObj); break;
+ case ENTERED: m_vpDateEntered = static_cast<GncDate *>(subObj); break;
+ case SPLIT: m_splitList.append (subObj); break;
+ case KVP: m_kvpList.append (subObj);
+ }
+ return ;
+}
+
+void GncTransaction::terminate() {
+ TRY
+ if (isTemplate()) {
+ pMain->saveTemplateTransaction(this);
+ } else {
+ pMain->convertTransaction (this);
+ }
+ return ;
+ PASS
+}
+//************* GncSplit********************************************
+GncSplit::GncSplit () {
+ m_subElementListCount = END_Split_SELS;
+ static const QString subEls[] = {"split:reconcile-date"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_Split_DELS;
+ static const QString dataEls[] = {"split:id", "split:memo", "split:reconciled-state", "split:value",
+ "split:quantity", "split:account"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, SUPPRESS, ASIS, MONEY1, MONEY1, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_vpDateReconciled = NULL;
+}
+
+GncSplit::~GncSplit () {
+ delete m_vpDateReconciled;
+}
+
+GncObject *GncSplit::startSubEl () {
+ TRY
+ GncObject *next = 0;
+ switch (m_state) {
+ case RECDATE: next = new GncDate; break;
+ default: throw new MYMONEYEXCEPTION ("GncTemplateSplit rcvd invalid m_state ");
+ }
+ return (next);
+ PASS
+}
+
+void GncSplit::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("Split end subel");
+ switch (m_state) {
+ case RECDATE: m_vpDateReconciled = static_cast<GncDate *>(subObj); break;
+ }
+ return ;
+}
+//************* GncTemplateSplit********************************************
+GncTemplateSplit::GncTemplateSplit () {
+ m_subElementListCount = END_TemplateSplit_SELS;
+ static const QString subEls[] = {"slot"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_TemplateSplit_DELS;
+ static const QString dataEls[] = {"split:id", "split:memo", "split:reconciled-state", "split:value",
+ "split:quantity", "split:account"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, SUPPRESS, ASIS, MONEY1, MONEY1, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_kvpList.setAutoDelete (true);
+}
+
+GncTemplateSplit::~GncTemplateSplit () {}
+
+GncObject *GncTemplateSplit::startSubEl() {
+ if (pMain->xmldebug) qDebug ("TemplateSplit start subel m_state %d", m_state);
+ TRY
+ GncObject *next = 0;
+ switch (m_state) {
+ case KVP: next = new GncKvp; break;
+ default: throw new MYMONEYEXCEPTION ("GncTemplateSplit rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncTemplateSplit::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("TemplateSplit end subel");
+ m_kvpList.append (subObj);
+ m_dataPtr = 0;
+ return ;
+}
+//************* GncSchedule********************************************
+GncSchedule::GncSchedule () {
+ m_subElementListCount = END_Schedule_SELS;
+ static const QString subEls[] = {"sx:start", "sx:last", "sx:end", "gnc:freqspec", "gnc:recurrence","sx:deferredInstance"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_Schedule_DELS;
+ static const QString dataEls[] = {"sx:name", "sx:enabled", "sx:autoCreate", "sx:autoCreateNotify",
+ "sx:autoCreateDays", "sx:advanceCreateDays", "sx:advanceRemindDays",
+ "sx:instanceCount", "sx:num-occur",
+ "sx:rem-occur", "sx:templ-acct"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {NXTSCHD, ASIS, ASIS, ASIS, ASIS, ASIS, ASIS, ASIS, ASIS, ASIS, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_vpStartDate = m_vpLastDate = m_vpEndDate = NULL;
+ m_vpFreqSpec = NULL;
+ m_vpRecurrence.clear();
+ m_vpRecurrence.setAutoDelete(true);
+ m_vpSchedDef = NULL;
+}
+
+GncSchedule::~GncSchedule () {
+ delete m_vpStartDate; delete m_vpLastDate; delete m_vpEndDate; delete m_vpFreqSpec; delete m_vpSchedDef;
+}
+
+GncObject *GncSchedule::startSubEl() {
+ if (pMain->xmldebug) qDebug ("Schedule start subel m_state %d", m_state);
+ TRY
+ GncObject *next = 0;
+ switch (m_state) {
+ case STARTDATE:
+ case LASTDATE:
+ case ENDDATE: next = new GncDate; break;
+ case FREQ: next = new GncFreqSpec; break;
+ case RECURRENCE: next = new GncRecurrence; break;
+ case DEFINST: next = new GncSchedDef; break;
+ default: throw new MYMONEYEXCEPTION ("GncSchedule rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncSchedule::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("Schedule end subel");
+ switch (m_state) {
+ case STARTDATE: m_vpStartDate = static_cast<GncDate *>(subObj); break;
+ case LASTDATE: m_vpLastDate = static_cast<GncDate *>(subObj); break;
+ case ENDDATE: m_vpEndDate = static_cast<GncDate *>(subObj); break;
+ case FREQ: m_vpFreqSpec = static_cast<GncFreqSpec *>(subObj); break;
+ case RECURRENCE: m_vpRecurrence.append(static_cast<GncRecurrence *>(subObj)); break;
+ case DEFINST: m_vpSchedDef = static_cast<GncSchedDef *>(subObj); break;
+ }
+ return ;
+}
+
+void GncSchedule::terminate() {
+ TRY
+ pMain->convertSchedule (this);
+ return ;
+ PASS
+}
+//************* GncFreqSpec********************************************
+GncFreqSpec::GncFreqSpec () {
+ m_subElementListCount = END_FreqSpec_SELS;
+ static const QString subEls[] = {"gnc:freqspec"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_FreqSpec_DELS;
+ static const QString dataEls[] = {"fs:ui_type", "fs:monthly", "fs:daily", "fs:weekly", "fs:interval",
+ "fs:offset", "fs:day"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, ASIS, ASIS, ASIS, ASIS, ASIS, ASIS };
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+ m_fsList.setAutoDelete (true);
+}
+
+GncFreqSpec::~GncFreqSpec () {}
+
+GncObject *GncFreqSpec::startSubEl() {
+ TRY
+ if (pMain->xmldebug) qDebug ("FreqSpec start subel m_state %d", m_state);
+
+ GncObject *next = 0;
+ switch (m_state) {
+ case COMPO: next = new GncFreqSpec; break;
+ default: throw new MYMONEYEXCEPTION ("GncFreqSpec rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncFreqSpec::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("FreqSpec end subel");
+ switch (m_state) {
+ case COMPO: m_fsList.append (subObj); break;
+ }
+ m_dataPtr = 0;
+ return ;
+}
+
+void GncFreqSpec::terminate() {
+ pMain->convertFreqSpec (this);
+ return ;
+}
+//************* GncRecurrence********************************************
+GncRecurrence::GncRecurrence () {
+ m_subElementListCount = END_Recurrence_SELS;
+ static const QString subEls[] = {"recurrence:start"};
+ m_subElementList = subEls;
+ m_dataElementListCount = END_Recurrence_DELS;
+ static const QString dataEls[] = {"recurrence:mult", "recurrence:period_type"};
+ m_dataElementList = dataEls;
+ static const unsigned int anonClasses[] = {ASIS, ASIS};
+ m_anonClassList = anonClasses;
+ for (uint i = 0; i < m_dataElementListCount; i++) m_v.append (new QString (""));
+}
+
+GncRecurrence::~GncRecurrence () {
+ delete m_vpStartDate;
+}
+
+GncObject *GncRecurrence::startSubEl() {
+ TRY
+ if (pMain->xmldebug) qDebug ("Recurrence start subel m_state %d", m_state);
+
+ GncObject *next = 0;
+ switch (m_state) {
+ case STARTDATE: next = new GncDate; break;
+ default: throw new MYMONEYEXCEPTION ("GncRecurrence rcvd invalid m_state");
+ }
+ return (next);
+ PASS
+}
+
+void GncRecurrence::endSubEl(GncObject *subObj) {
+ if (pMain->xmldebug) qDebug ("Recurrence end subel");
+ switch (m_state) {
+ case STARTDATE: m_vpStartDate = static_cast<GncDate *>(subObj); break;
+ }
+ m_dataPtr = 0;
+ return ;
+}
+
+void GncRecurrence::terminate() {
+ pMain->convertRecurrence (this);
+ return ;
+}
+
+QString GncRecurrence::getFrequency() const {
+ // This function converts a gnucash 2.2 recurrence specification into it's previous equivalent
+ // This will all need re-writing when MTE finishes the schedule re-write
+ if (periodType() == "once") return("once");
+ if ((periodType() == "day") and (mult() == "1")) return("daily");
+ if (periodType() == "week") {
+ if (mult() == "1") return ("weekly");
+ if (mult() == "2") return ("bi_weekly");
+ if (mult() == "4") return ("four-weekly");
+ }
+ if (periodType() == "month") {
+ if (mult() == "1") return ("monthly");
+ if (mult() == "2") return ("two-monthly");
+ if (mult() == "3") return ("quarterly");
+ if (mult() == "4") return ("tri_annually");
+ if (mult() == "6") return ("semi_yearly");
+ if (mult() == "12") return ("yearly");
+ if (mult() == "24") return ("two-yearly");
+ }
+ return ("unknown");
+}
+
+//************* GncSchedDef********************************************
+GncSchedDef::GncSchedDef () {
+ // process ing for this sub-object is undefined at the present time
+ m_subElementListCount = 0;
+ m_dataElementListCount = 0;
+}
+
+GncSchedDef::~GncSchedDef () {}
+
+/************************************************************************************************
+ XML Reader
+************************************************************************************************/
+void XmlReader::processFile (QIODevice* pDevice) {
+ m_source = new QXmlInputSource (pDevice); // set up the Qt XML reader
+ m_reader = new QXmlSimpleReader;
+ m_reader->setContentHandler (this);
+ // go read the file
+ if (!m_reader->parse (m_source)) {
+ throw new MYMONEYEXCEPTION (i18n("Input file cannot be parsed; may be corrupt\n%s", errorString().latin1()));
+ }
+ delete m_reader;
+ delete m_source;
+ return ;
+}
+
+// XML handling routines
+bool XmlReader::startDocument() {
+ m_os.setAutoDelete (true);
+ m_co = new GncFile; // create initial object, push to stack , pass it the 'main' pointer
+ m_os.push (m_co);
+ m_co->setPm (pMain);
+ m_headerFound = false;
+#ifdef _GNCFILEANON
+ pMain->oStream << "<?xml version=\"1.0\"?>";
+ lastType = -1;
+ indentCount = 0;
+#endif // _GNCFILEANON
+ return (true);
+}
+
+bool XmlReader::startElement (const QString&, const QString&, const QString& elName ,
+ const QXmlAttributes& elAttrs) {
+ try {
+ if (pMain->gncdebug) qDebug ("XML start - %s", elName.latin1());
+#ifdef _GNCFILEANON
+ int i;
+ QString spaces;
+ // anonymizer - write data
+ if (elName == "gnc:book" || elName == "gnc:count-data" || elName == "book:id") lastType = -1;
+ pMain->oStream << endl;
+ switch (lastType) {
+ case 0:
+ indentCount += 2;
+ // tricky fall through here
+
+ case 2:
+ spaces.fill (' ', indentCount);
+ pMain->oStream << spaces.latin1();
+ break;
+ }
+ pMain->oStream << '<' << elName;
+ for (i = 0; i < elAttrs.count(); i++) {
+ pMain->oStream << ' ' << elAttrs.qName(i) << '=' << '"' << elAttrs.value(i) << '"';
+ }
+ pMain->oStream << '>';
+ lastType = 0;
+#else
+ if ((!m_headerFound) && (elName != "gnc-v2"))
+ throw new MYMONEYEXCEPTION (i18n("Invalid header for file. Should be 'gnc-v2'"));
+ m_headerFound = true;
+#endif // _GNCFILEANON
+ m_co->checkVersion (elName, elAttrs, pMain->m_versionList);
+ // check if this is a sub object element; if so, push stack and initialize
+ GncObject *temp = m_co->isSubElement (elName, elAttrs);
+ if (temp != 0) {
+ m_os.push (temp);
+ m_co = m_os.top();
+ m_co->setVersion(elAttrs.value("version"));
+ m_co->setPm (pMain); // pass the 'main' pointer to the sub object
+ // return true; // removed, as we hit a return true anyway
+ }
+#if 0
+ // check for a data element
+ if (m_co->isDataElement (elName, elAttrs))
+ return (true);
+#endif
+ else {
+ // reduced the above to
+ m_co->isDataElement(elName, elAttrs);
+ }
+ } catch (MyMoneyException *e) {
+#ifndef _GNCFILEANON
+ // we can't pass on exceptions here coz the XML reader won't catch them and we just abort
+ KMessageBox::error(0, i18n("Import failed:\n\n%1").arg(e->what()), PACKAGE);
+ qFatal ("%s", e->what().latin1());
+#else
+ qFatal ("%s", e->latin1());
+#endif // _GNCFILEANON
+ }
+ return true; // to keep compiler happy
+}
+
+bool XmlReader::endElement( const QString&, const QString&, const QString&elName ) {
+ try {
+ if (pMain->xmldebug) qDebug ("XML end - %s", elName.latin1());
+#ifdef _GNCFILEANON
+ QString spaces;
+ switch (lastType) {
+ case 2:
+ indentCount -= 2; spaces.fill (' ', indentCount); pMain->oStream << endl << spaces.latin1(); break;
+ }
+ pMain->oStream << "</" << elName << '>' ;
+ lastType = 2;
+#endif // _GNCFILEANON
+ m_co->resetDataPtr(); // so we don't get extraneous data loaded into the variables
+ if (elName == m_co->getElName()) { // check if this is the end of the current object
+ if (pMain->gncdebug) m_co->debugDump(); // dump the object data (temp)
+ // call the terminate routine, pop the stack, and advise the parent that it's done
+ m_co->terminate();
+ GncObject *temp = m_co;
+ m_os.pop();
+ m_co = m_os.top();
+ m_co->endSubEl (temp);
+ }
+ return (true);
+ } catch (MyMoneyException *e) {
+#ifndef _GNCFILEANON
+ // we can't pass on exceptions here coz the XML reader won't catch them and we just abort
+ KMessageBox::error(0, i18n("Import failed:\n\n%1").arg(e->what()), PACKAGE);
+ qFatal ("%s", e->what().latin1());
+#else
+ qFatal ("%s", e->latin1());
+#endif // _GNCFILEANON
+ }
+ return (true); // to keep compiler happy
+}
+
+bool XmlReader::characters (const QString &data) {
+ if (pMain->xmldebug) qDebug ("XML Data received - %d bytes", data.length());
+ QString pData = data.stripWhiteSpace(); // data may contain line feeds and indentation spaces
+ if (!pData.isEmpty()) {
+ if (pMain->developerDebug) qDebug ("XML Data - %s", pData.latin1());
+ m_co->storeData (pData); //go store it
+#ifdef _GNCFILEANON
+ QString anonData = m_co->getData ();
+ if (anonData.isEmpty()) anonData = pData;
+ // there must be a Qt standard way of doing the following but I can't ... find it
+ anonData.replace ('<', "&lt;");
+ anonData.replace ('>', "&gt;");
+ anonData.replace ('&', "&amp;");
+ pMain->oStream << anonData; // write original data
+ lastType = 1;
+#endif // _GNCFILEANON
+ }
+ return (true);
+}
+
+bool XmlReader::endDocument() {
+#ifdef _GNCFILEANON
+ pMain->oStream << endl << endl;
+ pMain->oStream << "<!-- Local variables: -->" << endl;
+ pMain->oStream << "<!-- mode: xml -->" << endl;
+ pMain->oStream << "<!-- End: -->" << endl;
+#endif // _GNCFILEANON
+ return (true);
+}
+
+/*******************************************************************************************
+ Main class for this module
+ Controls overall operation of the importer
+********************************************************************************************/
+//***************** Constructor ***********************
+MyMoneyGncReader::MyMoneyGncReader() {
+#ifndef _GNCFILEANON
+ m_storage = NULL;
+ m_messageList.setAutoDelete (true);
+ m_templateList.setAutoDelete (true);
+#endif // _GNCFILEANON
+// to hold gnucash count data (only used for progress bar)
+ m_gncCommodityCount = m_gncAccountCount = m_gncTransactionCount = m_gncScheduleCount = 0;
+ m_smallBusinessFound = m_budgetsFound = m_lotsFound = false;
+ m_commodityCount = m_priceCount = m_accountCount = m_transactionCount = m_templateCount = m_scheduleCount = 0;
+ m_decoder = 0;
+ // build a list of valid versions
+ static const QString versionList[] = {"gnc:book 2.0.0", "gnc:commodity 2.0.0", "gnc:pricedb 1",
+ "gnc:account 2.0.0", "gnc:transaction 2.0.0", "gnc:schedxaction 1.0.0",
+ "gnc:schedxaction 2.0.0", // for gnucash 2.2 onward
+ "gnc:freqspec 1.0.0", "zzz" // zzz = stopper
+ };
+ unsigned int i;
+ for (i = 0; versionList[i] != "zzz"; ++i)
+ m_versionList[versionList[i].section (' ', 0, 0)].append(versionList[i].section (' ', 1, 1));
+}
+
+//***************** Destructor *************************
+MyMoneyGncReader::~MyMoneyGncReader() {}
+
+//**************************** Main Entry Point ************************************
+#ifndef _GNCFILEANON
+void MyMoneyGncReader::readFile(QIODevice* pDevice, IMyMoneySerialize* storage) {
+
+ Q_CHECK_PTR (pDevice);
+ Q_CHECK_PTR (storage);
+
+ m_storage = dynamic_cast<IMyMoneyStorage *>(storage);
+ qDebug ("Entering gnucash importer");
+ setOptions ();
+ // get a file anonymization factor from the user
+ if (bAnonymize) setFileHideFactor ();
+ //m_defaultPayee = createPayee (i18n("Unknown payee"));
+
+ MyMoneyFileTransaction ft;
+ m_xr = new XmlReader (this);
+ try {
+ m_xr->processFile (pDevice);
+ terminate (); // do all the wind-up things
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ KMessageBox::error(0, i18n("Import failed:\n\n%1").arg(e->what()), PACKAGE);
+ qFatal ("%s", e->what().latin1());
+ } // end catch
+ signalProgress (0, 1, i18n("Import complete")); // switch off progress bar
+ delete m_xr;
+ qDebug ("Exiting gnucash importer");
+ return ;
+}
+#else
+// Control code for the file anonymizer
+void MyMoneyGncReader::readFile(QString in, QString out) {
+ QFile pDevice (in);
+ if (!pDevice.open (IO_ReadOnly)) qFatal ("Can't open input file");
+ QFile outFile (out);
+ if (!outFile.open (IO_WriteOnly)) qFatal ("Can't open output file");
+ oStream.setDevice (&outFile);
+ bAnonymize = true;
+ // get a file anonymization factor from the user
+ setFileHideFactor ();
+ m_xr = new XmlReader (this);
+ try {
+ m_xr->processFile (&pDevice);
+ } catch (MyMoneyException *e) {
+ qFatal ("%s", e->latin1());
+ } // end catch
+ delete m_xr;
+ pDevice.close();
+ outFile.close();
+ return ;
+}
+
+#include <qapplication.h>
+int main (int argc, char ** argv) {
+ QApplication a (argc, argv);
+ MyMoneyGncReader m;
+ QString inFile, outFile;
+
+ if (argc > 0) inFile = a.argv()[1];
+ if (argc > 1) outFile = a.argv()[2];
+ if (inFile.isEmpty()) {
+ inFile = QFileDialog::getOpenFileName("",
+ "Gnucash files(*.nc *)",
+ 0);
+ }
+ if (inFile.isEmpty()) qFatal ("Input file required");
+ if (outFile.isEmpty()) outFile = inFile + ".anon";
+ m.readFile (inFile, outFile);
+ exit (0);
+}
+#endif // _GNCFILEANON
+
+void MyMoneyGncReader::setFileHideFactor () {
+#define MINFILEHIDEF 0.01
+#define MAXFILEHIDEF 99.99
+ srand (QTime::currentTime().second()); // seed randomizer for anonymize
+ m_fileHideFactor = 0.0;
+ while (m_fileHideFactor == 0.0) {
+ m_fileHideFactor = QInputDialog::getDouble (
+ i18n ("Disguise your wealth"),
+ i18n ("Each monetary value on your file will be multiplied by a random number between 0.01 and 1.99\n"
+ "with a different value used for each transaction. In addition, to further disguise the true\n"
+ "values, you may enter a number between %1 and %2 which will be applied to all values.\n"
+ "These numbers will not be stored in the file.").arg(MINFILEHIDEF).arg(MAXFILEHIDEF),
+ (1.0 + (int)(1000.0 * rand() / (RAND_MAX + 1.0))) / 100.0,
+ MINFILEHIDEF, MAXFILEHIDEF, 2);
+ }
+}
+#ifndef _GNCFILEANON
+
+//********************************* convertCommodity *******************************************
+void MyMoneyGncReader::convertCommodity (const GncCommodity *gcm) {
+ Q_CHECK_PTR (gcm);
+ MyMoneySecurity equ;
+ if (m_commodityCount == 0) signalProgress (0, m_gncCommodityCount, i18n("Loading commodities..."));
+ if (!gcm->isCurrency()) { // currencies should not be present here but...
+ equ.setName (gcm->name());
+ equ.setTradingSymbol (gcm->id());
+ equ.setTradingMarket (gcm->space()); // the 'space' may be market or quote source, dep on what the user did
+ // don't set the source here since he may not want quotes
+ //equ.setValue ("kmm-online-source", gcm->space()); // we don't know, so use it as both
+ equ.setTradingCurrency (""); // not available here, will set from pricedb or transaction
+ equ.setSecurityType (MyMoneySecurity::SECURITY_STOCK); // default to it being a stock
+ //tell the storage objects we have a new equity object.
+ equ.setSmallestAccountFraction(gcm->fraction().toInt());
+ m_storage->addSecurity(equ);
+
+ //assign the gnucash id as the key into the map to find our id
+ if (gncdebug) qDebug ("mapping, key = %s, id = %s", gcm->id().latin1(), equ.id().data());
+ m_mapEquities[gcm->id().utf8()] = equ.id();
+ }
+ signalProgress (++m_commodityCount, 0);
+ return ;
+}
+
+//******************************* convertPrice ************************************************
+void MyMoneyGncReader::convertPrice (const GncPrice *gpr) {
+ Q_CHECK_PTR (gpr);
+ // add this to our price history
+ if (m_priceCount == 0) signalProgress (0, 1, i18n("Loading prices..."));
+ MyMoneyMoney rate = convBadValue (gpr->value());
+ if (gpr->commodity()->isCurrency()) {
+ MyMoneyPrice exchangeRate (gpr->commodity()->id().utf8(), gpr->currency()->id().utf8(),
+ gpr->priceDate(), rate, i18n("Imported History"));
+ m_storage->addPrice (exchangeRate);
+ } else {
+ MyMoneySecurity e = m_storage->security(m_mapEquities[gpr->commodity()->id().utf8()]);
+ if (gncdebug) qDebug ("Searching map, key = %s, found id = %s",
+ gpr->commodity()->id().latin1(), e.id().data());
+ e.setTradingCurrency (gpr->currency()->id().utf8());
+ MyMoneyPrice stockPrice(e.id(), gpr->currency()->id().utf8(), gpr->priceDate(), rate, i18n("Imported History"));
+ m_storage->addPrice (stockPrice);
+ m_storage->modifySecurity(e);
+ }
+ signalProgress (++m_priceCount, 0);
+ return ;
+}
+
+//*********************************convertAccount ****************************************
+void MyMoneyGncReader::convertAccount (const GncAccount* gac) {
+ Q_CHECK_PTR (gac);
+ TRY
+ // we don't care about the GNC root account
+ if("ROOT" == gac->type()) {
+ m_rootId = gac->id().utf8();
+ return;
+ }
+
+ MyMoneyAccount acc;
+ if (m_accountCount == 0) signalProgress (0, m_gncAccountCount, i18n("Loading accounts..."));
+ acc.setName(gac->name());
+
+ acc.setDescription(gac->desc());
+
+ QDate currentDate = QDate::currentDate();
+ acc.setOpeningDate(currentDate);
+ acc.setLastModified(currentDate);
+ acc.setLastReconciliationDate(currentDate);
+ if (gac->commodity()->isCurrency()) {
+ acc.setCurrencyId (gac->commodity()->id().utf8());
+ m_currencyCount[gac->commodity()->id()]++;
+ }
+
+ acc.setParentAccountId (gac->parent().utf8());
+ // now determine the account type and its parent id
+ /* This list taken from
+# Feb 2006: A RELAX NG Compact schema for gnucash "v2" XML files.
+# Copyright (C) 2006 Joshua Sled <jsled@asynchronous.org>
+"NO_TYPE" "BANK" "CASH" "CREDIT" "ASSET" "LIABILITY" "STOCK" "MUTUAL" "CURRENCY"
+"INCOME" "EXPENSE" "EQUITY" "RECEIVABLE" "PAYABLE" "CHECKING" "SAVINGS" "MONEYMRKT" "CREDITLINE"
+ Some don't seem to be used in practice. Not sure what CREDITLINE s/be converted as.
+ */
+ if ("BANK" == gac->type() || "CHECKING" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Checkings);
+ } else if ("SAVINGS" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Savings);
+ } else if ("ASSET" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Asset);
+ } else if ("CASH" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Cash);
+ } else if ("CURRENCY" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Cash);
+ } else if ("STOCK" == gac->type() || "MUTUAL" == gac->type() ) {
+ // gnucash allows a 'broker' account to be denominated as type STOCK, but with
+ // a currency balance. We do not need to create a stock account for this
+ // actually, the latest version of gnc (1.8.8) doesn't seem to allow you to do
+ // this any more, though I do have one in my own account...
+ if (gac->commodity()->isCurrency()) {
+ acc.setAccountType(MyMoneyAccount::Investment);
+ } else {
+ acc.setAccountType(MyMoneyAccount::Stock);
+ }
+ } else if ("EQUITY" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Equity);
+ } else if ("LIABILITY" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Liability);
+ } else if ("CREDIT" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::CreditCard);
+ } else if ("INCOME" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Income);
+ } else if ("EXPENSE" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Expense);
+ } else if ("RECEIVABLE" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Asset);
+ } else if ("PAYABLE" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::Liability);
+ } else if ("MONEYMRKT" == gac->type()) {
+ acc.setAccountType(MyMoneyAccount::MoneyMarket);
+ } else { // we have here an account type we can't currently handle
+ QString em =
+ i18n("Current importer does not recognize GnuCash account type %1").arg(gac->type());
+ throw new MYMONEYEXCEPTION (em);
+ }
+ // if no parent account is present, assign to one of our standard accounts
+ if ((acc.parentAccountId().isEmpty()) || (acc.parentAccountId() == m_rootId)) {
+ switch (acc.accountGroup()) {
+ case MyMoneyAccount::Asset: acc.setParentAccountId (m_storage->asset().id()); break;
+ case MyMoneyAccount::Liability: acc.setParentAccountId (m_storage->liability().id()); break;
+ case MyMoneyAccount::Income: acc.setParentAccountId (m_storage->income().id()); break;
+ case MyMoneyAccount::Expense: acc.setParentAccountId (m_storage->expense().id()); break;
+ case MyMoneyAccount::Equity: acc.setParentAccountId (m_storage->equity().id()); break;
+ default: break; // not necessary but avoids compiler warnings
+ }
+ }
+
+ // extra processing for a stock account
+ if (acc.accountType() == MyMoneyAccount::Stock) {
+ // save the id for later linking to investment account
+ m_stockList.append (gac->id());
+ // set the equity type
+ MyMoneySecurity e = m_storage->security (m_mapEquities[gac->commodity()->id().utf8()]);
+ if (gncdebug) qDebug ("Acct equity search, key = %s, found id = %s",
+ gac->commodity()->id().latin1(), e.id().data());
+ acc.setCurrencyId (e.id()); // actually, the security id
+ if ("MUTUAL" == gac->type()) {
+ e.setSecurityType (MyMoneySecurity::SECURITY_MUTUALFUND);
+ if (gncdebug) qDebug ("Setting %s to mutual", e.name().latin1());
+ m_storage->modifySecurity (e);
+ }
+ // See if he wants online quotes for this account
+ // NB: In gnc, this selection is per account, in KMM, per security
+ // This is unlikely to cause problems in practice. If it does,
+ // we probably need to introduce a 'pricing basis' in the account class
+ QPtrListIterator<GncObject> kvpi (gac->m_kvpList);
+ GncKvp *k;
+ while ((k = static_cast<GncKvp *>(kvpi.current())) != 0) {
+ if (k->key().contains("price-source") && k->type() == "string") {
+ getPriceSource (e, k->value());
+ break;
+ } else {
+ ++kvpi;
+ }
+ }
+ }
+
+ // check for tax-related status
+ QPtrListIterator<GncObject> kvpi (gac->m_kvpList);
+ GncKvp *k;
+ while ((k = static_cast<GncKvp *>(kvpi.current())) != 0) {
+ if (k->key().contains("tax-related") && k->type() == "integer" && k->value() == "1") {
+ acc.setValue ("Tax", "Yes");
+ break;
+ } else {
+ ++kvpi;
+ }
+ }
+
+ // all the details from the file about the account should be known by now.
+ // calling addAccount will automatically fill in the account ID.
+ m_storage->addAccount(acc);
+ m_mapIds[gac->id().utf8()] = acc.id(); // to link gnucash id to ours for tx posting
+
+ if (gncdebug) qDebug("Gnucash account %s has id of %s, type of %s, parent is %s",
+ gac->id().latin1(), acc.id().data(),
+ KMyMoneyUtils::accountTypeToString(acc.accountType()).latin1(), acc.parentAccountId().data());
+
+ signalProgress (++m_accountCount, 0);
+ return ;
+ PASS
+}
+
+//********************************************** convertTransaction *****************************
+void MyMoneyGncReader::convertTransaction (const GncTransaction *gtx) {
+ Q_CHECK_PTR (gtx);
+ MyMoneyTransaction tx;
+ MyMoneySplit split;
+ unsigned int i;
+
+ if (m_transactionCount == 0) signalProgress (0, m_gncTransactionCount, i18n("Loading transactions..."));
+ // initialize class variables related to transactions
+ m_txCommodity = "";
+ m_txPayeeId = "";
+ m_potentialTransfer = true;
+ m_splitList.clear(); m_liabilitySplitList.clear(); m_otherSplitList.clear();
+ // payee, dates, commodity
+ if (!gtx->desc().isEmpty()) m_txPayeeId = createPayee (gtx->desc());
+ tx.setEntryDate (gtx->dateEntered());
+ tx.setPostDate (gtx->datePosted());
+ m_txDatePosted = tx.postDate(); // save for use in splits
+ m_txChequeNo = gtx->no(); // ditto
+ tx.setCommodity (gtx->currency().utf8());
+ m_txCommodity = tx.commodity(); // save in storage, maybe needed for Orphan accounts
+ // process splits
+ for (i = 0; i < gtx->splitCount(); i++) {
+ convertSplit (static_cast<const GncSplit *>(gtx->getSplit (i)));
+ }
+ // handle the odd case of just one split, which gnc allows,
+ // by just duplicating the split
+ // of course, we should change the sign but this case has only ever been seen
+ // when the balance is zero, and can cause kmm to crash, so...
+ if (gtx->splitCount() == 1) {
+ convertSplit (static_cast<const GncSplit *>(gtx->getSplit (0)));
+ }
+ m_splitList += m_liabilitySplitList += m_otherSplitList;
+ // the splits are in order in splitList. Link them to the tx. also, determine the
+ // action type, and fill in some fields which gnc holds at transaction level
+ // first off, is it a transfer (can only have 2 splits?)
+ // also, a tx with just 2 splits is shown by GnuCash as non-split
+ bool nonSplitTx = true;
+ if (m_splitList.count() != 2) {
+ m_potentialTransfer = false;
+ nonSplitTx = false;
+ }
+ for (i = 0; i < gtx->kvpCount(); i++ ) {
+ const GncKvp *slot = gtx->getKvp(i);
+ if (slot->key() == "notes") tx.setMemo(slot->value());
+ }
+ QValueList<MyMoneySplit>::iterator it = m_splitList.begin();
+ while (!m_splitList.isEmpty()) {
+ split = *it;
+ // at this point, if m_potentialTransfer is still true, it is actually one!
+ if (m_potentialTransfer) split.setAction(MyMoneySplit::ActionTransfer);
+ if ((m_useTxNotes) // if use txnotes option is set
+ && (nonSplitTx) // and it's a (GnuCash) non-split transaction
+ && (!tx.memo().isEmpty())) // and tx notes are present
+ split.setMemo(tx.memo()); // use the tx notes as memo
+ tx.addSplit(split);
+ it = m_splitList.remove(it);
+ }
+ // memo - set from split - not any more
+ //tx.setMemo(txMemo);
+ m_storage->addTransaction(tx, true); // all done, add the transaction to storage
+ signalProgress (++m_transactionCount, 0);
+ return ;
+}
+//******************************************convertSplit********************************
+void MyMoneyGncReader::convertSplit (const GncSplit *gsp) {
+ Q_CHECK_PTR (gsp);
+ MyMoneySplit split;
+ MyMoneyAccount splitAccount;
+ // find the kmm account id coresponding to the gnc id
+ QString kmmAccountId;
+ map_accountIds::Iterator id = m_mapIds.find(gsp->acct().utf8());
+ if (id != m_mapIds.end()) {
+ kmmAccountId = id.data();
+ } else { // for the case where the acs not found (which shouldn't happen?), create an account with gnc name
+ kmmAccountId = createOrphanAccount (gsp->acct());
+ }
+ // find the account pointer and save for later
+ splitAccount = m_storage->account (kmmAccountId);
+ // print some data so we can maybe identify this split later
+ // TODO : prints personal data
+ //if (gncdebug) qDebug ("Split data - gncid %s, kmmid %s, memo %s, value %s, recon state %s",
+ // gsp->acct().latin1(), kmmAccountId.data(), gsp->memo().latin1(), gsp->value().latin1(),
+ // gsp->recon().latin1());
+ // payee id
+ split.setPayeeId (m_txPayeeId.utf8());
+ // reconciled state and date
+ switch (gsp->recon().at(0).latin1()) {
+ case 'n':
+ split.setReconcileFlag(MyMoneySplit::NotReconciled); break;
+ case 'c':
+ split.setReconcileFlag(MyMoneySplit::Cleared); break;
+ case 'y':
+ split.setReconcileFlag(MyMoneySplit::Reconciled); break;
+ }
+ split.setReconcileDate(gsp->reconDate());
+ // memo
+ split.setMemo(gsp->memo());
+ // accountId
+ split.setAccountId (kmmAccountId);
+ // cheque no
+ split.setNumber (m_txChequeNo);
+ // value and quantity
+ MyMoneyMoney splitValue (convBadValue (gsp->value()));
+ if (gsp->value() == "-1/0") { // treat gnc invalid value as zero
+ // it's not quite a consistency check, but easier to treat it as such
+ postMessage ("CC", 4, splitAccount.name().latin1(), m_txDatePosted.toString(Qt::ISODate).latin1());
+ }
+ MyMoneyMoney splitQuantity(convBadValue(gsp->qty()));
+ split.setValue (splitValue);
+ // if split currency = tx currency, set shares = value (14/10/05)
+ if (splitAccount.currencyId() == m_txCommodity) {
+ split.setShares (splitValue);
+ } else {
+ split.setShares (splitQuantity);
+ }
+
+ // in kmm, the first split is important. in this routine we will
+ // save the splits in our split list with the priority:
+ // 1. assets
+ // 2. liabilities
+ // 3. others (categories)
+ // but keeping each in same order as gnucash
+ MyMoneySecurity e;
+ MyMoneyMoney price, newPrice(0);
+
+ switch (splitAccount.accountGroup()) {
+ case MyMoneyAccount::Asset:
+ if (splitAccount.accountType() == MyMoneyAccount::Stock) {
+ split.value() == MyMoneyMoney(0) ?
+ split.setAction (MyMoneySplit::ActionAddShares) : // free shares?
+ split.setAction (MyMoneySplit::ActionBuyShares);
+ m_potentialTransfer = false; // ?
+ // add a price history entry
+ e = m_storage->security(splitAccount.currencyId());
+ // newPrice fix supplied by Phil Longstaff
+ price = split.value() / split.shares();
+#define NEW_DENOM 10000
+ if (!split.shares().isZero()) // patch to fix divide by zero?
+ newPrice = MyMoneyMoney ( price.toDouble(), (signed64)NEW_DENOM );
+ if (!newPrice.isZero()) {
+ TRY
+ // we can't use m_storage->security coz security list is not built yet
+ m_storage->currency(m_txCommodity); // will throw exception if not currency
+ e.setTradingCurrency (m_txCommodity);
+ if (gncdebug) qDebug ("added price for %s, %s date %s",
+ e.name().latin1(), newPrice.toString().latin1(),
+ m_txDatePosted.toString(Qt::ISODate).latin1());
+ m_storage->modifySecurity(e);
+ MyMoneyPrice dealPrice (e.id(), m_txCommodity, m_txDatePosted, newPrice, i18n("Imported Transaction"));
+ m_storage->addPrice (dealPrice);
+ CATCH // stock transfer; treat like free shares?
+ split.setAction (MyMoneySplit::ActionAddShares);
+ delete e;
+ }
+ }
+ } else { // not stock
+ if (split.value().isNegative()) {
+ bool isNumeric = false;
+ if (!split.number().isEmpty()) {
+ split.number().toLong(&isNumeric); // No QString.isNumeric()??
+ }
+ if (isNumeric) {
+ split.setAction (MyMoneySplit::ActionCheck);
+ } else {
+ split.setAction (MyMoneySplit::ActionWithdrawal);
+ }
+ } else {
+ split.setAction (MyMoneySplit::ActionDeposit);
+ }
+ }
+ m_splitList.append(split);
+ break;
+ case MyMoneyAccount::Liability:
+ split.value().isNegative() ?
+ split.setAction (MyMoneySplit::ActionWithdrawal) :
+ split.setAction (MyMoneySplit::ActionDeposit);
+ m_liabilitySplitList.append(split);
+ break;
+ default:
+ m_potentialTransfer = false;
+ m_otherSplitList.append (split);
+ }
+ // backdate the account opening date if necessary
+ if (m_txDatePosted < splitAccount.openingDate()) {
+ splitAccount.setOpeningDate(m_txDatePosted);
+ m_storage->modifyAccount(splitAccount);
+ }
+ return ;
+}
+//********************************* convertTemplateTransaction **********************************************
+MyMoneyTransaction MyMoneyGncReader::convertTemplateTransaction (const QString& schedName, const GncTransaction *gtx) {
+
+ Q_CHECK_PTR (gtx);
+ MyMoneyTransaction tx;
+ MyMoneySplit split;
+ unsigned int i;
+ if (m_templateCount == 0) signalProgress (0, 1, i18n("Loading templates..."));
+
+ // initialize class variables related to transactions
+ m_txCommodity = "";
+ m_txPayeeId = "";
+ m_potentialTransfer = true;
+ m_splitList.clear(); m_liabilitySplitList.clear(); m_otherSplitList.clear();
+
+ // payee, dates, commodity
+ if (!gtx->desc().isEmpty()) {
+ m_txPayeeId = createPayee (gtx->desc());
+ } else {
+ m_txPayeeId = createPayee (i18n("Unknown payee")); // schedules require a payee tho normal tx's don't. not sure why...
+ }
+ tx.setEntryDate(gtx->dateEntered());
+ tx.setPostDate(gtx->datePosted());
+ m_txDatePosted = tx.postDate();
+ tx.setCommodity (gtx->currency().utf8());
+ m_txCommodity = tx.commodity(); // save for possible use in orphan account
+ // process splits
+ for (i = 0; i < gtx->splitCount(); i++) {
+ convertTemplateSplit (schedName, static_cast<const GncTemplateSplit *>(gtx->getSplit (i)));
+ }
+ // determine the action type for the splits and link them to the template tx
+ /*QString negativeActionType, positiveActionType;
+ if (!m_splitList.isEmpty()) { // if there are asset splits
+ positiveActionType = MyMoneySplit::ActionDeposit;
+ negativeActionType = MyMoneySplit::ActionWithdrawal;
+ } else { // if there are liability splits
+ positiveActionType = MyMoneySplit::ActionWithdrawal;
+ negativeActionType = MyMoneySplit::ActionDeposit;
+} */
+ if (!m_otherSplitList.isEmpty()) m_potentialTransfer = false; // tfrs can occur only between assets and asset/liabilities
+ m_splitList += m_liabilitySplitList += m_otherSplitList;
+ // the splits are in order in splitList. Transfer them to the tx
+ // also, determine the action type. first off, is it a transfer (can only have 2 splits?)
+ if (m_splitList.count() != 2) m_potentialTransfer = false;
+ // at this point, if m_potentialTransfer is still true, it is actually one!
+ QString txMemo = "";
+ QValueList<MyMoneySplit>::iterator it = m_splitList.begin();
+ while (!m_splitList.isEmpty()) {
+ split = *it;
+ if (m_potentialTransfer) {
+ split.setAction(MyMoneySplit::ActionTransfer);
+ } else {
+ if (split.value().isNegative()) {
+ //split.setAction (negativeActionType);
+ split.setAction (MyMoneySplit::ActionWithdrawal);
+ } else {
+ //split.setAction (positiveActionType);
+ split.setAction (MyMoneySplit::ActionDeposit);
+ }
+ }
+ split.setNumber(gtx->no()); // set cheque no (or equivalent description)
+ // Arbitrarily, save the first non-null split memo as the memo for the whole tx
+ // I think this is necessary because txs with just 2 splits (the majority)
+ // are not viewable as split transactions in kmm so the split memo is not seen
+ if ((txMemo.isEmpty()) && (!split.memo().isEmpty())) txMemo = split.memo();
+ tx.addSplit(split);
+ it = m_splitList.remove(it);
+ }
+ // memo - set from split
+ tx.setMemo (txMemo);
+ signalProgress (++m_templateCount, 0);
+ return (tx);
+}
+//********************************* convertTemplateSplit ****************************************************
+void MyMoneyGncReader::convertTemplateSplit (const QString& schedName, const GncTemplateSplit *gsp) {
+ Q_CHECK_PTR (gsp);
+ // convertTemplateSplit
+ MyMoneySplit split;
+ MyMoneyAccount splitAccount;
+ unsigned int i, j;
+ bool nonNumericFormula = false;
+
+ // action, value and account will be set from slots
+ // reconcile state, always Not since it hasn't even been posted yet (?)
+ split.setReconcileFlag(MyMoneySplit::NotReconciled);
+ // memo
+ split.setMemo(gsp->memo());
+ // payee id
+ split.setPayeeId (m_txPayeeId.utf8());
+ // read split slots (KVPs)
+ int xactionCount = 0;
+ int validSlotCount = 0;
+ QString gncAccountId;
+ for (i = 0; i < gsp->kvpCount(); i++ ) {
+ const GncKvp *slot = gsp->getKvp(i);
+ if ((slot->key() == "sched-xaction") && (slot->type() == "frame")) {
+ bool bFoundStringCreditFormula = false;
+ bool bFoundStringDebitFormula = false;
+ bool bFoundGuidAccountId = false;
+ QString gncCreditFormula, gncDebitFormula;
+ for (j = 0; j < slot->kvpCount(); j++) {
+ const GncKvp *subSlot = slot->getKvp (j);
+ // again, see comments above. when we have a full specification
+ // of all the options available to us, we can no doubt improve on this
+ if ((subSlot->key() == "credit-formula") && (subSlot->type() == "string")) {
+ gncCreditFormula = subSlot->value();
+ bFoundStringCreditFormula = true;
+ }
+ if ((subSlot->key() == "debit-formula") && (subSlot->type() == "string")) {
+ gncDebitFormula = subSlot->value();
+ bFoundStringDebitFormula = true;
+ }
+ if ((subSlot->key() == "account") && (subSlot->type() == "guid")) {
+ gncAccountId = subSlot->value();
+ bFoundGuidAccountId = true;
+ }
+ }
+ // all data read, now check we have everything
+ if ((bFoundStringCreditFormula) && (bFoundStringDebitFormula) && (bFoundGuidAccountId)) {
+ if (gncdebug) qDebug ("Found valid slot; credit %s, debit %s, acct %s",
+ gncCreditFormula.latin1(), gncDebitFormula.latin1(), gncAccountId.latin1());
+ validSlotCount++;
+ }
+ // validate numeric, work out sign
+ MyMoneyMoney exFormula (0);
+ exFormula.setNegativeMonetarySignPosition (MyMoneyMoney::BeforeQuantityMoney);
+ QString numericTest;
+ char crdr=0 ;
+ if (!gncCreditFormula.isEmpty()) {
+ crdr = 'C';
+ numericTest = gncCreditFormula;
+ } else if (!gncDebitFormula.isEmpty()) {
+ crdr = 'D';
+ numericTest = gncDebitFormula;
+ }
+ kMyMoneyMoneyValidator v (0);
+ int pos; // useless, but required for validator
+ if (v.validate (numericTest, pos) == QValidator::Acceptable) {
+ switch (crdr) {
+ case 'C':
+ exFormula = QString ("-" + numericTest); break;
+ case 'D':
+ exFormula = numericTest;
+ }
+ } else {
+ if (gncdebug) qDebug ("%s is not numeric", numericTest.latin1());
+ nonNumericFormula = true;
+ }
+ split.setValue (exFormula);
+ xactionCount++;
+ } else {
+ postMessage ("SC", 3, schedName.latin1(), slot->key().latin1(), slot->type().latin1());
+ m_suspectSchedule = true;
+ }
+ }
+ // report this as untranslatable tx
+ if (xactionCount > 1) {
+ postMessage ("SC", 4, schedName.latin1());
+ m_suspectSchedule = true;
+ }
+ if (validSlotCount == 0) {
+ postMessage ("SC", 5, schedName.latin1());
+ m_suspectSchedule = true;
+ }
+ if (nonNumericFormula) {
+ postMessage ("SC", 6, schedName.latin1());
+ m_suspectSchedule = true;
+ }
+ // find the kmm account id coresponding to the gnc id
+ QString kmmAccountId;
+ map_accountIds::Iterator id = m_mapIds.find(gncAccountId.utf8());
+ if (id != m_mapIds.end()) {
+ kmmAccountId = id.data();
+ } else { // for the case where the acs not found (which shouldn't happen?), create an account with gnc name
+ kmmAccountId = createOrphanAccount (gncAccountId);
+ }
+ splitAccount = m_storage->account (kmmAccountId);
+ split.setAccountId (kmmAccountId);
+ // if split currency = tx currency, set shares = value (14/10/05)
+ if (splitAccount.currencyId() == m_txCommodity) {
+ split.setShares (split.value());
+ } /* else { //FIXME: scheduled currency or investment tx needs to be investigated
+ split.setShares (splitQuantity);
+ } */
+ // add the split to one of the lists
+ switch (splitAccount.accountGroup()) {
+ case MyMoneyAccount::Asset:
+ m_splitList.append (split); break;
+ case MyMoneyAccount::Liability:
+ m_liabilitySplitList.append (split); break;
+ default:
+ m_otherSplitList.append (split);
+ }
+ // backdate the account opening date if necessary
+ if (m_txDatePosted < splitAccount.openingDate()) {
+ splitAccount.setOpeningDate(m_txDatePosted);
+ m_storage->modifyAccount(splitAccount);
+ }
+ return ;
+}
+//********************************* convertSchedule ********************************************************
+void MyMoneyGncReader::convertSchedule (const GncSchedule *gsc) {
+ TRY
+ Q_CHECK_PTR (gsc);
+ MyMoneySchedule sc;
+ MyMoneyTransaction tx;
+ m_suspectSchedule = false;
+ QDate startDate, nextDate, lastDate, endDate; // for date calculations
+ QDate today = QDate::currentDate();
+ int numOccurs, remOccurs;
+
+ if (m_scheduleCount == 0) signalProgress (0, m_gncScheduleCount, i18n("Loading schedules..."));
+ // schedule name
+ sc.setName(gsc->name());
+ // find the transaction template as stored earlier
+ QPtrListIterator<GncTransaction> itt (m_templateList);
+ GncTransaction *ttx;
+ while ((ttx = itt.current()) != 0) {
+ // the id to match against is the split:account value in the splits
+ if (static_cast<const GncTemplateSplit *>(ttx->getSplit(0))->acct() == gsc->templId()) break;
+ ++itt;
+ }
+ if (itt == 0) {
+ throw new MYMONEYEXCEPTION (i18n("Can't find template transaction for schedule %1").arg(sc.name()));
+ } else {
+ tx = convertTemplateTransaction (sc.name(), *itt);
+ }
+ tx.clearId();
+
+// define the conversion table for intervals
+ struct convIntvl {
+ QString gncType; // the gnucash name
+ unsigned char interval; // for date calculation
+ unsigned int intervalCount;
+ MyMoneySchedule::occurenceE occ; // equivalent occurence code
+ MyMoneySchedule::weekendOptionE wo;
+ };
+/* other intervals supported by gnc according to Josh Sled's schema (see above)
+ "none" "semi_monthly"
+ */
+ /* some of these type names do not appear in gnucash and are difficult to generate for
+ pre 2.2 files.They can be generated for 2.2 however, by GncRecurrence::getFrequency() */
+ static convIntvl vi [] = {
+ {"once", 'o', 1, MyMoneySchedule::OCCUR_ONCE, MyMoneySchedule::MoveNothing },
+ {"daily" , 'd', 1, MyMoneySchedule::OCCUR_DAILY, MyMoneySchedule::MoveNothing },
+ //{"daily_mf", 'd', 1, MyMoneySchedule::OCCUR_DAILY, MyMoneySchedule::MoveMonday }, doesn't work, need new freq in kmm
+ {"30-days" , 'd', 30, MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS, MyMoneySchedule::MoveNothing },
+ {"weekly", 'w', 1, MyMoneySchedule::OCCUR_WEEKLY, MyMoneySchedule::MoveNothing },
+ {"bi_weekly", 'w', 2, MyMoneySchedule::OCCUR_EVERYOTHERWEEK, MyMoneySchedule::MoveNothing },
+ {"three-weekly", 'w', 3, MyMoneySchedule::OCCUR_EVERYTHREEWEEKS, MyMoneySchedule::MoveNothing },
+ {"four-weekly", 'w', 4, MyMoneySchedule::OCCUR_EVERYFOURWEEKS,
+ MyMoneySchedule::MoveNothing },
+ {"eight-weekly", 'w', 8, MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS, MyMoneySchedule::MoveNothing },
+ {"monthly", 'm', 1, MyMoneySchedule::OCCUR_MONTHLY, MyMoneySchedule::MoveNothing },
+ {"two-monthly", 'm', 2, MyMoneySchedule::OCCUR_EVERYOTHERMONTH,
+ MyMoneySchedule::MoveNothing },
+ {"quarterly", 'm', 3, MyMoneySchedule::OCCUR_QUARTERLY, MyMoneySchedule::MoveNothing },
+ {"tri_annually", 'm', 4, MyMoneySchedule::OCCUR_EVERYFOURMONTHS, MyMoneySchedule::MoveNothing },
+ {"semi_yearly", 'm', 6, MyMoneySchedule::OCCUR_TWICEYEARLY, MyMoneySchedule::MoveNothing },
+ {"yearly", 'y', 1, MyMoneySchedule::OCCUR_YEARLY, MyMoneySchedule::MoveNothing },
+ {"two-yearly", 'y', 2, MyMoneySchedule::OCCUR_EVERYOTHERYEAR,
+ MyMoneySchedule::MoveNothing },
+ {"zzz", 'y', 1, MyMoneySchedule::OCCUR_YEARLY, MyMoneySchedule::MoveNothing}
+ // zzz = stopper, may cause problems. what else can we do?
+ };
+
+ QString frequency = "unknown"; // set default to unknown frequency
+ bool unknownOccurs = false; // may have zero, or more than one frequency/recurrence spec
+ QString schedEnabled;
+ if (gsc->version() == "2.0.0") {
+ if (gsc->m_vpRecurrence.count() != 1) {
+ unknownOccurs = true;
+ } else {
+ const GncRecurrence *gre = gsc->m_vpRecurrence.first();
+ //qDebug (QString("Sched %1, pt %2, mu %3, sd %4").arg(gsc->name()).arg(gre->periodType())
+ // .arg(gre->mult()).arg(gre->startDate().toString(Qt::ISODate)));
+ frequency = gre->getFrequency();
+ schedEnabled = gsc->enabled();
+ }
+ sc.setOccurence(MyMoneySchedule::OCCUR_ONCE); // FIXME - how to convert
+ } else {
+ // find this interval
+ const GncFreqSpec *fs = gsc->getFreqSpec();
+ if (fs == NULL) {
+ unknownOccurs = true;
+ } else {
+ frequency = fs->intervalType();
+ if (!fs->m_fsList.isEmpty()) unknownOccurs = true; // nested freqspec
+ }
+ schedEnabled = "y"; // earlier versions did not have an enable flag
+ }
+
+ int i;
+ for (i = 0; vi[i].gncType != "zzz"; i++) {
+ if (frequency == vi[i].gncType) break;
+ }
+ if (vi[i].gncType == "zzz") {
+ postMessage ("SC", 1, sc.name().latin1(), frequency.latin1());
+ i = 0; // treat as single occurrence
+ m_suspectSchedule = true;
+ }
+ if (unknownOccurs) {
+ postMessage ("SC", 7, sc.name().latin1());
+ m_suspectSchedule = true;
+ }
+ // set the occurrence interval, weekend option, start date
+ sc.setOccurence (vi[i].occ);
+ sc.setWeekendOption (vi[i].wo);
+ sc.setStartDate (gsc->startDate());
+ // if a last date was specified, use it, otherwise try to work out the last date
+ sc.setLastPayment(gsc->lastDate());
+ numOccurs = gsc->numOccurs().toInt();
+ if (sc.lastPayment() == QDate()) {
+ nextDate = lastDate = gsc->startDate();
+ while ((nextDate < today) && (numOccurs-- != 0)) {
+ lastDate = nextDate;
+ nextDate = incrDate (lastDate, vi[i].interval, vi[i].intervalCount);
+ }
+ sc.setLastPayment(lastDate);
+ }
+ // under Tom's new regime, the tx dates are the next due date (I think)
+ tx.setPostDate(incrDate(sc.lastPayment(), vi[i].interval, vi[i].intervalCount));
+ tx.setEntryDate(incrDate(sc.lastPayment(), vi[i].interval, vi[i].intervalCount));
+ // if an end date was specified, use it, otherwise if the input file had a number
+ // of occurs remaining, work out the end date
+ sc.setEndDate(gsc->endDate());
+ numOccurs = gsc->numOccurs().toInt();
+ remOccurs = gsc->remOccurs().toInt();
+ if ((sc.endDate() == QDate()) && (remOccurs > 0)) {
+ endDate = sc.lastPayment();
+ while (remOccurs-- > 0) {
+ endDate = incrDate (endDate, vi[i].interval, vi[i].intervalCount);
+ }
+ sc.setEndDate(endDate);
+ }
+ // Check for sched deferred interval. Don't know how/if we can handle it, or even what it means...
+ if (gsc->getSchedDef() != NULL) {
+ postMessage ("SC", 8, sc.name().latin1());
+ m_suspectSchedule = true;
+ }
+ // payment type, options
+ sc.setPaymentType((MyMoneySchedule::paymentTypeE)MyMoneySchedule::STYPE_OTHER);
+ sc.setFixed (!m_suspectSchedule); // if any probs were found, set it as variable so user will always be prompted
+ // we don't currently have a 'disable' option, but just make sure auto-enter is off if not enabled
+ //qDebug(QString("%1 and %2").arg(gsc->autoCreate()).arg(schedEnabled));
+ sc.setAutoEnter ((gsc->autoCreate() == "y") && (schedEnabled == "y"));
+ //qDebug(QString("autoEnter set to %1").arg(sc.autoEnter()));
+ // type
+ QString actionType = tx.splits().first().action();
+ if (actionType == MyMoneySplit::ActionDeposit) {
+ sc.setType((MyMoneySchedule::typeE)MyMoneySchedule::TYPE_DEPOSIT);
+ } else if (actionType == MyMoneySplit::ActionTransfer) {
+ sc.setType((MyMoneySchedule::typeE)MyMoneySchedule::TYPE_TRANSFER);
+ } else {
+ sc.setType((MyMoneySchedule::typeE)MyMoneySchedule::TYPE_BILL);
+ }
+ // finally, set the transaction pointer
+ sc.setTransaction(tx);
+ //tell the storage objects we have a new schedule object.
+ if (m_suspectSchedule && m_dropSuspectSchedules) {
+ postMessage ("SC", 2, sc.name().latin1());
+ } else {
+ m_storage->addSchedule(sc);
+ if (m_suspectSchedule)
+ m_suspectList.append (sc.id());
+ }
+ signalProgress (++m_scheduleCount, 0);
+ return ;
+ PASS
+}
+//********************************* convertFreqSpec ********************************************************
+void MyMoneyGncReader::convertFreqSpec (const GncFreqSpec *) {
+ // Nowt to do here at the moment, convertSched only retrieves the interval type
+ // but we will probably need to look into the nested freqspec when we properly implement semi-monthly and stuff
+ return ;
+}
+//********************************* convertRecurrence ********************************************************
+void MyMoneyGncReader::convertRecurrence (const GncRecurrence *) {
+ return ;
+}
+
+//**********************************************************************************************************
+//************************************* terminate **********************************************************
+void MyMoneyGncReader::terminate () {
+ TRY
+ // All data has been converted and added to storage
+ // this code is just temporary to show us what is in the file.
+ if (gncdebug) qDebug("%d accounts found in the GnuCash file", (unsigned int)m_mapIds.count());
+ for (map_accountIds::Iterator it = m_mapIds.begin(); it != m_mapIds.end(); ++it) {
+ if (gncdebug) qDebug("key = %s, value = %s", it.key().data(), it.data().data());
+ }
+ // first step is to implement the users investment option, now we
+ // have all the accounts available
+ QValueList<QString>::iterator stocks;
+ for (stocks = m_stockList.begin(); stocks != m_stockList.end(); ++stocks) {
+ checkInvestmentOption (*stocks);
+ }
+ // Next step is to walk the list and assign the parent/child relationship between the objects.
+ unsigned int i = 0;
+ signalProgress (0, m_accountCount, i18n ("Reorganizing accounts..."));
+ QValueList<MyMoneyAccount> list;
+ QValueList<MyMoneyAccount>::Iterator acc;
+ m_storage->accountList(list);
+ for (acc = list.begin(); acc != list.end(); ++acc) {
+ if ((*acc).parentAccountId() == m_storage->asset().id()) {
+ MyMoneyAccount assets = m_storage->asset();
+ m_storage->addAccount(assets, (*acc));
+ if (gncdebug) qDebug("Account id %s is a child of the main asset account", (*acc).id().data());
+ } else if ((*acc).parentAccountId() == m_storage->liability().id()) {
+ MyMoneyAccount liabilities = m_storage->liability();
+ m_storage->addAccount(liabilities, (*acc));
+ if (gncdebug) qDebug("Account id %s is a child of the main liability account", (*acc).id().data());
+ } else if ((*acc).parentAccountId() == m_storage->income().id()) {
+ MyMoneyAccount incomes = m_storage->income();
+ m_storage->addAccount(incomes, (*acc));
+ if (gncdebug) qDebug("Account id %s is a child of the main income account", (*acc).id().data());
+ } else if ((*acc).parentAccountId() == m_storage->expense().id()) {
+ MyMoneyAccount expenses = m_storage->expense();
+ m_storage->addAccount(expenses, (*acc));
+ if (gncdebug) qDebug("Account id %s is a child of the main expense account", (*acc).id().data());
+ } else if ((*acc).parentAccountId() == m_storage->equity().id()) {
+ MyMoneyAccount equity = m_storage->equity();
+ m_storage->addAccount(equity, (*acc));
+ if (gncdebug) qDebug("Account id %s is a child of the main equity account", (*acc).id().data());
+ } else if ((*acc).parentAccountId() == m_rootId) {
+ if (gncdebug) qDebug("Account id %s is a child of root", (*acc).id().data());
+ } else {
+ // it is not under one of the main accounts, so find gnucash parent
+ QString parentKey = (*acc).parentAccountId();
+ if (gncdebug) qDebug ("acc %s, parent %s", (*acc).id().data(),
+ (*acc).parentAccountId().data());
+ map_accountIds::Iterator id = m_mapIds.find(parentKey);
+ if (id != m_mapIds.end()) {
+ if (gncdebug) qDebug("Setting account id %s's parent account id to %s",
+ (*acc).id().data(), id.data().data());
+ MyMoneyAccount parent = m_storage->account(id.data());
+ parent = checkConsistency (parent, (*acc));
+ m_storage->addAccount (parent, (*acc));
+ } else {
+ throw new MYMONEYEXCEPTION ("terminate() could not find account id");
+ }
+ }
+ signalProgress (++i, 0);
+ } // end for account
+ signalProgress (0, 1, (".")); // debug - get rid of reorg message
+ // offer the most common account currency as a default
+ QString mainCurrency = "";
+ unsigned int maxCount = 0;
+ QMap<QString, unsigned int>::ConstIterator it;
+ for (it = m_currencyCount.begin(); it != m_currencyCount.end(); ++it) {
+ if (it.data() > maxCount) {
+ maxCount = it.data();
+ mainCurrency = it.key();
+ }
+ }
+
+ if (mainCurrency != "") {
+ /* fix for qt3.3.4?. According to Qt docs, this should return the enum id of the button pressed, and
+ indeed it used to do so. However now it seems to return the index of the button. In this case it doesn't matter,
+ since for Yes, the id is 3 and the index is 0, whereas the No button will return 4 or 1. So we test for either Yes case */
+ /* and now it seems to have changed again, returning 259 for a Yes??? so use KMessagebox */
+ QString question = i18n("Your main currency seems to be %1 (%2); do you want to set this as your base currency?")
+ .arg(mainCurrency).arg(m_storage->currency(mainCurrency.utf8()).name());
+ if(KMessageBox::questionYesNo(0, question, PACKAGE) == KMessageBox::Yes) {
+ m_storage->setValue ("kmm-baseCurrency", mainCurrency);
+ }
+ }
+ // now produce the end of job reports - first, work out which ones are required
+ m_ccCount = 0, m_orCount = 0, m_scCount = 0;
+ for (i = 0; i < m_messageList.count(); i++) {
+ if ((*m_messageList.at(i)).source == "CC") m_ccCount++;
+ if ((*m_messageList.at(i)).source == "OR") m_orCount++;
+ if ((*m_messageList.at(i)).source == "SC") m_scCount++;
+ }
+ QValueList<QString> sectionsToReport; // list of sections needing report
+ sectionsToReport.append ("MN"); // always build the main section
+ if (m_ccCount > 0) sectionsToReport.append ("CC");
+ if (m_orCount > 0) sectionsToReport.append ("OR");
+ if (m_scCount > 0) sectionsToReport.append ("SC");
+ // produce the sections in message boxes
+ bool exit = false;
+ for (i = 0; (i < sectionsToReport.count()) && !exit; i++) {
+ QString button0Text = i18n("More");
+ if (i + 1 == sectionsToReport.count())
+ button0Text = i18n("Done"); // last section
+ KGuiItem yesItem(button0Text, QIconSet(), "", "");
+ KGuiItem noItem(i18n("Save Report"), QIconSet(), "", "");
+
+ switch(KMessageBox::questionYesNoCancel(0,
+ buildReportSection (*sectionsToReport.at(i)),
+ PACKAGE,
+ yesItem, noItem)) {
+ case KMessageBox::Yes:
+ break;
+ case KMessageBox::No:
+ exit = writeReportToFile (sectionsToReport);
+ break;
+ default:
+ exit = true;
+ break;
+ }
+ }
+
+ for (i = 0; i < m_suspectList.count(); i++) {
+ MyMoneySchedule sc = m_storage->schedule(m_suspectList[i]);
+ KEditScheduleDlg *s;
+ switch(KMessageBox::warningYesNo(0, i18n("Problems were encountered in converting schedule '%1'.\nDo you want to review or edit it now?").arg(sc.name()), PACKAGE)) {
+ case KMessageBox::Yes:
+ s = new KEditScheduleDlg (sc);
+ // FIXME: connect newCategory to something useful, so that we
+ // can create categories from within the dialog
+ if (s->exec())
+ m_storage->modifySchedule (s->schedule());
+ delete s;
+ break;
+
+ default:
+ break;
+ }
+ }
+ PASS
+}
+//************************************ buildReportSection************************************
+QString MyMoneyGncReader::buildReportSection (const QString& source) {
+ TRY
+ QString s = "";
+ bool more = false;
+ if (source == "MN") {
+ s.append (i18n("Found:\n\n"));
+ s.append (QString::number(m_commodityCount) + i18n(" commodities (equities)\n"));
+ s.append (QString::number(m_priceCount) + i18n(" prices\n"));
+ s.append (QString::number(m_accountCount) + i18n(" accounts\n"));
+ s.append (QString::number(m_transactionCount) + i18n(" transactions\n"));
+ s.append (QString::number(m_scheduleCount) + i18n(" schedules\n"));
+ s.append ("\n\n");
+ if (m_ccCount == 0) {
+ s.append (i18n("No inconsistencies were detected"));
+ } else {
+ s.append (QString::number(m_ccCount) + i18n(" inconsistencies were detected and corrected\n"));
+ more = true;
+ }
+ if (m_orCount > 0) {
+ s.append ("\n\n");
+ s.append (QString::number(m_orCount) + i18n(" orphan accounts were created\n"));
+ more = true;
+ }
+ if (m_scCount > 0) {
+ s.append ("\n\n");
+ s.append (QString::number(m_scCount) + i18n(" possible schedule problems were noted\n"));
+ more = true;
+ }
+ QString unsupported ("");
+ QString lineSep ("\n - ");
+ if (m_smallBusinessFound) unsupported.append(lineSep + i18n("Small Business Features (Customers, Invoices, etc.)"));
+ if (m_budgetsFound) unsupported.append(lineSep + i18n("Budgets"));
+ if (m_lotsFound) unsupported.append(lineSep + i18n("Lots"));
+ if (!unsupported.isEmpty()) {
+ unsupported.prepend(i18n("The following features found in your file are not currently supported:"));
+ s.append(unsupported);
+ }
+ if (more) s.append (i18n("\n\nPress More for further information"));
+ } else { // we need to retrieve the posted messages for this source
+ if (gncdebug) qDebug("Building messages for source %s", source.latin1());
+ unsigned int i, j;
+ for (i = 0; i < m_messageList.count(); i++) {
+ GncMessageArgs *m = m_messageList.at(i);
+ if (m->source == source) {
+ if (gncdebug) qDebug("%s", QString("build text source %1, code %2, argcount %3")
+ .arg(m->source).arg(m->code).arg(m->args.count()).data());
+ QString ss = GncMessages::text (m->source, m->code);
+ // add variable args. the .arg function seems always to replace the
+ // lowest numbered placeholder it finds, so translating messages
+ // with variables in a different order should still work okay (I think...)
+ for (j = 0; j < m->args.count(); j++) ss = ss.arg (*m->args.at(j));
+ s.append (ss + "\n");
+ }
+ }
+ }
+ if (gncdebug) qDebug ("%s", s.latin1());
+ return (static_cast<const QString>(s));
+ PASS
+}
+//************************ writeReportToFile*********************************
+bool MyMoneyGncReader::writeReportToFile (const QValueList<QString>& sectionsToReport) {
+ TRY
+ unsigned int i;
+ QFileDialog* fd = new QFileDialog (0, "Save report as", TRUE);
+ fd->setMode (QFileDialog::AnyFile);
+ if (fd->exec() != QDialog::Accepted) {
+ delete fd;
+ return (false);
+ }
+ QFile reportFile(fd->selectedFile());
+ QFileInfo fi (reportFile);
+ if (!reportFile.open (IO_WriteOnly)) {
+ delete fd;
+ return (false);
+ }
+ QTextStream stream (&reportFile);
+ for (i = 0; i < sectionsToReport.count(); i++) {
+ stream << buildReportSection (*sectionsToReport.at(i)).latin1() << endl;
+ }
+ reportFile.close();
+ delete fd;
+ return (true);
+ PASS
+}
+/****************************************************************************
+ Utility routines
+*****************************************************************************/
+//************************ createPayee ***************************
+
+QString MyMoneyGncReader::createPayee (const QString& gncDescription) {
+ MyMoneyPayee payee;
+ try {
+ payee = m_storage->payeeByName (gncDescription);
+ } catch (MyMoneyException *e) { // payee not found, create one
+ delete e;
+ payee.setName (gncDescription);
+ m_storage->addPayee (payee);
+ }
+ return (payee.id());
+}
+//************************************** createOrphanAccount *******************************
+QString MyMoneyGncReader::createOrphanAccount (const QString& gncName) {
+ MyMoneyAccount acc;
+
+ acc.setName ("orphan_" + gncName);
+ acc.setDescription (i18n("Orphan created from unknown gnucash account"));
+
+ QDate today = QDate::currentDate();
+
+ acc.setOpeningDate (today);
+ acc.setLastModified (today);
+ acc.setLastReconciliationDate (today);
+ acc.setCurrencyId (m_txCommodity);
+ acc.setAccountType (MyMoneyAccount::Asset);
+ acc.setParentAccountId (m_storage->asset().id());
+ m_storage->addAccount (acc);
+ // assign the gnucash id as the key into the map to find our id
+ m_mapIds[gncName.utf8()] = acc.id();
+ postMessage ("OR", 1, acc.name().data());
+ return (acc.id());
+}
+//****************************** incrDate *********************************************
+QDate MyMoneyGncReader::incrDate (QDate lastDate, unsigned char interval, unsigned int intervalCount) {
+ TRY
+ switch (interval) {
+ case 'd':
+ return (lastDate.addDays(intervalCount));
+ case 'w':
+ return (lastDate.addDays(intervalCount * 7));
+ case 'm':
+ return (lastDate.addMonths(intervalCount));
+ case 'y':
+ return (lastDate.addYears(intervalCount));
+ case 'o': // once-only
+ return (lastDate);
+ }
+ throw new MYMONEYEXCEPTION (i18n("Internal error - invalid interval char in incrDate"));
+ QDate r = QDate(); return (r); // to keep compiler happy
+ PASS
+}
+//********************************* checkConsistency **********************************
+MyMoneyAccount MyMoneyGncReader::checkConsistency (MyMoneyAccount& parent, MyMoneyAccount& child) {
+ TRY
+ // gnucash is flexible/weird enough to allow various inconsistencies
+ // these are a couple I found in my file, no doubt more will be discovered
+ if ((child.accountType() == MyMoneyAccount::Investment) &&
+ (parent.accountType() != MyMoneyAccount::Asset)) {
+ postMessage ("CC", 1, child.name().latin1());
+ return m_storage->asset();
+ }
+ if ((child.accountType() == MyMoneyAccount::Income) &&
+ (parent.accountType() != MyMoneyAccount::Income)) {
+ postMessage ("CC", 2, child.name().latin1());
+ return m_storage->income();
+ }
+ if ((child.accountType() == MyMoneyAccount::Expense) &&
+ (parent.accountType() != MyMoneyAccount::Expense)) {
+ postMessage ("CC", 3, child.name().latin1());
+ return m_storage->expense();
+ }
+ return (parent);
+ PASS
+}
+//*********************************** checkInvestmentOption *************************
+void MyMoneyGncReader::checkInvestmentOption (QString stockId) {
+ // implement the investment option for stock accounts
+ // first check whether the parent account (gnucash id) is actually an
+ // investment account. if it is, no further action is needed
+ MyMoneyAccount stockAcc = m_storage->account (m_mapIds[stockId.utf8()]);
+ MyMoneyAccount parent;
+ QString parentKey = stockAcc.parentAccountId();
+ map_accountIds::Iterator id = m_mapIds.find (parentKey);
+ if (id != m_mapIds.end()) {
+ parent = m_storage->account (id.data());
+ if (parent.accountType() == MyMoneyAccount::Investment) return ;
+ }
+ // so now, check the investment option requested by the user
+ // option 0 creates a separate investment account for each stock account
+ if (m_investmentOption == 0) {
+ MyMoneyAccount invAcc (stockAcc);
+ invAcc.setAccountType (MyMoneyAccount::Investment);
+ invAcc.setCurrencyId (QString("")); // we don't know what currency it is!!
+ invAcc.setParentAccountId (parentKey); // intersperse it between old parent and child stock acct
+ m_storage->addAccount (invAcc);
+ m_mapIds [invAcc.id()] = invAcc.id(); // so stock account gets parented (again) to investment account later
+ if (gncdebug) qDebug ("Created investment account %s as id %s, parent %s", invAcc.name().data(), invAcc.id().data(),
+ invAcc.parentAccountId().data());
+ if (gncdebug) qDebug ("Setting stock %s, id %s, as child of %s", stockAcc.name().data(), stockAcc.id().data(), invAcc.id().data());
+ stockAcc.setParentAccountId (invAcc.id());
+ m_storage->addAccount(invAcc, stockAcc);
+ // investment option 1 creates a single investment account for all stocks
+ } else if (m_investmentOption == 1) {
+ static QString singleInvAccId = "";
+ MyMoneyAccount singleInvAcc;
+ bool ok = false;
+ if (singleInvAccId.isEmpty()) { // if the account has not yet been created
+ QString invAccName;
+ while (!ok) {
+ invAccName = QInputDialog::getText (PACKAGE,
+ i18n("Enter the investment account name "), QLineEdit::Normal,
+ i18n("My Investments"), &ok);
+ }
+ singleInvAcc.setName (invAccName);
+ singleInvAcc.setAccountType (MyMoneyAccount::Investment);
+ singleInvAcc.setCurrencyId (QString(""));
+ singleInvAcc.setParentAccountId (m_storage->asset().id());
+ m_storage->addAccount (singleInvAcc);
+ m_mapIds [singleInvAcc.id()] = singleInvAcc.id(); // so stock account gets parented (again) to investment account later
+ if (gncdebug) qDebug ("Created investment account %s as id %s, parent %s, reparenting stock",
+ singleInvAcc.name().data(), singleInvAcc.id().data(), singleInvAcc.parentAccountId().data());
+ singleInvAccId = singleInvAcc.id();
+ } else { // the account has already been created
+ singleInvAcc = m_storage->account (singleInvAccId);
+ }
+ m_storage->addAccount(singleInvAcc, stockAcc); // add stock as child
+ // the original intention of option 2 was to allow any asset account to be converted to an investment (broker) account
+ // however, since we have already stored the accounts as asset, we have no way at present of changing their type
+ // the only alternative would be to hold all the gnucash data in memory, then implement this option, then convert all the data
+ // that would mean a major overhaul of the code. Perhaps I'll think of another way...
+ } else if (m_investmentOption == 2) {
+ static int lastSelected = 0;
+ MyMoneyAccount invAcc (stockAcc);
+ QStringList accList;
+ QValueList<MyMoneyAccount> list;
+ QValueList<MyMoneyAccount>::Iterator acc;
+ m_storage->accountList(list);
+ // build a list of candidates for the input box
+ for (acc = list.begin(); acc != list.end(); ++acc) {
+ // if (((*acc).accountGroup() == MyMoneyAccount::Asset) && ((*acc).accountType() != MyMoneyAccount::Stock)) accList.append ((*acc).name());
+ if ((*acc).accountType() == MyMoneyAccount::Investment) accList.append ((*acc).name());
+ }
+ //if (accList.isEmpty()) qFatal ("No available accounts");
+ bool ok = false;
+ while (!ok) { // keep going till we have a valid investment parent
+ QString invAccName = QInputDialog::getItem (
+ PACKAGE, i18n("Select parent investment account or enter new name. Stock %1").arg(stockAcc.name ()),
+ accList, lastSelected, true, &ok);
+ if (ok) {
+ lastSelected = accList.findIndex (invAccName); // preserve selection for next time
+ for (acc = list.begin(); acc != list.end(); ++acc) {
+ if ((*acc).name() == invAccName) break;
+ }
+ if (acc != list.end()) { // an account was selected
+ invAcc = *acc;
+ } else { // a new account name was entered
+ invAcc.setAccountType (MyMoneyAccount::Investment);
+ invAcc.setName (invAccName);
+ invAcc.setCurrencyId (QString(""));
+ invAcc.setParentAccountId (m_storage->asset().id());
+ m_storage->addAccount (invAcc);
+ ok = true;
+ }
+ if (invAcc.accountType() == MyMoneyAccount::Investment) {
+ ok = true;
+ } else {
+ // this code is probably not going to be implemented coz we can't change account types (??)
+#if 0
+ QMessageBox mb (PACKAGE,
+ i18n ("%1 is not an Investment Account. Do you wish to make it one?").arg(invAcc.name()),
+ QMessageBox::Question,
+ QMessageBox::Yes | QMessageBox::Default,
+ QMessageBox::No | QMessageBox::Escape,
+ QMessageBox::NoButton);
+ switch (mb.exec()) {
+ case QMessageBox::No :
+ ok = false; break;
+ default:
+ // convert it - but what if it has splits???
+ qFatal ("Not yet implemented");
+ ok = true;
+ break;
+ }
+#endif
+ switch(KMessageBox::questionYesNo(0, i18n ("%1 is not an Investment Account. Do you wish to make it one?").arg(invAcc.name(), PACKAGE))) {
+ case KMessageBox::Yes:
+ // convert it - but what if it has splits???
+ qFatal ("Not yet implemented");
+ ok = true;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+ } // end if ok - user pressed Cancel
+ } // end while !ok
+ m_mapIds [invAcc.id()] = invAcc.id(); // so stock account gets parented (again) to investment account later
+ m_storage->addAccount(invAcc, stockAcc);
+ } else { // investment option != 0, 1, 2
+ qFatal ("Invalid investment option %d", m_investmentOption);
+ }
+}
+
+// get the price source for a stock (gnc account) where online quotes are requested
+void MyMoneyGncReader::getPriceSource (MyMoneySecurity stock, QString gncSource) {
+ // if he wants to use Finance::Quote, no conversion of source name is needed
+ if (m_useFinanceQuote) {
+ stock.setValue ("kmm-online-quote-system", "Finance::Quote");
+ stock.setValue ("kmm-online-source", gncSource.lower());
+ m_storage->modifySecurity(stock);
+ return;
+ }
+ // first check if we have already asked about this source
+ // (mapSources is initialy empty. We may be able to pre-fill it with some equivalent
+ // sources, if such things do exist. User feedback may help here.)
+ QMap<QString, QString>::Iterator it;
+ for (it = m_mapSources.begin(); it != m_mapSources.end(); it++) {
+ if (it.key() == gncSource) {
+ stock.setValue("kmm-online-source", it.data());
+ m_storage->modifySecurity(stock);
+ return;
+ }
+ }
+ // not found in map, so ask the user
+ KGncPriceSourceDlg *dlg = new KGncPriceSourceDlg (stock.name(), gncSource);
+ dlg->exec();
+ QString s = dlg->selectedSource();
+ if (!s.isEmpty()) {
+ stock.setValue("kmm-online-source", s);
+ m_storage->modifySecurity(stock);
+ }
+ if (dlg->alwaysUse()) m_mapSources[gncSource] = s;
+ delete dlg;
+ return;
+}
+
+// functions to control the progress bar
+//*********************** setProgressCallback *****************************
+void MyMoneyGncReader::setProgressCallback(void(*callback)(int, int, const QString&)) {
+ m_progressCallback = callback; return ;
+}
+//************************** signalProgress *******************************
+void MyMoneyGncReader::signalProgress(int current, int total, const QString& msg) {
+ if (m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+ return ;
+}
+// error and information reporting
+//***************************** Information and error messages *********************
+void MyMoneyGncReader::postMessage (const QString& source, const unsigned int code, const char* arg1) {
+ postMessage (source, code, QStringList(arg1));
+}
+void MyMoneyGncReader::postMessage (const QString& source, const unsigned int code, const char* arg1, const char* arg2) {
+ QStringList argList(arg1);
+ argList.append(arg2);
+ postMessage(source, code, argList);
+}
+void MyMoneyGncReader::postMessage (const QString& source, const unsigned int code, const char* arg1, const char* arg2, const char* arg3) {
+ QStringList argList(arg1);
+ argList.append(arg2);
+ argList.append(arg3);
+ postMessage(source, code, argList);
+}
+void MyMoneyGncReader::postMessage (const QString& source, const unsigned int code, const QStringList& argList) {
+ unsigned int i;
+ GncMessageArgs *m = new GncMessageArgs;
+
+ m->source = source;
+ m->code = code;
+ // get the number of args this message requires
+ const unsigned int argCount = GncMessages::argCount (source, code);
+ if ((gncdebug) && (argCount != argList.count()))
+ qDebug("%s", QString("MyMoneyGncReader::postMessage debug: Message %1, code %2, requires %3 arguments, got %4")
+ .arg(source).arg(code).arg(argCount).arg(argList.count()).data());
+ // store the arguments
+ for (i = 0; i < argCount; i++) {
+ if (i > argList.count()) m->args.append(QString());
+ else m->args.append (argList[i]); //Adds the next argument to the list
+ }
+ m_messageList.append (m);
+ return ;
+}
+//********************************** Message texts **********************************************
+GncMessages::messText GncMessages::texts [] = {
+ {"CC", 1, i18n("An Investment account must be a child of an Asset account\n"
+ "Account %1 will be stored under the main Asset account")},
+ {"CC", 2, i18n("An Income account must be a child of an Income account\n"
+ "Account %1 will be stored under the main Income account")},
+ {"CC", 3, i18n("An Expense account must be a child of an Expense account\n"
+ "Account %1 will be stored under the main Expense account")},
+ {"OR", 1, i18n("One or more transactions contain a reference to an otherwise unknown account\n"
+ "An asset account with the name %1 has been created to hold the data")},
+ {"SC", 1, i18n("Schedule %1 has interval of %2 which is not currently available")},
+ {"SC", 2, i18n("Schedule %1 dropped at user request")},
+ {"SC", 3, i18n("Schedule %1 contains unknown action (key = %2, type = %3)")},
+ {"SC", 4, i18n("Schedule %1 contains multiple actions; only one has been imported")},
+ {"SC", 5, i18n("Schedule %1 contains no valid splits")},
+ {"SC", 6, i18n("Schedule %1 appears to contain a formula. GnuCash formulae are not convertible")},
+ {"SC", 7, i18n("Schedule %1 contains unknown interval specification; please check for correct operation")},
+ {"SC", 8, i18n("Schedule %1 contains a deferred interval specification; please check for correct operation")},
+ {"CC", 4, i18n("Account or Category %1, transaction date %2; split contains invalid value; please check")},
+ {"ZZ", 0, ""} // stopper
+ };
+//
+QString GncMessages::text (const QString source, const unsigned int code) {
+ TRY
+ unsigned int i;
+ for (i = 0; texts[i].source != "ZZ"; i++) {
+ if ((source == texts[i].source) && (code == texts[i].code)) break;
+ }
+ if (texts[i].source == "ZZ") {
+ QString mess = QString().sprintf("Internal error - unknown message - source %s, code %d", source.latin1(), code);
+ throw new MYMONEYEXCEPTION (mess);
+ }
+ return (texts[i].text);
+ PASS
+}
+//
+unsigned int GncMessages::argCount (const QString source, const unsigned int code) {
+ TRY
+ unsigned int i;
+ for (i = 0; texts[i].source != "ZZ"; i++) {
+ if ((source == texts[i].source) && (code == texts[i].code)) break;
+ }
+ if (texts[i].source == "ZZ") {
+ QString mess = QString().sprintf("Internal error - unknown message - source %s, code %d", source.latin1(), code);
+ throw new MYMONEYEXCEPTION (mess);
+ }
+ QRegExp argConst ("%\\d");
+ int offset = 0;
+ unsigned int argCount = 0;
+ while ((offset = argConst.search (texts[i].text, offset)) != -1) {
+ argCount++;
+ offset += 2;
+ }
+ return (argCount);
+ PASS
+}
+#endif // _GNCFILEANON
diff --git a/kmymoney2/converter/mymoneygncreader.h b/kmymoney2/converter/mymoneygncreader.h
new file mode 100644
index 0000000..df08913
--- /dev/null
+++ b/kmymoney2/converter/mymoneygncreader.h
@@ -0,0 +1,904 @@
+/***************************************************************************
+ mymoneygncreader - description
+ -------------------
+ begin : Wed Mar 3 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/*
+The main class of this module, MyMoneyGncReader, contains only a readFile()
+function, which controls the import of data from an XML file created by the
+current GnuCash version (1.8.8).
+
+The XML is processed in class XmlReader, which is an implementation of the Qt
+SAX2 reader class.
+
+Data in the input file is processed as a set of objects which fortunately,
+though perhaps not surprisingly, have almost a one-for-one correspondence with
+KMyMoney objects. These objects are bounded by start and end XML elements, and
+may contain both nested objects (described as sub objects in the code), and data
+items, also delimited by start and end elements. For example:
+<gnc:account> * start of sub object within file
+ <act:name>Account Name</act:name> * data string with start and end elements
+ ...
+</gnc:account> * end of sub objects
+
+A GnuCash file may consist of more than one 'book', or set of data. It is not
+clear how we could currently implement this, so only the first book in a file is
+processed. This should satisfy most user situations.
+
+GnuCash is somewhat inconsistent in its division of the major sections of the
+file. For example, multiple price history entries are delimited by <gnc:pricedb>
+elements, while each account starts with its own top-level element. In general,
+the 'container' elements are ignored.
+
+XmlReader
+
+This is an implementation of the Qt QXmlDefaultHandler class, which provides
+three main function calls in addition to start and end of document. The
+startElement() and endElement() calls are self-explanatory, the characters()
+function provides data strings. Thus in the above example, the sequence of calls
+would be
+ startElement() for gnc:account
+ startElement() for act:name
+ characters() for 'Account Name'
+ endElement() for act:name
+ ...
+ endElement() for gnc:account
+
+Objects
+
+Since the processing requirements of XML for most elements are very similar, the
+common code is implemented in a GncObject class, from which the others are
+derived, with virtual function calls to cater for any differences. The
+'grandfather' object, GncFile representing the file (or more correctly, 'book')
+as a whole, is created in the startDocument() function call.
+
+The constructor function of each object is responsible for providing two lists
+for the XmlReader to scan, a list of element names which represent sub objects
+(called sub elements in the code), and a similar list of names representing data
+elements. In addition, an array of variables (m_v) is provided and initialized,
+to contain the actual data strings.
+
+Implementation
+
+Since objects may be nested, a stack is used, with the top element pointing to
+the 'current object'. The startDocument() call creates the first, GncFile,
+object at the top of the stack.
+
+As each startElement() call occurs, the two element lists created by the current
+object are scanned.
+If this element represents the start of a sub object, the current object's subEl()
+function is called to create an instance of the appropriate type. This is then
+pushed to the top of the stack, and the new object's initiate() function is
+called. This is used to process any XML attributes attached to the element;
+GnuCash makes little use of these.
+If this represents the start of a data element, a pointer (m_dataPointer) is set
+to point to an entry in the array (m_v) in which a subsequent characters() call
+can store the actual data.
+
+When an endElement() call occurs, a check is made to see if it matches the
+element name which started the current object. If so, the object's terminate()
+function is called. If the object represents a similar KMM object, this will
+normally result in a call to a conversion routine in the main
+(MyMoneyGncReader) class to convert the data to native format and place it in
+storage. The stack is then popped, and the parent (now current) object notified
+by a call to its endSubEl() function. Again depending on the type of object,
+this will either delete the instance, or save it in its own storage for later
+processing.
+For example, a GncSplit object makes little sense outside the context of its
+transaction, so will be saved by the transaction. A GncTransaction object on the
+other hand will be converted, along with its attendant splits, and then deleted
+by its parent.
+
+Since at any one time an object will only be processing either a subobject or a
+data element, a single object variable, m_state, is used to determine the actual
+type. In effect, it acts as the current index into either the subElement or
+dataElement list. As an object variable, it will be saved on the stack across
+subobject processing.
+
+Exceptions and Problems
+
+Fatal exceptions are processed via the standard MyMoneyException method.
+Due to differences in implementation between GnuCash and KMM, it is not always
+possible to provide an absolutely correct conversion. When such a problem
+situation is recognized, a message, along with any relevant variable data, is
+passed to the main class, and used to produce a report when processing
+terminates. The GncMessages and GncMessageArg classes implement this.
+
+Anonymizer
+
+When debugging problems, it is often useful to have a trace of what is happening
+within the module. However, in view of the sensitive nature of personal finance
+data, most users will be reluctant to provide this. Accordingly, an anonymize
+(hide()) function is provided to handle data strings. These may either be passed
+through asis (non-personal data), blanked out (non-critical but possibly personal
+data), replaced with a generated version (required, but possibly personal), or
+randomized (monetary amounts). The action for each data item is determined in
+the object's constructor function along with the creation of the data element
+list.
+This module will later be used as the basis of a file anonymizer, which will
+enable users to safely provide us with a copy of their GnuCash files, and will
+allow us to test the structure, if not the data content, of the file.
+*/
+
+#ifndef MYMONEYSTORAGEGNC_H
+#define MYMONEYSTORAGEGNC_H
+
+// Some STL headers in GCC4.3 contain operator new. Memory checker mangles these
+#ifdef _CHECK_MEMORY
+ #undef new
+#endif
+// system includes
+#include <stdlib.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatastream.h>
+class QIODevice;
+#include <qobject.h>
+#include <qvaluelist.h>
+#include <qptrlist.h>
+#include <qptrstack.h>
+#include <qxml.h>
+#include <qdatetime.h>
+#include <qtextcodec.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#ifdef _CHECK_MEMORY
+ #include <kmymoney/mymoneyutils.h>
+#endif
+
+#ifndef _GNCFILEANON
+#include "../mymoney/storage/imymoneyserialize.h" // not used any more, but call interface requires it
+#include "../mymoney/storage/imymoneystorageformat.h"
+#endif // _GNCFILEANON
+
+// not sure what these are for, but leave them in
+#define VERSION_0_60_XML 0x10000010 // Version 0.5 file version info
+#define VERSION_0_61_XML 0x10000011 // use 8 bytes for MyMoneyMoney objects
+#define GNUCASH_ID_KEY "GNUCASH_ID"
+
+typedef QMap<QString, QString> map_accountIds;
+typedef map_accountIds::iterator map_accountIds_iter;
+typedef map_accountIds::const_iterator map_accountIds_citer;
+
+typedef QMap<QString, QStringList> map_elementVersions;
+
+class MyMoneyGncReader;
+
+/** GncObject is the base class for the various objects in the gnucash file
+ Beyond the first level XML objects, elements will be of one of three types:
+ 1. Sub object elements, which require creation of another object to process
+ 2. Data object elements, which are only followed by data to be stored in a variable (m_v array)
+ 3. Ignored objects, data not needed and not included herein
+*/
+class GncObject {
+public:
+ GncObject();
+ ; // to save delete loop when finished
+ virtual ~GncObject() {} // make sure to have impl of all virtual rtns to avoid vtable errors?
+protected:
+ friend class XmlReader;
+ friend class MyMoneyGncReader;
+
+ // check for sub object element; if it is, create the object
+ GncObject *isSubElement (const QString &elName, const QXmlAttributes& elAttrs);
+ // check for data element; if so, set data pointer
+ bool isDataElement (const QString &elName, const QXmlAttributes& elAttrs);
+ // process start element for 'this'; normally for attribute checking; other initialization done in constructor
+ virtual void initiate (const QString&, const QXmlAttributes&) { return ;};
+ // a sub object has completed; process the data it gathered
+ virtual void endSubEl(GncObject *) {m_dataPtr = 0; return ;};
+ // store data for data element
+ void storeData (const QString& pData) // NB - data MAY come in chunks, and may need to be anonymized
+ {if (m_dataPtr != 0)
+ m_dataPtr->append (hide (pData, m_anonClass)); return ;}
+ // following is provided only for a future file anonymizer
+ QString getData () const { return ((m_dataPtr != 0) ? *m_dataPtr : "");};
+ void resetDataPtr() {m_dataPtr = 0;};
+ // process end element for 'this'; usually to convert to KMM format
+ virtual void terminate() { return ;};
+ void setVersion (const QString& v) {m_version = v; return; };
+ QString version() const {return (m_version);};
+
+ // some gnucash elements have version attribute; check it
+ void checkVersion (const QString&, const QXmlAttributes&, const map_elementVersions&);
+ // get name of element processed by 'this'
+ QString getElName () const { return (m_elementName);};
+ // pass 'main' pointer to object
+ void setPm (MyMoneyGncReader *pM) {pMain = pM;};
+ // debug only
+ void debugDump();
+
+ // called by isSubElement to create appropriate sub object
+ virtual GncObject *startSubEl() { return (0);};
+ // called by isDataElement to set variable pointer
+ virtual void dataEl(const QXmlAttributes&) {m_dataPtr = m_v.at(m_state); m_anonClass = m_anonClassList[m_state];};
+ // return gnucash data string variable pointer
+ virtual QString var (int i) const;
+ // anonymize data
+ virtual QString hide (QString, unsigned int);
+
+ MyMoneyGncReader *pMain; // pointer to 'main' class
+ // used at start of each transaction so same money hide factor is applied to all splits
+ void adjustHideFactor();
+
+ QString m_elementName; // save 'this' element's name
+ QString m_version; // and it's gnucash version
+ const QString *m_subElementList; // list of sub object element names for 'this'
+ unsigned int m_subElementListCount; // count of above
+ const QString *m_dataElementList; // ditto for data elements
+ unsigned int m_dataElementListCount;
+ QString *m_dataPtr; // pointer to m_v variable for current data item
+ mutable QPtrList<QString> m_v; // storage for variable pointers
+
+ unsigned int m_state; // effectively, the index to subElementList or dataElementList, whichever is currently in use
+
+ const unsigned int *m_anonClassList;
+ enum anonActions {ASIS, SUPPRESS, NXTACC, NXTEQU, NXTPAY, NXTSCHD, MAYBEQ, MONEY1, MONEY2}; // anonymize actions - see hide()
+ unsigned int m_anonClass; // class of current data item for anonymizer
+ static double m_moneyHideFactor; // a per-transaction factor
+};
+
+// *****************************************************************************
+// This is the 'grandfather' object representing the gnucash file as a whole
+class GncFile : public GncObject {
+public:
+ GncFile ();
+ ~GncFile();
+private:
+ enum iSubEls {BOOK, COUNT, CMDTY, PRICE, ACCT, TX, TEMPLATES, SCHEDULES, END_FILE_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+
+ bool m_processingTemplates; // gnc uses same transaction element for ordinary and template tx's; this will distinguish
+ bool m_bookFound; // to detect multi-book files
+};
+// The following are 'utility' objects, which occur within several other object types
+// ****************************************************************************
+// commodity specification. consists of
+// cmdty:space - either ISO4217 if this cmdty is a currency, or, usually, the name of a stock exchange
+// cmdty:id - ISO4217 currency symbol, or 'ticker symbol'
+class GncCmdtySpec : public GncObject {
+public:
+ GncCmdtySpec ();
+ ~GncCmdtySpec ();
+protected:
+ friend class MyMoneyGncReader;
+ friend class GncTransaction;
+ bool isCurrency() const { return (*m_v.at(CMDTYSPC) == QString("ISO4217"));};
+ QString id() const { return (*m_v.at(CMDTYID));};
+ QString space() const { return (*m_v.at(CMDTYSPC));};
+private:
+ // data elements
+ enum CmdtySpecDataEls {CMDTYSPC, CMDTYID, END_CmdtySpec_DELS};
+ virtual QString hide (QString, unsigned int);
+};
+// *********************************************************************
+// date; maybe one of two types, ts:date which is date/time, gdate which is date only
+// we do not preserve time data (at present)
+class GncDate : public GncObject {
+public:
+ GncDate ();
+ ~GncDate();
+protected:
+ friend class MyMoneyGncReader;
+ friend class GncPrice;
+ friend class GncTransaction;
+ friend class GncSplit;
+ friend class GncSchedule;
+ friend class GncRecurrence;
+ const QDate date() const { return (QDate::fromString(m_v.at(TSDATE)->section(' ', 0, 0), Qt::ISODate));};
+private:
+ // data elements
+ enum DateDataEls {TSDATE, GDATE, END_Date_DELS};
+ virtual void dataEl(const QXmlAttributes&) {m_dataPtr = m_v.at(TSDATE); m_anonClass = GncObject::ASIS;}
+ ; // treat both date types the same
+};
+// ************* GncKvp********************************************
+// Key/value pairs, which are introduced by the 'slot' element
+// Consist of slot:key (the 'name' of the kvp), and slot:value (the data value)
+// the slot value also contains a slot type (string, integer, etc) implemented as an XML attribute
+// kvp's may be nested
+class GncKvp : public GncObject {
+public:
+ GncKvp ();
+ ~GncKvp();
+protected:
+ friend class MyMoneyGncReader;
+
+ QString key() const { return (var(KEY));};
+ QString value() const { return (var(VALUE));};
+ QString type() const { return (m_kvpType);};
+ unsigned int kvpCount() const { return (m_kvpList.count());};
+ const GncKvp *getKvp(unsigned int i) const { return (static_cast<GncKvp *>(m_kvpList.at(i)));};
+private:
+ // subsidiary objects/elements
+ enum KvpSubEls {KVP, END_Kvp_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ // data elements
+ enum KvpDataEls {KEY, VALUE, END_Kvp_DELS };
+ virtual void dataEl (const QXmlAttributes&);
+ mutable QPtrList<GncObject> m_kvpList;
+ QString m_kvpType; // type is an XML attribute
+};
+// ************* GncLot********************************************
+// KMM doesn't have support for lots as yet
+class GncLot : public GncObject {
+ public:
+ GncLot ();
+ ~GncLot();
+ protected:
+ friend class MyMoneyGncReader;
+ private:
+};
+
+/** Following are the main objects within the gnucash file, which correspond largely one-for-one
+ with similar objects in the kmymoney structure, apart from schedules which gnc splits between
+ template (transaction data) and schedule (date data)
+*/
+//********************************************************************
+class GncCountData : public GncObject {
+public:
+ GncCountData ();
+ ~GncCountData ();
+private:
+ virtual void initiate (const QString&, const QXmlAttributes&);
+ virtual void terminate();
+ QString m_countType; // type of element being counted
+};
+//********************************************************************
+class GncCommodity : public GncObject {
+public:
+ GncCommodity ();
+ ~GncCommodity();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ bool isCurrency() const { return (var(SPACE) == QString("ISO4217"));};
+ QString space() const { return (var(SPACE));};
+ QString id() const { return (var(ID));};
+ QString name() const { return (var(NAME));};
+ QString fraction() const { return (var(FRACTION));};
+private:
+ virtual void terminate();
+ // data elements
+ enum {SPACE, ID, NAME, FRACTION, END_Commodity_DELS};
+};
+// ************* GncPrice********************************************
+class GncPrice : public GncObject {
+public:
+ GncPrice ();
+ ~GncPrice();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ const GncCmdtySpec *commodity() const { return (m_vpCommodity);};
+ const GncCmdtySpec *currency() const { return (m_vpCurrency);};
+ QString value() const { return (var(VALUE));};
+ QDate priceDate () const { return (m_vpPriceDate->date());};
+private:
+ virtual void terminate();
+ // sub object elements
+ enum PriceSubEls {CMDTY, CURR, PRICEDATE, END_Price_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ // data elements
+ enum PriceDataEls {VALUE, END_Price_DELS };
+ GncCmdtySpec *m_vpCommodity, *m_vpCurrency;
+ GncDate *m_vpPriceDate;
+};
+// ************* GncAccount********************************************
+class GncAccount : public GncObject {
+public:
+ GncAccount ();
+ ~GncAccount();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ GncCmdtySpec *commodity() const { return (m_vpCommodity);};
+ QString id () const { return (var(ID));};
+ QString name () const { return (var(NAME));};
+ QString desc () const { return (var(DESC));};
+ QString type () const { return (var(TYPE));};
+ QString parent () const { return (var(PARENT));};
+private:
+ // subsidiary objects/elements
+ enum AccountSubEls {CMDTY, KVP, LOTS, END_Account_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ virtual void terminate();
+ // data elements
+ enum AccountDataEls {ID, NAME, DESC, TYPE, PARENT, END_Account_DELS };
+ GncCmdtySpec *m_vpCommodity;
+ QPtrList<GncObject> m_kvpList;
+};
+// ************* GncSplit********************************************
+class GncSplit : public GncObject {
+public:
+ GncSplit ();
+ ~GncSplit();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ QString id() const { return (var(ID));};
+ QString memo() const { return (var(MEMO));};
+ QString recon() const { return (var(RECON));};
+ QString value() const { return (var(VALUE));};
+ QString qty() const { return (var(QTY));};
+ QString acct() const { return (var(ACCT));};
+const QDate reconDate() const {QDate x = QDate(); return (m_vpDateReconciled == NULL ? x : m_vpDateReconciled->date());};
+private:
+ // subsidiary objects/elements
+ enum TransactionSubEls {RECDATE, END_Split_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ // data elements
+ enum SplitDataEls {ID, MEMO, RECON, VALUE, QTY, ACCT, END_Split_DELS };
+ GncDate *m_vpDateReconciled;
+};
+// ************* GncTransaction********************************************
+class GncTransaction : public GncObject {
+public:
+ GncTransaction (bool processingTemplates);
+ ~GncTransaction();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ QString id() const { return (var(ID));};
+ QString no() const { return (var(NO));};
+ QString desc() const { return (var(DESC));};
+ QString currency() const { return (m_vpCurrency == NULL ? QString () : m_vpCurrency->id());};
+ QDate dateEntered() const { return (m_vpDateEntered->date());};
+ QDate datePosted() const { return (m_vpDatePosted->date());};
+ bool isTemplate() const { return (m_template);};
+ unsigned int splitCount() const { return (m_splitList.count());};
+ unsigned int kvpCount() const { return (m_kvpList.count());};
+ const GncObject *getSplit (unsigned int i) const { return (m_splitList.at(i));};
+ const GncKvp *getKvp(unsigned int i) const { return (static_cast<GncKvp *>(m_kvpList.at(i)));};
+private:
+ // subsidiary objects/elements
+ enum TransactionSubEls {CURRCY, POSTED, ENTERED, SPLIT, KVP, END_Transaction_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ virtual void terminate();
+ // data elements
+ enum TransactionDataEls {ID, NO, DESC, END_Transaction_DELS };
+ GncCmdtySpec *m_vpCurrency;
+ GncDate *m_vpDateEntered, *m_vpDatePosted;
+ mutable QPtrList<GncObject> m_splitList;
+ bool m_template; // true if this is a template for scheduled transaction
+ mutable QPtrList<GncObject> m_kvpList;
+};
+
+// ************* GncTemplateSplit********************************************
+class GncTemplateSplit : public GncObject {
+public:
+ GncTemplateSplit ();
+ ~GncTemplateSplit();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ QString id() const { return (var(ID));};
+ QString memo() const { return (var(MEMO));};
+ QString recon() const { return (var(RECON));};
+ QString value() const { return (var(VALUE));};
+ QString qty() const { return (var(QTY));};
+ QString acct() const { return (var(ACCT));};
+ unsigned int kvpCount() const { return (m_kvpList.count());};
+ const GncKvp *getKvp(unsigned int i) const { return (static_cast<GncKvp *>(m_kvpList.at(i)));};
+private:
+ // subsidiary objects/elements
+ enum TemplateSplitSubEls {KVP, END_TemplateSplit_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ // data elements
+ enum TemplateSplitDataEls {ID, MEMO, RECON, VALUE, QTY, ACCT, END_TemplateSplit_DELS };
+ mutable QPtrList<GncObject> m_kvpList;
+};
+// ************* GncSchedule********************************************
+class GncFreqSpec;
+class GncRecurrence;
+class GncSchedDef;
+class GncSchedule : public GncObject {
+public:
+ GncSchedule ();
+ ~GncSchedule();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ QString name() const { return (var(NAME));};
+ QString enabled() const {return var(ENABLED);};
+ QString autoCreate() const { return (var(AUTOC));};
+ QString autoCrNotify() const { return (var(AUTOCN));};
+ QString autoCrDays() const { return (var(AUTOCD));};
+ QString advCrDays() const { return (var(ADVCD));};
+ QString advCrRemindDays() const { return (var(ADVRD));};
+ QString instanceCount() const { return (var(INSTC));};
+ QString numOccurs() const { return (var(NUMOCC));};
+ QString remOccurs() const { return (var(REMOCC));};
+ QString templId() const { return (var(TEMPLID));};
+ QDate startDate () const
+ {QDate x = QDate(); return (m_vpStartDate == NULL ? x : m_vpStartDate->date());};
+ QDate lastDate () const
+ {QDate x = QDate(); return (m_vpLastDate == NULL ? x : m_vpLastDate->date());};
+ QDate endDate() const
+ {QDate x = QDate(); return (m_vpEndDate == NULL ? x : m_vpEndDate->date());};
+ const GncFreqSpec *getFreqSpec() const { return (m_vpFreqSpec);};
+ const GncSchedDef *getSchedDef() const { return (m_vpSchedDef);};
+private:
+ // subsidiary objects/elements
+ enum ScheduleSubEls {STARTDATE, LASTDATE, ENDDATE, FREQ, RECURRENCE, DEFINST, END_Schedule_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ virtual void terminate();
+ // data elements
+ enum ScheduleDataEls {NAME, ENABLED, AUTOC, AUTOCN, AUTOCD, ADVCD, ADVRD, INSTC,
+ NUMOCC, REMOCC, TEMPLID, END_Schedule_DELS };
+ GncDate *m_vpStartDate, *m_vpLastDate, *m_vpEndDate;
+ GncFreqSpec *m_vpFreqSpec;
+ mutable QPtrList<GncRecurrence> m_vpRecurrence; // gnc handles multiple occurrences
+ GncSchedDef *m_vpSchedDef;
+};
+// ************* GncFreqSpec********************************************
+class GncFreqSpec : public GncObject {
+public:
+ GncFreqSpec ();
+ ~GncFreqSpec();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values (only interval type used at present)
+ QString intervalType() const { return (var(INTVT));};
+private:
+ // subsidiary objects/elements
+ enum FreqSpecSubEls {COMPO, END_FreqSpec_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ // data elements
+ enum FreqSpecDataEls {INTVT, MONTHLY, DAILY, WEEKLY, INTVI, INTVO, INTVD, END_FreqSpec_DELS};
+ virtual void terminate();
+ mutable QPtrList<GncObject> m_fsList;
+};
+
+// ************* GncRecurrence********************************************
+// this object replaces GncFreqSpec from Gnucash 2.2 onwards
+class GncRecurrence : public GncObject {
+public:
+ GncRecurrence ();
+ ~GncRecurrence();
+protected:
+ friend class MyMoneyGncReader;
+ // access data values
+ QDate startDate () const
+ {QDate x = QDate(); return (m_vpStartDate == NULL ? x : m_vpStartDate->date());};
+ QString mult() const {return (var(MULT));};
+ QString periodType() const {return (var(PERIODTYPE));};
+ QString getFrequency() const;
+private:
+ // subsidiary objects/elements
+ enum RecurrenceSubEls {STARTDATE, END_Recurrence_SELS };
+ virtual GncObject *startSubEl();
+ virtual void endSubEl(GncObject *);
+ // data elements
+ enum RecurrenceDataEls {MULT, PERIODTYPE, END_Recurrence_DELS};
+ virtual void terminate();
+ GncDate *m_vpStartDate;
+};
+
+// ************* GncSchedDef********************************************
+// This is a sub-object of GncSchedule, (sx:deferredInstance) function currently unknown
+class GncSchedDef : public GncObject {
+ public:
+ GncSchedDef ();
+ ~GncSchedDef();
+ protected:
+ friend class MyMoneyGncReader;
+ private:
+ // subsidiary objects/elements
+};
+
+// ****************************************************************************************
+/**
+ XML Reader
+ The XML reader is an implementation of the Qt SAX2 XML parser. It determines the type
+ of object represented by the XMl, and calls the appropriate object functions
+*/
+// *****************************************************************************************
+class XmlReader : public QXmlDefaultHandler {
+protected:
+ friend class MyMoneyGncReader;
+ XmlReader (MyMoneyGncReader *pM) : pMain(pM) {} // keep pointer to 'main'
+ void processFile (QIODevice*); // main entry point of reader
+ // define xml content handler functions
+ bool startDocument ();
+ bool startElement (const QString&, const QString&, const QString&, const QXmlAttributes&);
+ bool endElement (const QString&, const QString&, const QString&);
+ bool characters (const QString &);
+ bool endDocument();
+private:
+ QXmlInputSource *m_source;
+ QXmlSimpleReader *m_reader;
+ QPtrStack<GncObject> m_os; // stack of sub objects
+ GncObject *m_co; // current object, for ease of coding (=== m_os.top)
+ MyMoneyGncReader *pMain; // the 'main' pointer, to pass on to objects
+ bool m_headerFound; // check for gnc-v2 header
+#ifdef _GNCFILEANON
+ int lastType; // 0 = start element, 1 = data, 2 = end element
+ int indentCount;
+#endif // _GNCFILEANON
+};
+
+/**
+ * private classes to define messages to be held in list for final report
+ */
+class GncMessageArgs {
+protected:
+ friend class MyMoneyGncReader;
+ QString source; // 'type of message
+ unsigned int code; // to identify actual message
+ QValueList<QString> args; // variable arguments
+};
+
+class GncMessages {
+protected:
+ friend class MyMoneyGncReader;
+ static QString text (const QString, const unsigned int); // returns text of identified message
+ static unsigned int argCount (const QString, const unsigned int); // returns no. of args required
+private:
+ typedef struct {
+ const QString source;
+ const unsigned int code;
+ QString text;
+ }
+ messText;
+ static messText texts [];
+};
+
+/**
+ MyMoneyGncReader - Main class for this module
+ Controls overall operation of the importer
+ */
+
+#ifndef _GNCFILEANON
+class MyMoneyGncReader : public IMyMoneyStorageFormat {
+#else
+class MyMoneyGncReader {
+#endif // _GNCFILEANON
+public:
+ MyMoneyGncReader();
+ virtual ~MyMoneyGncReader();
+ /**
+ * Import a GnuCash XML file
+ *
+ * @param pDevice : pointer to GnuCash file
+ * @param storage : pointer to MyMoneySerialize storage
+ *
+ * @return void
+ *
+ */
+#ifndef _GNCFILEANON
+ void readFile (QIODevice* pDevice, IMyMoneySerialize* storage); // main entry point, IODevice is gnucash file
+ void writeFile (QIODevice*, IMyMoneySerialize*) { return ;}; // dummy entry needed by kmymoneywiew. we will not be writing
+#else
+ void readFile (QString, QString);
+#endif // _GNCFILEANON
+ QTextCodec *m_decoder;
+protected:
+ friend class GncObject; // pity we can't just say GncObject. And compiler doesn't like multiple friends on one line...
+ friend class GncFile; // there must be a better way...
+ friend class GncDate;
+ friend class GncCmdtySpec;
+ friend class GncKvp;
+ friend class GncLot;
+ friend class GncCountData;
+ friend class GncCommodity;
+ friend class GncPrice;
+ friend class GncAccount;
+ friend class GncTransaction;
+ friend class GncSplit;
+ friend class GncTemplateTransaction;
+ friend class GncTemplateSplit;
+ friend class GncSchedule;
+ friend class GncFreqSpec;
+ friend class GncRecurrence;
+ friend class XmlReader;
+#ifndef _GNCFILEANON
+ /** functions to convert gnc objects to our equivalent */
+ void convertCommodity (const GncCommodity *);
+ void convertPrice (const GncPrice *);
+ void convertAccount (const GncAccount *);
+ void convertTransaction (const GncTransaction *);
+ void convertSplit (const GncSplit *);
+ void saveTemplateTransaction (GncTransaction *t) {m_templateList.append (t);};
+ void convertSchedule (const GncSchedule *);
+ void convertFreqSpec (const GncFreqSpec *);
+ void convertRecurrence (const GncRecurrence *);
+#else
+ /** functions to convert gnc objects to our equivalent */
+ void convertCommodity (const GncCommodity *) {return;};
+ void convertPrice (const GncPrice *) {return;};
+ void convertAccount (const GncAccount *) {return;};
+ void convertTransaction (const GncTransaction *) {return;};
+ void convertSplit (const GncSplit *) {return;};
+ void saveTemplateTransaction (GncTransaction *t) {return;};
+ void convertSchedule (const GncSchedule *) {return;};
+ void convertFreqSpec (const GncFreqSpec *) {return;};
+#endif // _GNCFILEANON
+/** to post messages for final report */
+ void postMessage (const QString&, const unsigned int, const char *);
+ void postMessage (const QString&, const unsigned int, const char *, const char *);
+ void postMessage (const QString&, const unsigned int, const char *, const char *, const char *);
+ void postMessage (const QString&, const unsigned int, const QStringList&);
+ void setProgressCallback (void(*callback)(int, int, const QString&));
+ void signalProgress (int current, int total, const QString& = "");
+ /** user options */
+ /**
+ Scheduled Transactions
+ Due to differences in implementation, it is not always possible to import scheduled
+ transactions correctly. Though best efforts are made, it may be that some
+ imported transactions cause problems within kmymoney.
+ An attempt is made within the importer to identify potential problem transactions,
+ and setting this option will cause them to be dropped from the file.
+ A report of which were dropped, and why, will be produced.
+ m_dropSuspectSchedules - drop suspect scheduled transactions
+ */
+ bool m_dropSuspectSchedules;
+ /**
+ Investments
+ In kmymoney, all accounts representing investments (stocks, shares, bonds, etc.) must
+ have an associated investment account (e.g. a broker account). The stock account holds
+ the share balance, the investment account a money balance.
+ Gnucash does not do this, so we cannot automate this function. If you have investments,
+ you must select one of the following options.
+ 0 - create a separate investment account for each stock with the same name as the stock
+ 1 - create a single investment account to hold all stocks - you will be asked for a name
+ 2 - create multiple investment accounts - you will be asked for a name for each stock
+ N.B. :- option 2 doesn't really work quite as desired at present
+ */
+ unsigned int m_investmentOption;
+ /** Online quotes
+ The user has the option to use the Finance::Quote system, as used by GnuCash, to
+ retrieve online share price quotes
+ */
+ bool m_useFinanceQuote;
+ /** Tx Notes handling
+ Under some usage conditions, non-split GnuCash transactions may contain residual, usually incorrect, memo
+ data which is not normally visible to the user. When imported into KMyMoney however, due to display
+ differences, this data can become visible. Often, these transactions will have a Notes field describing
+ the real purpose of the transaction. If this option is selected, these notes, if present, will be used to
+ override the extraneous memo data." */
+ bool m_useTxNotes;
+ // set gnucash counts (not always accurate!)
+ void setGncCommodityCount(int i) { m_gncCommodityCount = i;};
+ void setGncAccountCount (int i) { m_gncAccountCount = i;};
+ void setGncTransactionCount (int i) { m_gncTransactionCount = i;};
+ void setGncScheduleCount (int i) { m_gncScheduleCount = i;};
+ void setSmallBusinessFound (bool b) { m_smallBusinessFound = b;};
+ void setBudgetsFound (bool b) { m_budgetsFound = b;};
+ void setLotsFound (bool b) { m_lotsFound = b;};
+ /* Debug Options
+ If you don't know what these are, best leave them alone.
+ gncdebug - produce general debug messages
+ xmldebug - produce a trace of the gnucash file XML
+ bAnonymize - hide personal data (account names, payees, etc., randomize money amounts)
+ */
+ bool gncdebug; // general debug messages
+ bool xmldebug; // xml trace
+ bool bAnonymize; // anonymize input
+ static double m_fileHideFactor; // an overall anonymization factor to be applied to all items
+ bool developerDebug;
+private:
+ void setOptions (); // to set user options from dialog
+ void setFileHideFactor ();
+ // the following handles the gnucash indicator for a bad value (-1/0) which causes us probs
+ QString convBadValue (QString gncValue) const {return (gncValue == "-1/0" ? "0/1" : gncValue); };
+#ifndef _GNCFILEANON
+ MyMoneyTransaction convertTemplateTransaction (const QString&, const GncTransaction *);
+ void convertTemplateSplit (const QString&, const GncTemplateSplit *);
+#endif // _GNCFILEANON
+ // wind up when all done
+ void terminate();
+ QString buildReportSection (const QString&);
+ bool writeReportToFile (const QValueList<QString>&);
+ // main storage
+#ifndef _GNCFILEANON
+ IMyMoneyStorage *m_storage;
+#else
+ QTextStream oStream;
+#endif // _GNCFILEANON
+ XmlReader *m_xr;
+ /** to hold the callback pointer for the progress bar */
+ void (*m_progressCallback)(int, int, const QString&);
+ // a map of which versions of the various elements (objects) we can import
+ map_elementVersions m_versionList;
+ // counters holding count data from the Gnc 'count-data' section
+ int m_gncCommodityCount;
+ int m_gncAccountCount;
+ int m_gncTransactionCount;
+ int m_gncScheduleCount;
+
+ // flags indicating detection of features not (yet?) supported
+ bool m_smallBusinessFound;
+ bool m_budgetsFound;
+ bool m_lotsFound;
+
+ /** counters for reporting */
+ int m_commodityCount;
+ int m_priceCount;
+ int m_accountCount;
+ int m_transactionCount;
+ int m_templateCount;
+ int m_scheduleCount;
+#ifndef _GNCFILEANON
+ // counters for error reporting
+ int m_ccCount, m_orCount, m_scCount;
+ // currency counter
+ QMap<QString, unsigned int> m_currencyCount;
+ /**
+ * Map gnucash vs. Kmm ids for accounts, equities, schedules, price sources
+ */
+ QMap<QString, QString> m_mapIds;
+ QString m_rootId; // save the root id for terminate()
+ QMap<QString, QString> m_mapEquities;
+ QMap<QString, QString> m_mapSchedules;
+ QMap<QString, QString> m_mapSources;
+ /**
+ * A list of stock accounts (gnc ids) which will be held till the end
+ so we can implement the user's investment option
+ */
+ QValueList<QString> m_stockList;
+ /**
+ * Temporary storage areas for transaction processing
+ */
+ QString m_txCommodity; // save commodity for current transaction
+ QString m_txPayeeId; // gnc has payee at tx level, we need it at split level
+ QDate m_txDatePosted; // ditto for post date
+ QString m_txChequeNo; // ditto for cheque number
+ /** In kmm, the order of splits is critical to some operations. These
+ * areas will hold the splits until we've read them all */
+ QValueList<MyMoneySplit> m_splitList, m_liabilitySplitList, m_otherSplitList;
+ bool m_potentialTransfer; // to determine whether this might be a transfer
+ /** Schedules are processed through 3 different functions, any of which may set this flag */
+ bool m_suspectSchedule;
+ /**
+ * A holding area for template txs while we're waiting for the schedules
+ */
+ QPtrList<GncTransaction> m_templateList;
+ /** Hold a list of suspect schedule ids for later processing? */
+ QValueList<QString> m_suspectList;
+ /**
+ * To hold message data till final report
+ */
+ QPtrList<GncMessageArgs> m_messageList;
+ GncMessages *m_messageTexts;
+ /**
+ * Internal utility functions
+ */
+ QString createPayee (const QString&); // create a payee and return it's id
+ QString createOrphanAccount (const QString&); // create unknown account and return the id
+ QDate incrDate (QDate lastDate, unsigned char interval, unsigned int intervalCount); // for date calculations
+ MyMoneyAccount checkConsistency (MyMoneyAccount& parent, MyMoneyAccount& child); // gnucash is sometimes TOO flexible
+ void checkInvestmentOption (QString stockId); // implement user investment option
+ void getPriceSource (MyMoneySecurity stock, QString gncSource);
+#endif // _GNCFILEANON
+};
+
+#endif // MYMONEYSTORAGEGNC_H
diff --git a/kmymoney2/converter/mymoneyqifprofile.cpp b/kmymoney2/converter/mymoneyqifprofile.cpp
new file mode 100644
index 0000000..b8fe97c
--- /dev/null
+++ b/kmymoney2/converter/mymoneyqifprofile.cpp
@@ -0,0 +1,1013 @@
+/***************************************************************************
+ mymoneyqifprofile.cpp - description
+ -------------------
+ begin : Tue Dec 24 2002
+ copyright : (C) 2002 by Thomas Baumgart
+ email : thb@net-bembel.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregexp.h>
+#include <qvaluevector.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kcalendarsystem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyqifprofile.h"
+#include "../mymoney/mymoneyexception.h"
+#include "../mymoney/mymoneymoney.h"
+
+/*
+ * CENTURY_BREAK is used to identfy the century for a two digit year
+ *
+ * if yr is < CENTURY_BREAK it is in 2000
+ * if yr is >= CENTURY_BREAK it is in 1900
+ *
+ * so with CENTURY_BREAK being 70 the following will happen:
+ *
+ * 00..69 -> 2000..2069
+ * 70..99 -> 1970..1999
+ */
+#define CENTURY_BREAK 70
+
+class MyMoneyQifProfile::Private {
+ public:
+ Private() {
+ m_changeCount.resize(3, 0);
+ m_lastValue.resize(3, 0);
+ m_largestValue.resize(3, 0);
+ }
+
+ void getThirdPosition(void);
+ void dissectDate(QValueVector<QString>& parts, const QString& txt) const;
+
+ QValueVector<int> m_changeCount;
+ QValueVector<int> m_lastValue;
+ QValueVector<int> m_largestValue;
+ QMap<QChar, int> m_partPos;
+};
+
+void MyMoneyQifProfile::Private::dissectDate(QValueVector<QString>& parts, const QString& txt) const
+{
+ QRegExp nonDelimChars("[ 0-9a-zA-Z]");
+ int part = 0; // the current part we scan
+ unsigned int pos; // the current scan position
+ unsigned int maxPartSize = txt.length() > 6 ? 4 : 2;
+ // the maximum size of a part
+ // some fu... up MS-Money versions write two delimiter in a row
+ // so we need to keep track of them. Example: D14/12/'08
+ bool lastWasDelim = false;
+
+ // separate the parts of the date and keep the locations of the delimiters
+ for(pos = 0; pos < txt.length() && part < 3; ++pos) {
+ if(nonDelimChars.search(txt[pos]) == -1) {
+ if(!lastWasDelim) {
+ ++part;
+ maxPartSize = 0; // make sure to pick the right one depending if next char is numeric or not
+ lastWasDelim = true;
+ }
+ } else {
+ lastWasDelim = false;
+ // check if the part is over and we did not see a delimiter
+ if((maxPartSize != 0) && (parts[part].length() == maxPartSize)) {
+ ++part;
+ maxPartSize = 0;
+ }
+ if(maxPartSize == 0) {
+ maxPartSize = txt[pos].isDigit() ? 2 : 3;
+ if(part == 2)
+ maxPartSize = 4;
+ }
+ if(part < 3)
+ parts[part] += txt[pos];
+ }
+ }
+
+ if(part == 3) { // invalid date
+ for(int i = 0; i < 3; ++i) {
+ parts[i] = "0";
+ }
+ }
+}
+
+
+void MyMoneyQifProfile::Private::getThirdPosition(void)
+{
+ // if we have detected two parts we can calculate the third and its position
+ if(m_partPos.count() == 2) {
+ QValueList<QChar> partsPresent = m_partPos.keys();
+ QStringList partsAvail = QStringList::split(",", "d,m,y");
+ int missingIndex = -1;
+ int value = 0;
+ for(int i = 0; i < 3; ++i) {
+ if(!partsPresent.contains(partsAvail[i][0])) {
+ missingIndex = i;
+ } else {
+ value += m_partPos[partsAvail[i][0]];
+ }
+ }
+ m_partPos[partsAvail[missingIndex][0]] = 3 - value;
+ }
+}
+
+
+
+MyMoneyQifProfile::MyMoneyQifProfile() :
+ d(new Private),
+ m_isDirty(false)
+{
+ clear();
+}
+
+MyMoneyQifProfile::MyMoneyQifProfile(const QString& name) :
+ d(new Private),
+ m_isDirty(false)
+{
+ loadProfile(name);
+}
+
+MyMoneyQifProfile::~MyMoneyQifProfile()
+{
+ delete d;
+}
+
+void MyMoneyQifProfile::clear(void)
+{
+ m_dateFormat = "%d.%m.%yyyy";
+ m_apostropheFormat = "2000-2099";
+ m_valueMode = "";
+ m_filterScriptImport = "";
+ m_filterScriptExport = "";
+ m_filterFileType = "*.qif";
+
+ m_decimal.clear();
+ m_decimal['$'] =
+ m_decimal['Q'] =
+ m_decimal['T'] =
+ m_decimal['O'] =
+ m_decimal['I'] = KGlobal::locale()->monetaryDecimalSymbol()[0];
+
+ m_thousands.clear();
+ m_thousands['$'] =
+ m_thousands['Q'] =
+ m_thousands['T'] =
+ m_thousands['O'] =
+ m_thousands['I'] = KGlobal::locale()->monetaryThousandsSeparator()[0];
+
+ m_openingBalanceText = "Opening Balance";
+ m_voidMark = "VOID ";
+ m_accountDelimiter = "[";
+
+ m_profileName = "";
+ m_profileDescription = "";
+ m_profileType = "Bank";
+
+ m_attemptMatchDuplicates = true;
+}
+
+void MyMoneyQifProfile::loadProfile(const QString& name)
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup(name);
+
+ clear();
+
+ m_profileName = name;
+ m_profileDescription = config->readEntry("Description", m_profileDescription);
+ m_profileType = config->readEntry("Type", m_profileType);
+ m_dateFormat = config->readEntry("DateFormat", m_dateFormat);
+ m_apostropheFormat = config->readEntry("ApostropheFormat", m_apostropheFormat);
+ m_accountDelimiter = config->readEntry("AccountDelimiter", m_accountDelimiter);
+ m_openingBalanceText = config->readEntry("OpeningBalance", m_openingBalanceText);
+ m_voidMark = config->readEntry("VoidMark", m_voidMark);
+ m_filterScriptImport = config->readEntry("FilterScriptImport", m_filterScriptImport);
+ m_filterScriptExport = config->readEntry("FilterScriptExport", m_filterScriptExport);
+ m_filterFileType = config->readEntry("FilterFileType",m_filterFileType);
+
+ m_attemptMatchDuplicates = config->readBoolEntry("AttemptMatchDuplicates", m_attemptMatchDuplicates);
+
+ // make sure, we remove any old stuff for now
+ config->deleteEntry("FilterScript");
+
+ QString tmp = QString(m_decimal['Q']) + m_decimal['T'] + m_decimal['I'] +
+ m_decimal['$'] + m_decimal['O'];
+ tmp = config->readEntry("Decimal", tmp);
+ m_decimal['Q'] = tmp[0];
+ m_decimal['T'] = tmp[1];
+ m_decimal['I'] = tmp[2];
+ m_decimal['$'] = tmp[3];
+ m_decimal['O'] = tmp[4];
+
+ tmp = QString(m_thousands['Q']) + m_thousands['T'] + m_thousands['I'] +
+ m_thousands['$'] + m_thousands['O'];
+ tmp = config->readEntry("Thousand", tmp);
+ m_thousands['Q'] = tmp[0];
+ m_thousands['T'] = tmp[1];
+ m_thousands['I'] = tmp[2];
+ m_thousands['$'] = tmp[3];
+ m_thousands['O'] = tmp[4];
+
+ m_isDirty = false;
+}
+
+void MyMoneyQifProfile::saveProfile(void)
+{
+ if(m_isDirty == true) {
+ KConfig* config = KGlobal::config();
+ config->setGroup(m_profileName);
+
+ config->writeEntry("Description", m_profileDescription);
+ config->writeEntry("Type", m_profileType);
+ config->writeEntry("DateFormat", m_dateFormat);
+ config->writeEntry("ApostropheFormat", m_apostropheFormat);
+ config->writeEntry("AccountDelimiter", m_accountDelimiter);
+ config->writeEntry("OpeningBalance", m_openingBalanceText);
+ config->writeEntry("VoidMark", m_voidMark);
+ config->writeEntry("FilterScriptImport", m_filterScriptImport);
+ config->writeEntry("FilterScriptExport", m_filterScriptExport);
+ config->writeEntry("FilterFileType", m_filterFileType);
+ config->writeEntry("AttemptMatchDuplicates", m_attemptMatchDuplicates);
+
+ QString tmp;
+
+ tmp = QString(m_decimal['Q']) + m_decimal['T'] + m_decimal['I'] +
+ m_decimal['$'] + m_decimal['O'];
+ config->writeEntry("Decimal", tmp);
+ tmp = QString(m_thousands['Q']) + m_thousands['T'] + m_thousands['I'] +
+ m_thousands['$'] + m_thousands['O'];
+ config->writeEntry("Thousand", tmp);
+ }
+ m_isDirty = false;
+}
+
+void MyMoneyQifProfile::setProfileName(const QString& name)
+{
+ if(m_profileName != name)
+ m_isDirty = true;
+
+ m_profileName = name;
+}
+
+void MyMoneyQifProfile::setProfileDescription(const QString& desc)
+{
+ if(m_profileDescription != desc)
+ m_isDirty = true;
+
+ m_profileDescription = desc;
+}
+
+void MyMoneyQifProfile::setProfileType(const QString& type)
+{
+ if(m_profileType != type)
+ m_isDirty = true;
+ m_profileType = type;
+}
+
+void MyMoneyQifProfile::setOutputDateFormat(const QString& dateFormat)
+{
+ if(m_dateFormat != dateFormat)
+ m_isDirty = true;
+
+ m_dateFormat = dateFormat;
+}
+
+void MyMoneyQifProfile::setInputDateFormat(const QString& dateFormat)
+{
+ int j = -1;
+ if(dateFormat.length() > 0) {
+ for(unsigned int i = 0; i < dateFormat.length()-1; ++i) {
+ if(dateFormat[i] == '%') {
+ d->m_partPos[dateFormat[++i]] = ++j;
+ }
+ }
+ }
+}
+
+void MyMoneyQifProfile::setApostropheFormat(const QString& apostropheFormat)
+{
+ if(m_apostropheFormat != apostropheFormat)
+ m_isDirty = true;
+
+ m_apostropheFormat = apostropheFormat;
+}
+
+void MyMoneyQifProfile::setAmountDecimal(const QChar& def, const QChar& chr)
+{
+ QChar ch(chr);
+ if(ch == QChar())
+ ch = ' ';
+
+ if(m_decimal[def] != ch)
+ m_isDirty = true;
+
+ m_decimal[def] = ch;
+}
+
+void MyMoneyQifProfile::setAmountThousands(const QChar& def, const QChar& chr)
+{
+ QChar ch(chr);
+ if(ch == QChar())
+ ch = ' ';
+
+ if(m_thousands[def] != ch)
+ m_isDirty = true;
+
+ m_thousands[def] = ch;
+}
+
+QChar MyMoneyQifProfile::amountDecimal(const QChar& def) const
+{
+ QChar chr = m_decimal[def];
+ return chr;
+}
+
+QChar MyMoneyQifProfile::amountThousands(const QChar& def) const
+{
+ QChar chr = m_thousands[def];
+ return chr;
+}
+
+void MyMoneyQifProfile::setAccountDelimiter(const QString& delim)
+{
+ QString txt(delim);
+
+ if(txt.isEmpty())
+ txt = " ";
+ else if(txt[0] != '[')
+ txt = "[";
+
+ if(m_accountDelimiter[0] != txt[0])
+ m_isDirty = true;
+ m_accountDelimiter = txt[0];
+}
+
+void MyMoneyQifProfile::setOpeningBalanceText(const QString& txt)
+{
+ if(m_openingBalanceText != txt)
+ m_isDirty = true;
+ m_openingBalanceText = txt;
+}
+
+void MyMoneyQifProfile::setVoidMark(const QString& txt)
+{
+ if(m_voidMark != txt)
+ m_isDirty = true;
+ m_voidMark = txt;
+}
+
+QString MyMoneyQifProfile::accountDelimiter(void) const
+{
+ QString rc;
+
+ switch(m_accountDelimiter[0]) {
+ case ' ':
+ rc = " ";
+ break;
+ default:
+ rc = "[]";
+ break;
+ }
+ return rc;
+}
+
+QString MyMoneyQifProfile::date(const QDate& datein) const
+{
+ const char* format = m_dateFormat.latin1();
+ QString buffer;
+ QChar delim;
+ int maskLen;
+ char maskChar;
+
+ while(*format) {
+ switch(*format) {
+ case '%':
+ maskLen = 0;
+ maskChar = *++format;
+ while(*format && *format == maskChar) {
+ ++maskLen;
+ ++format;
+ }
+
+ switch(maskChar) {
+ case 'd':
+ if(delim)
+ buffer += delim;
+ buffer += QString::number(datein.day()).rightJustify(2, '0');
+ break;
+
+ case 'm':
+ if(delim)
+ buffer += delim;
+ if(maskLen == 3)
+ buffer += KGlobal::locale()->calendar()->monthName(datein.month(), datein.year(), true);
+ else
+ buffer += QString::number(datein.month()).rightJustify(2, '0');
+ break;
+
+ case 'y':
+ if(maskLen == 2) {
+ buffer += twoDigitYear(delim, datein.year());
+ } else {
+ if(delim)
+ buffer += delim;
+ buffer += QString::number(datein.year());
+ }
+ break;
+ default:
+ throw new MYMONEYEXCEPTION("Invalid char in QifProfile date field");
+ break;
+ }
+ delim = 0;
+ break;
+
+ default:
+ if(delim)
+ buffer += delim;
+ delim = *format++;
+ break;
+ }
+ }
+ return buffer;
+}
+
+const QDate MyMoneyQifProfile::date(const QString& datein) const
+{
+ // in case we don't know the format, we return an invalid date
+ if(d->m_partPos.count() != 3)
+ return QDate();
+
+ QValueVector<QString> scannedParts(3);
+ d->dissectDate(scannedParts, datein);
+
+ int yr, mon, day;
+ bool ok;
+ yr = scannedParts[d->m_partPos['y']].toInt();
+ mon = scannedParts[d->m_partPos['m']].toInt(&ok);
+ if(!ok) {
+ QStringList monthNames = QStringList::split(",", "jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec");
+ int j;
+ for(j = 1; j <= 12; ++j) {
+ if((KGlobal::locale()->calendar()->monthName(j, 2000, true).lower() == scannedParts[d->m_partPos['m']].lower())
+ || (monthNames[j-1] == scannedParts[d->m_partPos['m']].lower())) {
+ mon = j;
+ break;
+ }
+ }
+ if(j == 13) {
+ qWarning("Unknown month '%s'", scannedParts[d->m_partPos['m']].data());
+ return QDate();
+ }
+ }
+
+ day = scannedParts[d->m_partPos['d']].toInt();
+ if(yr < 100) { // two digit year information?
+ if(yr < CENTURY_BREAK) // less than the CENTURY_BREAK we assume this century
+ yr += 2000;
+ else
+ yr += 1900;
+ }
+ return QDate(yr, mon, day);
+
+#if 0
+ QString scannedDelim[2];
+ QString formatParts[3];
+ QString formatDelim[2];
+ int part;
+ int delim;
+ unsigned int i,j;
+
+ part = -1;
+ delim = 0;
+ for(i = 0; i < m_dateFormat.length(); ++i) {
+ if(m_dateFormat[i] == '%') {
+ ++part;
+ if(part == 3) {
+ qWarning("MyMoneyQifProfile::date(const QString& datein) Too many parts in date format");
+ return QDate();
+ }
+ ++i;
+ }
+ switch(m_dateFormat[i].latin1()) {
+ case 'm':
+ case 'd':
+ case 'y':
+ formatParts[part] += m_dateFormat[i];
+ break;
+ case '/':
+ case '-':
+ case '.':
+ case '\'':
+ if(delim == 2) {
+ qWarning("MyMoneyQifProfile::date(const QString& datein) Too many delimiters in date format");
+ return QDate();
+ }
+ formatDelim[delim] = m_dateFormat[i];
+ ++delim;
+ break;
+ default:
+ qWarning("MyMoneyQifProfile::date(const QString& datein) Invalid char in date format");
+ return QDate();
+ }
+ }
+
+
+ part = 0;
+ delim = 0;
+ bool prevWasChar = false;
+ for(i = 0; i < datein.length(); ++i) {
+ switch(datein[i].latin1()) {
+ case '/':
+ case '.':
+ case '-':
+ case '\'':
+ if(delim == 2) {
+ qWarning("MyMoneyQifProfile::date(const QString& datein) Too many delimiters in date field");
+ return QDate();
+ }
+ scannedDelim[delim] = datein[i];
+ ++delim;
+ ++part;
+ prevWasChar = false;
+ break;
+
+ default:
+ if(prevWasChar && datein[i].isDigit()) {
+ ++part;
+ prevWasChar = false;
+ }
+ if(datein[i].isLetter())
+ prevWasChar = true;
+ // replace blank with 0
+ scannedParts[part] += (datein[i] == ' ') ? QChar('0') : datein[i];
+ break;
+ }
+ }
+
+ int day = 1,
+ mon = 1,
+ yr = 1900;
+ bool ok = false;
+ for(i = 0; i < 2; ++i) {
+ if(scannedDelim[i] != formatDelim[i]
+ && scannedDelim[i] != QChar('\'')) {
+ qWarning("MyMoneyQifProfile::date(const QString& datein) Invalid delimiter '%s' when '%s' was expected",
+ scannedDelim[i].latin1(), formatDelim[i].latin1());
+ return QDate();
+ }
+ }
+
+ QString msg;
+ for(i = 0; i < 3; ++i) {
+ switch(formatParts[i][0].latin1()) {
+ case 'd':
+ day = scannedParts[i].toUInt(&ok);
+ if (!ok)
+ msg = "Invalid numeric character in day string";
+ break;
+ case 'm':
+ if(formatParts[i].length() != 3) {
+ mon = scannedParts[i].toUInt(&ok);
+ if (!ok)
+ msg = "Invalid numeric character in month string";
+ } else {
+ for(j = 1; j <= 12; ++j) {
+ if(KGlobal::locale()->calendar()->monthName(j, 2000, true).lower() == formatParts[i].lower()) {
+ mon = j;
+ ok = true;
+ break;
+ }
+ }
+ if(j == 13) {
+ msg = "Unknown month '" + scannedParts[i] + "'";
+ }
+ }
+ break;
+ case 'y':
+ ok = false;
+ if(scannedParts[i].length() == formatParts[i].length()) {
+ yr = scannedParts[i].toUInt(&ok);
+ if (!ok)
+ msg = "Invalid numeric character in month string";
+ if(yr < 100) { // two digit year info
+ if(i > 1) {
+ ok = true;
+ if(scannedDelim[i-1] == QChar('\'')) {
+ if(m_apostropheFormat == "1900-1949") {
+ if(yr < 50)
+ yr += 1900;
+ else
+ yr += 2000;
+ } else if(m_apostropheFormat == "1900-1999") {
+ yr += 1900;
+ } else if(m_apostropheFormat == "2000-2099") {
+ yr += 2000;
+ } else {
+ msg = "Unsupported apostropheFormat!";
+ ok = false;
+ }
+ } else {
+ if(m_apostropheFormat == "1900-1949") {
+ if(yr < 50)
+ yr += 2000;
+ else
+ yr += 1900;
+ } else if(m_apostropheFormat == "1900-1999") {
+ yr += 2000;
+ } else if(m_apostropheFormat == "2000-2099") {
+ yr += 1900;
+ } else {
+ msg = "Unsupported apostropheFormat!";
+ ok = false;
+ }
+ }
+ } else {
+ msg = "Year as first parameter is not supported!";
+ }
+ } else if(yr < 1900) {
+ msg = "Year not in range < 100 or >= 1900!";
+ } else {
+ ok = true;
+ }
+ } else {
+ msg = QString("Length of year (%1) does not match expected length (%2).")
+ .arg(scannedParts[i].length()).arg(formatParts[i].length());
+ }
+ break;
+ }
+ if(!msg.isEmpty()) {
+ qWarning("MyMoneyQifProfile::date(const QString& datein) %s",msg.latin1());
+ return QDate();
+ }
+ }
+ return QDate(yr, mon, day);
+#endif
+}
+
+QString MyMoneyQifProfile::twoDigitYear(const QChar delim, int yr) const
+{
+ QChar realDelim = delim;
+ QString buffer;
+
+ if(delim) {
+ if((m_apostropheFormat == "1900-1949" && yr <= 1949)
+ || (m_apostropheFormat == "1900-1999" && yr <= 1999)
+ || (m_apostropheFormat == "2000-2099" && yr >= 2000))
+ realDelim = '\'';
+ buffer += realDelim;
+ }
+ yr -= 1900;
+ if(yr > 100)
+ yr -= 100;
+
+ if(yr < 10)
+ buffer += "0";
+
+ buffer += QString::number(yr);
+ return buffer;
+}
+
+QString MyMoneyQifProfile::value(const QChar& def, const MyMoneyMoney& valuein) const
+{
+ unsigned char _decimalSeparator;
+ unsigned char _thousandsSeparator;
+ QString res;
+
+ _decimalSeparator = MyMoneyMoney::decimalSeparator();
+ _thousandsSeparator = MyMoneyMoney::thousandSeparator();
+ MyMoneyMoney::signPosition _signPosition = MyMoneyMoney::negativeMonetarySignPosition();
+
+ MyMoneyMoney::setDecimalSeparator(amountDecimal(def));
+ MyMoneyMoney::setThousandSeparator(amountThousands(def));
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+
+ res = valuein.formatMoney("", 2);
+
+ MyMoneyMoney::setDecimalSeparator(_decimalSeparator);
+ MyMoneyMoney::setThousandSeparator(_thousandsSeparator);
+ MyMoneyMoney::setNegativeMonetarySignPosition(_signPosition);
+
+ return res;
+}
+
+MyMoneyMoney MyMoneyQifProfile::value(const QChar& def, const QString& valuein) const
+{
+ unsigned char _decimalSeparator;
+ unsigned char _thousandsSeparator;
+ MyMoneyMoney res;
+
+ _decimalSeparator = MyMoneyMoney::decimalSeparator();
+ _thousandsSeparator = MyMoneyMoney::thousandSeparator();
+ MyMoneyMoney::signPosition _signPosition = MyMoneyMoney::negativeMonetarySignPosition();
+
+ MyMoneyMoney::setDecimalSeparator(amountDecimal(def));
+ MyMoneyMoney::setThousandSeparator(amountThousands(def));
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+
+ res = MyMoneyMoney(valuein);
+
+ MyMoneyMoney::setDecimalSeparator(_decimalSeparator);
+ MyMoneyMoney::setThousandSeparator(_thousandsSeparator);
+ MyMoneyMoney::setNegativeMonetarySignPosition(_signPosition);
+
+ return res;
+}
+
+void MyMoneyQifProfile::setFilterScriptImport(const QString& script)
+{
+ if(m_filterScriptImport != script)
+ m_isDirty = true;
+
+ m_filterScriptImport = script;
+}
+
+void MyMoneyQifProfile::setFilterScriptExport(const QString& script)
+{
+ if(m_filterScriptExport != script)
+ m_isDirty = true;
+
+ m_filterScriptExport = script;
+}
+
+void MyMoneyQifProfile::setFilterFileType(const QString& txt)
+{
+ if(m_filterFileType != txt)
+ m_isDirty = true;
+
+ m_filterFileType = txt;
+}
+
+void MyMoneyQifProfile::setAttemptMatchDuplicates(bool f)
+{
+ if ( m_attemptMatchDuplicates != f )
+ m_isDirty = true;
+
+ m_attemptMatchDuplicates = f;
+}
+
+QString MyMoneyQifProfile::inputDateFormat(void) const
+{
+ QStringList list;
+ possibleDateFormats(list);
+ if(list.count() == 1)
+ return list.first();
+ return QString();
+}
+
+void MyMoneyQifProfile::possibleDateFormats(QStringList& list) const
+{
+ QStringList defaultList = QStringList::split(":", "y,m,d:y,d,m:m,d,y:m,y,d:d,m,y:d,y,m");
+ list.clear();
+ QStringList::const_iterator it_d;
+ for(it_d = defaultList.begin(); it_d != defaultList.end(); ++it_d) {
+ QStringList parts = QStringList::split(",", *it_d);
+ int i;
+ for(i = 0; i < 3; ++i) {
+ if(d->m_partPos.contains(parts[i][0])) {
+ if(d->m_partPos[parts[i][0]] != i)
+ break;
+ }
+ // months can't be larger than 12
+ if(parts[i] == "m" && d->m_largestValue[i] > 12)
+ break;
+ // days can't be larger than 31
+ if(parts[i] == "d" && d->m_largestValue[i] > 31)
+ break;
+ }
+ // matches all tests
+ if(i == 3) {
+ QString format = *it_d;
+ format.replace('y', "%y");
+ format.replace('m', "%m");
+ format.replace('d', "%d");
+ format.replace(',', " ");
+ list << format;
+ }
+ }
+ // if we haven't found any, then there's something wrong.
+ // in this case, we present the full list and let the user decide
+ if(list.count() == 0) {
+ for(it_d = defaultList.begin(); it_d != defaultList.end(); ++it_d) {
+ QString format = *it_d;
+ format.replace('y', "%y");
+ format.replace('m', "%m");
+ format.replace('d', "%d");
+ format.replace(',', " ");
+ list << format;
+ }
+ }
+}
+
+void MyMoneyQifProfile::autoDetect(const QStringList& lines)
+{
+ m_dateFormat = QString();
+ m_decimal.clear();
+ m_thousands.clear();
+
+ QString numericRecords = "BT$OIQ";
+ QStringList::const_iterator it;
+ int datesScanned = 0;
+ // section: used to switch between different QIF sections,
+ // because the Record identifiers are ambigous between sections
+ // eg. in transaction records, T identifies a total amount, in
+ // account sections it's the type.
+ //
+ // 0 - unknown
+ // 1 - account
+ // 2 - transactions
+ // 3 - prices
+ int section = 0;
+ QRegExp price("\"(.*)\",(.*),\"(.*)\"");
+ for(it = lines.begin(); it != lines.end(); ++it) {
+ QChar c((*it)[0]);
+ if(c == '!') {
+ QString sname = (*it).lower();
+ section = 0;
+ if(sname.startsWith("!account"))
+ section = 1;
+ else if(sname.startsWith("!type")) {
+ if(sname.startsWith("!type:cat")
+ || sname.startsWith("!type:payee")
+ || sname.startsWith("!type:security")
+ || sname.startsWith("!type:class")) {
+ section = 0;
+ } else if(sname.startsWith("!type:price")) {
+ section = 3;
+ } else
+ section = 2;
+ }
+ }
+
+ switch(section) {
+ case 1:
+ if(c == 'B') {
+ scanNumeric((*it).mid(1), m_decimal[c], m_thousands[c]);
+ }
+ break;
+ case 2:
+ if(numericRecords.contains(c)) {
+ scanNumeric((*it).mid(1), m_decimal[c], m_thousands[c]);
+ } else if((c == 'D') && (m_dateFormat.isEmpty())) {
+ if(d->m_partPos.count() != 3) {
+ scanDate((*it).mid(1));
+ ++datesScanned;
+ if(d->m_partPos.count() == 2) {
+ // if we have detected two parts we can calculate the third and its position
+ d->getThirdPosition();
+ }
+ }
+ }
+ break;
+ case 3:
+ if(price.search(*it) != -1) {
+ scanNumeric(price.cap(2), m_decimal['P'], m_thousands['P']);
+ scanDate(price.cap(3));
+ ++datesScanned;
+ }
+ break;
+ }
+ }
+
+ // the following algorithm is only applied if we have more
+ // than 20 dates found. Smaller numbers have shown that the
+ // results are inaccurate which leads to a reduced number of
+ // date formats presented to choose from.
+ if(d->m_partPos.count() != 3 && datesScanned > 20) {
+ QMap<int, int> sortedPos;
+ // make sure to reset the known parts for the following algorithm
+ if(d->m_partPos.contains('y')) {
+ d->m_changeCount[d->m_partPos['y']] = -1;
+ for(int i = 0; i < 3; ++i) {
+ if(d->m_partPos['y'] == i)
+ continue;
+ // can we say for sure that we hit the day field?
+ if(d->m_largestValue[i] > 12) {
+ d->m_partPos['d'] = i;
+ }
+ }
+ }
+ if(d->m_partPos.contains('d'))
+ d->m_changeCount[d->m_partPos['d']] = -1;
+ if(d->m_partPos.contains('m'))
+ d->m_changeCount[d->m_partPos['m']] = -1;
+
+ for(int i = 0; i < 3; ++i) {
+ if(d->m_changeCount[i] != -1) {
+ sortedPos[d->m_changeCount[i]] = i;
+ }
+ }
+
+ QMap<int, int>::const_iterator it_a;
+ QMap<int, int>::const_iterator it_b;
+ switch(sortedPos.count()) {
+ case 1: // all the same
+ // let the user decide, we can't figure it out
+ break;
+
+ case 2: // two are the same, we treat the largest as the day
+ // if it's 20% larger than the other one and let the
+ // user pick the other two
+ {
+ it_b = sortedPos.begin();
+ it_a = it_b;
+ ++it_b;
+ double a = d->m_changeCount[*it_a];
+ double b = d->m_changeCount[*it_b];
+ if(b > (a * 1.2)) {
+ d->m_partPos['d'] = *it_b;
+ }
+ }
+ break;
+
+ case 3: // three different, we check if they are 20% apart each
+ it_b = sortedPos.begin();
+ for(int i = 0; i < 2; ++i) {
+ it_a = it_b;
+ ++it_b;
+ double a = d->m_changeCount[*it_a];
+ double b = d->m_changeCount[*it_b];
+ if(b > (a * 1.2)) {
+ switch(i) {
+ case 0:
+ d->m_partPos['y'] = *it_a;
+ break;
+ case 1:
+ d->m_partPos['d'] = *it_b;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ // extract the last if necessary and possible date position
+ d->getThirdPosition();
+ }
+}
+
+void MyMoneyQifProfile::scanNumeric(const QString& txt, QChar& decimal, QChar& thousands) const
+{
+ QChar first, second;
+ QRegExp numericChars("[0-9-()]");
+ for(unsigned int i = 0; i < txt.length(); ++i) {
+ if(numericChars.search(txt[i]) == -1) {
+ first = second;
+ second = txt[i];
+ }
+ }
+ if(!second.isNull())
+ decimal = second;
+ if(!first.isNull())
+ thousands = first;
+}
+
+void MyMoneyQifProfile::scanDate(const QString& txt) const
+{
+ // extract the parts from the txt
+ QValueVector<QString> parts(3); // the various parts of the date
+ d->dissectDate(parts, txt);
+
+ // now analyse the parts
+ for(int i = 0; i < 3; ++i) {
+ bool ok;
+ int value = parts[i].toInt(&ok);
+ if(!ok) { // this should happen only if the part is non-numeric -> month
+ d->m_partPos['m'] = i;
+ } else if(value != 0) {
+ if(value != d->m_lastValue[i]) {
+ d->m_changeCount[i]++;
+ d->m_lastValue[i] = value;
+ if(value > d->m_largestValue[i])
+ d->m_largestValue[i] = value;
+ }
+ // if it's > 31 it can only be years
+ if(value > 31) {
+ d->m_partPos['y'] = i;
+ }
+ // and if it's in between 12 and 32 and we already identified the
+ // position for the year it must be days
+ if((value > 12) && (value < 32) && d->m_partPos.contains('y')) {
+ d->m_partPos['d'] = i;
+ }
+ }
+ }
+}
+
+#include "mymoneyqifprofile.moc"
diff --git a/kmymoney2/converter/mymoneyqifprofile.h b/kmymoney2/converter/mymoneyqifprofile.h
new file mode 100644
index 0000000..bd6b328
--- /dev/null
+++ b/kmymoney2/converter/mymoneyqifprofile.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+ mymoneyqifprofile.h - description
+ -------------------
+ begin : Tue Dec 24 2002
+ copyright : (C) 2002 by Thomas Baumgart
+ email : thb@net-bembel.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYQIFPROFILE_H
+#define MYMONEYQIFPROFILE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+class QDate;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class MyMoneyMoney;
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class MyMoneyQifProfile : public QObject
+{
+ Q_OBJECT
+
+public:
+ MyMoneyQifProfile();
+ MyMoneyQifProfile(const QString& name);
+ ~MyMoneyQifProfile();
+
+ const QString& profileName(void) const { return m_profileName; }
+ void setProfileName(const QString& name);
+
+ void loadProfile(const QString& name);
+ void saveProfile(void);
+
+ const QDate date(const QString& datein) const;
+ QString date(const QDate& datein) const;
+
+ MyMoneyMoney value(const QChar& def, const QString& valuein) const;
+ QString value(const QChar& def, const MyMoneyMoney& valuein) const;
+
+ const QString& outputDateFormat(void) const { return m_dateFormat; }
+ QString inputDateFormat(void) const;
+ const QString& apostropheFormat(void) const { return m_apostropheFormat; }
+ QChar amountDecimal(const QChar& def) const;
+ QChar amountThousands(const QChar& def) const;
+ const QString& profileDescription(void) const { return m_profileDescription; }
+ const QString& profileType(void) const { return m_profileType; }
+ const QString& openingBalanceText(void) const { return m_openingBalanceText; }
+ QString accountDelimiter(void) const;
+ const QString& voidMark(void) const { return m_voidMark; }
+ const QString& filterScriptImport(void) const { return m_filterScriptImport; }
+ const QString& filterScriptExport(void) const { return m_filterScriptExport; }
+ const QString& filterFileType(void) const { return m_filterFileType; }
+ bool attemptMatchDuplicates(void) const { return m_attemptMatchDuplicates; }
+
+ /**
+ * This method scans all strings contained in @a lines and tries to figure
+ * out the settings for m_decimal, m_thousands and m_dateFormat
+ */
+ void autoDetect(const QStringList& lines);
+
+ /**
+ * This method returns a list of possible date formats the user
+ * can choose from. If autoDetect() has not been run, the @a list
+ * contains all possible date formats, in the other case, the @a list
+ * is adjusted to those that will match the data scanned.
+ */
+ void possibleDateFormats(QStringList& list) const;
+
+ /**
+ * This method presets the member variables with the default values.
+ */
+ void clear(void);
+
+ /**
+ * This method is used to determine, if a profile has been changed or not
+ */
+ bool isDirty(void) const { return m_isDirty; };
+
+public slots:
+ void setProfileDescription(const QString& desc);
+ void setProfileType(const QString& type);
+ void setOutputDateFormat(const QString& dateFormat);
+ void setInputDateFormat(const QString& dateFormat);
+ void setApostropheFormat(const QString& apostropheFormat);
+ void setAmountDecimal(const QChar& def, const QChar& chr);
+ void setAmountThousands(const QChar& def, const QChar& chr);
+ void setAccountDelimiter(const QString& delim);
+ void setOpeningBalanceText(const QString& text);
+ void setVoidMark(const QString& txt);
+ void setFilterScriptImport(const QString& txt);
+ void setFilterScriptExport(const QString& txt);
+ void setFilterFileType(const QString& txt);
+ void setAttemptMatchDuplicates(bool);
+
+private:
+ QString twoDigitYear(const QChar delim, int yr) const;
+ void scanNumeric(const QString& txt, QChar& decimal, QChar& thousands) const;
+ void scanDate(const QString& txt) const;
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+ bool m_isDirty;
+ QString m_profileName;
+ QString m_profileDescription;
+ QString m_dateFormat;
+ QString m_apostropheFormat;
+ QString m_valueMode;
+ QString m_profileType;
+ QString m_openingBalanceText;
+ QString m_voidMark;
+ QString m_accountDelimiter;
+ QString m_filterScriptImport;
+ QString m_filterScriptExport;
+ QString m_filterFileType; /*< The kind of input files the filter will expect, e.g. "*.qif" */
+ QMap<QChar, QChar> m_decimal;
+ QMap<QChar, QChar> m_thousands;
+ bool m_attemptMatchDuplicates;
+};
+
+#endif
diff --git a/kmymoney2/converter/mymoneyqifreader.cpp b/kmymoney2/converter/mymoneyqifreader.cpp
new file mode 100644
index 0000000..60b0604
--- /dev/null
+++ b/kmymoney2/converter/mymoneyqifreader.cpp
@@ -0,0 +1,2336 @@
+/***************************************************************************
+ mymoneyqifreader.cpp
+ -------------------
+ begin : Mon Jan 27 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <iostream>
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <qtextedit.h>
+#include <qregexp.h>
+#include <qbuffer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kprogress.h>
+#include <kinputdialog.h>
+#include <kio/netaccess.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "mymoneyqifreader.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../dialogs/kaccountselectdlg.h"
+#include "../kmymoney2.h"
+#include "kmymoneyglobalsettings.h"
+
+#include "mymoneystatementreader.h"
+#include <kmymoney/mymoneystatement.h>
+
+// define this to debug the code. Using external filters
+// while debugging did not work too good for me, so I added
+// this code.
+// #define DEBUG_IMPORT
+
+#ifdef DEBUG_IMPORT
+#warning "DEBUG_IMPORT defined --> external filter not available!!!!!!!"
+#endif
+
+class MyMoneyQifReader::Private {
+ public:
+ Private() :
+ accountType(MyMoneyAccount::Checkings),
+ mapCategories(true)
+ {}
+
+ QString accountTypeToQif(MyMoneyAccount::accountTypeE type) const;
+
+ /**
+ * finalize the current statement and add it to the statement list
+ */
+ void finishStatement(void);
+
+ bool isTransfer(QString& name, const QString& leftDelim, const QString& rightDelim);
+
+ /**
+ * Converts the QIF specific N-record of investment transactions into
+ * a category name
+ */
+ QString typeToAccountName(const QString& type) const;
+
+ /**
+ * Converts the QIF reconcile state to the KMyMoney reconcile state
+ */
+ MyMoneySplit::reconcileFlagE reconcileState(const QString& state) const;
+
+ /**
+ */
+ void fixMultiLineMemo(QString& memo) const;
+
+ public:
+ /**
+ * the statement that is currently collected/processed
+ */
+ MyMoneyStatement st;
+ /**
+ * the list of all statements to be sent to MyMoneyStatementReader
+ */
+ QValueList<MyMoneyStatement> statements;
+
+ /**
+ * a list of already used hashes in this file
+ */
+ QMap<QString, bool> m_hashMap;
+
+ QString st_AccountName;
+ QString st_AccountId;
+ MyMoneyAccount::accountTypeE accountType;
+ bool firstTransaction;
+ bool mapCategories;
+ MyMoneyQifReader::QifEntryTypeE transactionType;
+};
+
+void MyMoneyQifReader::Private::fixMultiLineMemo(QString& memo) const
+{
+ memo.replace("\\n", "\n");
+}
+
+void MyMoneyQifReader::Private::finishStatement(void)
+{
+ // in case we have collected any data in the statement, we keep it
+ if((st.m_listTransactions.count() + st.m_listPrices.count() + st.m_listSecurities.count()) > 0) {
+ statements += st;
+ qDebug("Statement with %d transactions, %d prices and %d securities added to the statement list",
+ st.m_listTransactions.count(), st.m_listPrices.count(), st.m_listSecurities.count());
+ }
+ // start with a fresh statement
+ st = MyMoneyStatement();
+ st.m_skipCategoryMatching = !mapCategories;
+ st.m_eType = (transactionType == MyMoneyQifReader::EntryTransaction) ? MyMoneyStatement::etCheckings : MyMoneyStatement::etInvestment;
+}
+
+QString MyMoneyQifReader::Private::accountTypeToQif(MyMoneyAccount::accountTypeE type) const
+{
+ QString rc = "Bank";
+
+ switch(type) {
+ default:
+ break;
+ case MyMoneyAccount::Cash:
+ rc = "Cash";
+ break;
+ case MyMoneyAccount::CreditCard:
+ rc = "CCard";
+ break;
+ case MyMoneyAccount::Asset:
+ rc = "Oth A";
+ break;
+ case MyMoneyAccount::Liability:
+ rc = "Oth L";
+ break;
+ case MyMoneyAccount::Investment:
+ rc = "Port";
+ break;
+ }
+ return rc;
+}
+
+QString MyMoneyQifReader::Private::typeToAccountName(const QString& type) const
+{
+ if(type == "reinvdiv")
+ return i18n("Category name", "Reinvested dividend");
+
+ if(type == "reinvlg")
+ return i18n("Category name", "Reinvested dividend (long term)");
+
+ if(type == "reinvsh")
+ return i18n("Category name", "Reinvested dividend (short term)");
+
+ if (type == "div")
+ return i18n("Category name", "Dividend");
+
+ if(type == "intinc")
+ return i18n("Category name", "Interest");
+
+ if(type == "cgshort")
+ return i18n("Category name", "Capital Gain (short term)");
+
+ if( type == "cgmid")
+ return i18n("Category name", "Capital Gain (mid term)");
+
+ if(type == "cglong")
+ return i18n("Category name", "Capital Gain (long term)");
+
+ if(type == "rtrncap")
+ return i18n("Category name", "Returned capital");
+
+ if(type == "miscinc")
+ return i18n("Category name", "Miscellaneous income");
+
+ if(type == "miscexp")
+ return i18n("Category name", "Miscellaneous expense");
+
+ if(type == "sell" || type == "buy")
+ return i18n("Category name", "Investment fees");
+
+ return i18n("Unknown QIF type %1").arg(type);
+}
+
+bool MyMoneyQifReader::Private::isTransfer(QString& tmp, const QString& leftDelim, const QString& rightDelim)
+{
+ // it's a transfer, extract the account name
+ // I've seen entries like this
+ //
+ // S[Mehrwertsteuer]/_VATCode_N_I
+ //
+ // so extracting is a bit more complex and we use a regexp for it
+ QRegExp exp(QString("\\%1(.*)\\%2(.*)").arg(leftDelim, rightDelim));
+
+ bool rc;
+ if((rc = (exp.search(tmp) != -1)) == true) {
+ tmp = exp.cap(1)+exp.cap(2);
+ tmp = tmp.stripWhiteSpace();
+ }
+ return rc;
+}
+
+MyMoneySplit::reconcileFlagE MyMoneyQifReader::Private::reconcileState(const QString& state) const
+{
+ if(state == "X" || state == "R") // Reconciled
+ return MyMoneySplit::Reconciled;
+
+ if(state == "*") // Cleared
+ return MyMoneySplit::Cleared;
+
+ return MyMoneySplit::NotReconciled;
+}
+
+
+MyMoneyQifReader::MyMoneyQifReader() :
+ d(new Private)
+{
+ m_skipAccount = false;
+ m_transactionsProcessed =
+ m_transactionsSkipped = 0;
+ m_progressCallback = 0;
+ m_file = 0;
+ m_entryType = EntryUnknown;
+ m_processingData = false;
+ m_userAbort = false;
+ m_warnedInvestment = false;
+ m_warnedSecurity = false;
+ m_warnedPrice = false;
+
+ connect(&m_filter, SIGNAL(wroteStdin(KProcess*)), this, SLOT(slotSendDataToFilter()));
+ connect(&m_filter, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotReceivedDataFromFilter(KProcess*, char*, int)));
+ connect(&m_filter, SIGNAL(processExited(KProcess*)), this, SLOT(slotImportFinished()));
+ connect(&m_filter, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotReceivedErrorFromFilter(KProcess*, char*, int)));
+}
+
+MyMoneyQifReader::~MyMoneyQifReader()
+{
+ if(m_file)
+ delete m_file;
+ delete d;
+}
+
+void MyMoneyQifReader::setCategoryMapping(bool map)
+{
+ d->mapCategories = map;
+}
+
+void MyMoneyQifReader::setURL(const KURL& url)
+{
+ m_url = url;
+}
+
+void MyMoneyQifReader::setProfile(const QString& profile)
+{
+ m_qifProfile.loadProfile("Profile-" + profile);
+}
+
+void MyMoneyQifReader::slotSendDataToFilter(void)
+{
+ Q_LONG len;
+
+ if(m_file->atEnd()) {
+ // m_filter.flushStdin();
+ m_filter.closeStdin();
+ } else {
+ len = m_file->readBlock(m_buffer, sizeof(m_buffer));
+ if(len == -1) {
+ qWarning("Failed to read block from QIF import file");
+ m_filter.closeStdin();
+ m_filter.kill();
+ } else {
+ m_filter.writeStdin(m_buffer, len);
+ }
+ }
+}
+
+void MyMoneyQifReader::slotReceivedErrorFromFilter(KProcess* /* proc */, char *buff, int len)
+{
+ QByteArray data;
+ data.duplicate(buff, len);
+ qWarning("%s",static_cast<const char*>(data));
+}
+
+void MyMoneyQifReader::slotReceivedDataFromFilter(KProcess* /* proc */, char *buff, int len)
+{
+ m_pos += len;
+ // signalProgress(m_pos, 0);
+
+ while(len) {
+ // process char
+ if(*buff == '\n' || *buff == '\r') {
+ // found EOL
+ if(!m_lineBuffer.isEmpty()) {
+ m_qifLines << QString::fromUtf8(m_lineBuffer.stripWhiteSpace());
+ }
+ m_lineBuffer = QCString();
+ } else {
+ // collect all others
+ m_lineBuffer += (*buff);
+ }
+ ++buff;
+ --len;
+ }
+}
+
+void MyMoneyQifReader::slotImportFinished(void)
+{
+ // check if the last EOL char was missing and add the trailing line
+ if(!m_lineBuffer.isEmpty()) {
+ m_qifLines << QString::fromUtf8(m_lineBuffer.stripWhiteSpace());
+ }
+ qDebug("Read %d bytes", m_pos);
+ QTimer::singleShot(0, this, SLOT(slotProcessData()));
+}
+
+void MyMoneyQifReader::slotProcessData(void)
+{
+ signalProgress(-1, -1);
+
+ // scan the file and try to determine numeric and date formats
+ m_qifProfile.autoDetect(m_qifLines);
+
+ // the detection is accurate for numeric values, but it could be
+ // that the dates were too ambiguous so that we have to let the user
+ // decide which one to pick.
+ QStringList dateFormats;
+ m_qifProfile.possibleDateFormats(dateFormats);
+ QStringList list;
+ if(dateFormats.count() > 1) {
+ list << dateFormats.first();
+ bool ok;
+ list = KInputDialog::getItemList(i18n("Date format selection"), i18n("Pick the date format that suits your input file"), dateFormats, list, false, &ok);
+ if(!ok) {
+ m_userAbort = true;
+ }
+ } else
+ list = dateFormats;
+
+ m_qifProfile.setInputDateFormat(list.first());
+
+ qDebug("Selected date format: '%s'", list.first().data());
+
+ signalProgress(0, m_qifLines.count(), i18n("Importing QIF ..."));
+ QStringList::iterator it;
+ for(it = m_qifLines.begin(); m_userAbort == false && it != m_qifLines.end(); ++it) {
+ ++m_linenumber;
+ // qDebug("Proc: '%s'", (*it).data());
+ if((*it).startsWith("!")) {
+ processQifSpecial(*it);
+ m_qifEntry.clear();
+ } else if(*it == "^") {
+ if(m_qifEntry.count() > 0) {
+ signalProgress(m_linenumber, 0);
+ processQifEntry();
+ m_qifEntry.clear();
+ }
+ } else {
+ m_qifEntry += *it;
+ }
+ }
+ d->finishStatement();
+
+ qDebug("%d lines processed", m_linenumber);
+ signalProgress(-1, -1);
+
+ emit importFinished();
+}
+
+bool MyMoneyQifReader::startImport(void)
+{
+ bool rc = false;
+ d->st = MyMoneyStatement();
+ d->st.m_skipCategoryMatching = !d->mapCategories;
+ m_dontAskAgain.clear();
+ m_accountTranslation.clear();
+ m_userAbort = false;
+ m_pos = 0;
+ m_linenumber = 0;
+ m_filename = QString::null;
+ m_data.clear();
+
+ if(!KIO::NetAccess::download(m_url, m_filename, NULL)) {
+ KMessageBox::detailedError(0,
+ i18n("Error while loading file '%1'!").arg(m_url.prettyURL()),
+ KIO::NetAccess::lastErrorString(),
+ i18n("File access error"));
+ return false;
+ }
+
+ m_file = new QFile(m_filename);
+ if(m_file->open(IO_ReadOnly)) {
+
+#ifdef DEBUG_IMPORT
+ Q_LONG len;
+
+ while(!m_file->atEnd()) {
+ len = m_file->readBlock(m_buffer, sizeof(m_buffer));
+ if(len == -1) {
+ qWarning("Failed to read block from QIF import file");
+ } else {
+ slotReceivedDataFromFilter(0, m_buffer, len);
+ }
+ }
+ slotImportFinished();
+
+#else
+ // start filter process, use 'cat -' as the default filter
+ m_filter.clearArguments();
+ if(m_qifProfile.filterScriptImport().isEmpty()) {
+ m_filter << "cat";
+ m_filter << "-";
+ } else {
+ m_filter << QStringList::split(" ", m_qifProfile.filterScriptImport(), true);
+ }
+ m_entryType = EntryUnknown;
+
+ if(m_filter.start(KProcess::NotifyOnExit, KProcess::All)) {
+ m_filter.resume();
+ signalProgress(0, m_file->size(), i18n("Reading QIF ..."));
+ slotSendDataToFilter();
+ rc = true;
+ } else {
+ qDebug("starting filter failed :-(");
+ }
+#endif
+ }
+ return rc;
+}
+
+bool MyMoneyQifReader::finishImport(void)
+{
+ bool rc = false;
+
+#ifdef DEBUG_IMPORT
+ delete m_file;
+ m_file = 0;
+
+ // remove the Don't ask again entries
+ KConfig* config = KGlobal::config();
+ config->setGroup(QString::fromLatin1("Notification Messages"));
+ QStringList::ConstIterator it;
+
+ for(it = m_dontAskAgain.begin(); it != m_dontAskAgain.end(); ++it) {
+ config->deleteEntry(*it);
+ }
+ config->sync();
+ m_dontAskAgain.clear();
+ m_accountTranslation.clear();
+
+ signalProgress(-1, -1);
+ rc = !m_userAbort;
+
+#else
+ if(!m_filter.isRunning()) {
+ delete m_file;
+ m_file = 0;
+
+ // remove the Don't ask again entries
+ KConfig* config = KGlobal::config();
+ config->setGroup(QString::fromLatin1("Notification Messages"));
+ QStringList::ConstIterator it;
+
+ for(it = m_dontAskAgain.begin(); it != m_dontAskAgain.end(); ++it) {
+ config->deleteEntry(*it);
+ }
+ config->sync();
+ m_dontAskAgain.clear();
+ m_accountTranslation.clear();
+
+ signalProgress(-1, -1);
+ rc = !m_userAbort && m_filter.normalExit();
+ } else {
+ qWarning("MyMoneyQifReader::finishImport() must not be called while the filter\n\tprocess is still running.");
+ }
+#endif
+
+ // if a temporary file was constructed by NetAccess::download,
+ // then it will be removed with the next call. Otherwise, it
+ // stays untouched on the local filesystem
+ KIO::NetAccess::removeTempFile(m_filename);
+
+#if 0
+ // Add the transaction entries
+ KProgressDialog dlg(0,"transactionaddprogress",i18n("Adding transactions"),i18n("Now adding the transactions to your ledger..."));
+ dlg.progressBar()->setTotalSteps(m_transactionCache.count());
+ dlg.progressBar()->setTextEnabled(true);
+ dlg.setAllowCancel(true);
+ dlg.show();
+ kapp->processEvents();
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyTransaction>::iterator it = m_transactionCache.begin();
+ MyMoneyFileTransaction ft;
+ try
+ {
+ while( it != m_transactionCache.end() )
+ {
+ if ( dlg.wasCancelled() )
+ {
+ m_userAbort = true;
+ rc = false;
+ break;
+ }
+ file->addTransaction(*it);
+ dlg.progressBar()->advance(1);
+ ++it;
+ }
+ if(rc)
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to add transactions"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ rc = false;
+ }
+#endif
+ // Now to import the statements
+ QValueList<MyMoneyStatement>::const_iterator it_st;
+ for(it_st = d->statements.begin(); it_st != d->statements.end(); ++it_st)
+ kmymoney2->slotStatementImport(*it_st);
+ return rc;
+}
+
+void MyMoneyQifReader::processQifSpecial(const QString& _line)
+{
+ QString line = _line.mid(1); // get rid of exclamation mark
+ // QString test = line.left(5).lower();
+ if(line.left(5).lower() == QString("type:")) {
+ line = line.mid(5);
+
+ // exportable accounts
+ if(line.lower() == "ccard" || KMyMoneyGlobalSettings::qifCreditCard().lower().contains(line.lower())) {
+ d->accountType = MyMoneyAccount::CreditCard;
+ d->firstTransaction = true;
+ d->transactionType = m_entryType = EntryTransaction;
+
+ } else if(line.lower() == "bank" || KMyMoneyGlobalSettings::qifBank().lower().contains(line.lower())) {
+ d->accountType = MyMoneyAccount::Checkings;
+ d->firstTransaction = true;
+ d->transactionType = m_entryType = EntryTransaction;
+
+ } else if(line.lower() == "cash" || KMyMoneyGlobalSettings::qifCash().lower().contains(line.lower())) {
+ d->accountType = MyMoneyAccount::Cash;
+ d->firstTransaction = true;
+ d->transactionType = m_entryType = EntryTransaction;
+
+ } else if(line.lower() == "oth a" || KMyMoneyGlobalSettings::qifAsset().lower().contains(line.lower())) {
+ d->accountType = MyMoneyAccount::Asset;
+ d->firstTransaction = true;
+ d->transactionType = m_entryType = EntryTransaction;
+
+ } else if(line.lower() == "oth l" || line.lower() == i18n("QIF tag for liability account", "Oth L").lower()) {
+ d->accountType = MyMoneyAccount::Liability;
+ d->firstTransaction = true;
+ d->transactionType = m_entryType = EntryTransaction;
+
+ } else if(line.lower() == "invst" || line.lower() == i18n("QIF tag for investment account", "Invst").lower()) {
+ d->transactionType = m_entryType = EntryInvestmentTransaction;
+
+ } else if(line.lower() == "invoice" || KMyMoneyGlobalSettings::qifInvoice().lower().contains(line.lower())) {
+ m_entryType = EntrySkip;
+
+ } else if(line.lower() == "tax") {
+ m_entryType = EntrySkip;
+
+ } else if(line.lower() == "bill") {
+ m_entryType = EntrySkip;
+
+ // exportable lists
+ } else if(line.lower() == "cat" || line.lower() == i18n("QIF tag for category", "Cat").lower()) {
+ m_entryType = EntryCategory;
+
+ } else if(line.lower() == "security" || line.lower() == i18n("QIF tag for security", "Security").lower()) {
+ m_entryType = EntrySecurity;
+
+ } else if(line.lower() == "prices" || line.lower() == i18n("QIF tag for prices", "Prices").lower()) {
+ m_entryType = EntryPrice;
+
+ } else if(line.lower() == "payee") {
+ m_entryType = EntryPayee;
+
+ } else if(line.lower() == "class" || line.lower() == i18n("QIF tag for a class", "Class").lower()) {
+ m_entryType = EntryClass;
+
+ } else if(line.lower() == "memorized") {
+ m_entryType = EntryMemorizedTransaction;
+
+ } else if(line.lower() == "budget") {
+ m_entryType = EntrySkip;
+
+ } else if(line.lower() == "invitem") {
+ m_entryType = EntrySkip;
+
+ } else if(line.lower() == "template") {
+ m_entryType = EntrySkip;
+
+ } else {
+ qWarning("Unknown export header '!Type:%s' in QIF file on line %d: Skipping section.", line.data(), m_linenumber);
+ m_entryType = EntrySkip;
+ }
+
+ // account headers
+ } else if(line.lower() == "account") {
+ m_entryType = EntryAccount;
+
+ } else if(line.lower() == "option:autoswitch") {
+ m_entryType = EntryAccount;
+
+ } else if(line.lower() == "clear:autoswitch") {
+ m_entryType = d->transactionType;
+ }
+}
+
+void MyMoneyQifReader::processQifEntry(void)
+{
+ // This method processes a 'QIF Entry' which is everything between two caret
+ // signs
+ //
+ try {
+ switch(m_entryType) {
+ case EntryCategory:
+ processCategoryEntry();
+ break;
+
+ case EntryUnknown:
+ kdDebug(2) << "Line " << m_linenumber << ": Warning: Found an entry without a type being specified. Checking assumed." << endl;
+ processTransactionEntry();
+ break;
+
+ case EntryTransaction:
+ processTransactionEntry();
+ break;
+
+ case EntryInvestmentTransaction:
+ processInvestmentTransactionEntry();
+ break;
+
+ case EntryAccount:
+ processAccountEntry();
+ break;
+
+ case EntrySecurity:
+ processSecurityEntry();
+ break;
+
+ case EntryPrice:
+ processPriceEntry();
+ break;
+
+ case EntryPayee:
+ processPayeeEntry();
+ break;
+
+ case EntryClass:
+ kdDebug(2) << "Line " << m_linenumber << ": Classes are not yet supported!" << endl;
+ break;
+
+ case EntryMemorizedTransaction:
+ kdDebug(2) << "Line " << m_linenumber << ": Memorized transactions are not yet implemented!" << endl;
+ break;
+
+ case EntrySkip:
+ break;
+
+ default:
+ kdDebug(2) << "Line " << m_linenumber<< ": EntryType " << m_entryType <<" not yet implemented!" << endl;
+ break;
+ }
+ } catch(MyMoneyException *e) {
+ if(e->what() != "USERABORT") {
+ kdDebug(2) << "Line " << m_linenumber << ": Unhandled error: " << e->what() << endl;
+ } else {
+ m_userAbort = true;
+ }
+ delete e;
+ }
+}
+
+const QString MyMoneyQifReader::extractLine(const QChar id, int cnt)
+{
+ QStringList::ConstIterator it;
+
+ m_extractedLine = -1;
+ for(it = m_qifEntry.begin(); it != m_qifEntry.end(); ++it) {
+ m_extractedLine++;
+ if((*it)[0] == id) {
+ if(cnt-- == 1) {
+ if((*it).mid(1).isEmpty())
+ return QString(" ");
+ return (*it).mid(1);
+ }
+ }
+ }
+ m_extractedLine = -1;
+ return QString();
+}
+
+void MyMoneyQifReader::extractSplits(QValueList<qSplit>& listqSplits) const
+{
+// *** With apologies to QString MyMoneyQifReader::extractLine ***
+
+ QStringList::ConstIterator it;
+
+ for(it = m_qifEntry.begin(); it != m_qifEntry.end(); ++it) {
+ if((*it)[0] == "S") {
+ qSplit q;
+ q.m_strCategoryName = (*it++).mid(1); // 'S'
+ if((*it)[0] == "E") {
+ q.m_strMemo = (*it++).mid(1); // 'E'
+ d->fixMultiLineMemo(q.m_strMemo);
+ }
+ if((*it)[0] == "$") {
+ q.m_amount = (*it).mid(1); // '$'
+ }
+ listqSplits += q;
+ }
+ }
+}
+#if 0
+void MyMoneyQifReader::processMSAccountEntry(const MyMoneyAccount::accountTypeE accountType)
+{
+ if(extractLine('P').lower() == m_qifProfile.openingBalanceText().lower()) {
+ m_account = MyMoneyAccount();
+ m_account.setAccountType(accountType);
+ QString txt = extractLine('T');
+ MyMoneyMoney balance = m_qifProfile.value('T', txt);
+
+ QDate date = m_qifProfile.date(extractLine('D'));
+ m_account.setOpeningDate(date);
+
+ QString name = extractLine('L');
+ if(name.left(1) == m_qifProfile.accountDelimiter().left(1)) {
+ name = name.mid(1, name.length()-2);
+ }
+ d->st_AccountName = name;
+ m_account.setName(name);
+ selectOrCreateAccount(Select, m_account, balance);
+ d->st.m_accountId = m_account.id();
+ if ( ! balance.isZero() )
+ {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString openingtxid = file->openingBalanceTransaction(m_account);
+ MyMoneyFileTransaction ft;
+ if ( ! openingtxid.isEmpty() )
+ {
+ MyMoneyTransaction openingtx = file->transaction(openingtxid);
+ MyMoneySplit split = openingtx.splitByAccount(m_account.id());
+
+ if ( split.shares() != balance )
+ {
+ const MyMoneySecurity& sec = file->security(m_account.currencyId());
+ if ( KMessageBox::questionYesNo(
+ qApp->mainWidget(),
+ i18n("The %1 account currently has an opening balance of %2. This QIF file reports an opening balance of %3. Would you like to overwrite the current balance with the one from the QIF file?").arg(m_account.name(), split.shares().formatMoney(m_account, sec),balance.formatMoney(m_account, sec)),
+ i18n("Overwrite opening balance"),
+ KStdGuiItem::yes(),
+ KStdGuiItem::no(),
+ "OverwriteOpeningBalance" )
+ == KMessageBox::Yes )
+ {
+ file->removeTransaction( openingtx );
+ m_account.setOpeningDate( date );
+ file->createOpeningBalanceTransaction( m_account, balance );
+ }
+ }
+
+ }
+ else
+ {
+ // Add an opening balance
+ m_account.setOpeningDate( date );
+ file->createOpeningBalanceTransaction( m_account, balance );
+ }
+ ft.commit();
+ }
+
+ } else {
+ // for some unknown reason, Quicken 2001 generates the following (somewhat
+ // misleading) sequence of lines:
+ //
+ // 1: !Account
+ // 2: NAT&T Universal
+ // 3: DAT&T Univers(...xxxx) [CLOSED]
+ // 4: TCCard
+ // 5: ^
+ // 6: !Type:CCard
+ // 7: !Account
+ // 8: NCFCU Visa
+ // 9: DRick's CFCU Visa card (...xxxx)
+ // 10: TCCard
+ // 11: ^
+ // 12: !Type:CCard
+ // 13: D1/ 4' 1
+ //
+ // Lines 1-5 are processed via processQifEntry() and processAccountEntry()
+ // Then Quicken issues line 6 but since the account does not carry any
+ // transaction does not write an end delimiter. Arrrgh! So we end up with
+ // a QIF entry comprising of lines 6-11 and end up in this routine. Actually,
+ // lines 7-11 are the leadin for the next account. So we check here if
+ // the !Type:xxx record also contains an !Account line and process the
+ // entry as required.
+ //
+ // (Ace) I think a better solution here is to handle exclamation point
+ // lines separately from entries. In the above case:
+ // Line 1 would set the mode to "account entries".
+ // Lines 2-5 would be interpreted as an account entry. This would set m_account.
+ // Line 6 would set the mode to "cc transaction entries".
+ // Line 7 would immediately set the mode to "account entries" again
+ // Lines 8-11 would be interpreted as an account entry. This would set m_account.
+ // Line 12 would set the mode to "cc transaction entries"
+ // Lines 13+ would be interpreted as cc transaction entries, and life is good
+ int exclamationCnt = 1;
+ QString category;
+ do {
+ category = extractLine('!', exclamationCnt++);
+ } while(!category.isEmpty() && category != "Account");
+
+ // we have such a weird empty account
+ if(category == "Account") {
+ processAccountEntry();
+ } else
+ {
+ selectOrCreateAccount(Select, m_account);
+
+ d->st_AccountName = m_account.name();
+ d->st.m_strAccountName = m_account.name();
+ d->st.m_accountId = m_account.id();
+ d->st.m_strAccountNumber = m_account.id();
+ m_account.setNumber(m_account.id());
+ if ( m_entryType == EntryInvestmentTransaction )
+ processInvestmentTransactionEntry();
+ else
+ processTransactionEntry();
+ }
+ }
+}
+#endif
+
+void MyMoneyQifReader::processPayeeEntry(void)
+{
+ // TODO
+}
+
+void MyMoneyQifReader::processCategoryEntry(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount account = MyMoneyAccount();
+ account.setName(extractLine('N'));
+ account.setDescription(extractLine('D'));
+
+ MyMoneyAccount parentAccount;
+ if(!extractLine('I').isEmpty()) {
+ account.setAccountType(MyMoneyAccount::Income);
+ parentAccount = file->income();
+ } else if(!extractLine('E').isEmpty()) {
+ account.setAccountType(MyMoneyAccount::Expense);
+ parentAccount = file->expense();
+ }
+
+ // check if we can find the account already in the file
+ MyMoneyAccount acc = kmymoney2->findAccount(account, MyMoneyAccount());
+
+ // if not, we just create it
+ if(acc.id().isEmpty()) {
+ MyMoneyAccount brokerage;
+ MyMoneyMoney balance;
+ kmymoney2->createAccount(account, parentAccount, brokerage, balance);
+ }
+}
+
+QString MyMoneyQifReader::transferAccount(QString name, bool useBrokerage)
+{
+ QString accountId;
+ QStringList tmpEntry = m_qifEntry; // keep temp copies
+ MyMoneyAccount tmpAccount = m_account;
+
+ m_qifEntry.clear(); // and construct a temp entry to create/search the account
+ m_qifEntry << QString("N%1").arg(name);
+ m_qifEntry << QString("Tunknown");
+ m_qifEntry << QString("D%1").arg(i18n("Autogenerated by QIF importer"));
+ accountId = processAccountEntry(false);
+
+ // in case we found a reference to an investment account, we need
+ // to switch to the brokerage account instead.
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(accountId);
+ if(useBrokerage && (acc.accountType() == MyMoneyAccount::Investment)) {
+ name = acc.brokerageName();
+ m_qifEntry.clear(); // and construct a temp entry to create/search the account
+ m_qifEntry << QString("N%1").arg(name);
+ m_qifEntry << QString("Tunknown");
+ m_qifEntry << QString("D%1").arg(i18n("Autogenerated by QIF importer"));
+ accountId = processAccountEntry(false);
+ }
+ m_qifEntry = tmpEntry; // restore local copies
+ m_account = tmpAccount;
+
+ return accountId;
+}
+
+void MyMoneyQifReader::createOpeningBalance(MyMoneyAccount::_accountTypeE accType)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // if we don't have a name for the current account we need to extract the name from the L-record
+ if(m_account.name().isEmpty()) {
+ QString name = extractLine('L');
+ if(name.isEmpty()) {
+ name = i18n("QIF imported, no account name supplied");
+ }
+ d->isTransfer(name, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1,1));
+ QStringList entry = m_qifEntry; // keep a temp copy
+ m_qifEntry.clear(); // and construct a temp entry to create/search the account
+ m_qifEntry << QString("N%1").arg(name);
+ m_qifEntry << QString("T%1").arg(d->accountTypeToQif(accType));
+ m_qifEntry << QString("D%1").arg(i18n("Autogenerated by QIF importer"));
+ processAccountEntry();
+ m_qifEntry = entry; // restore local copy
+ }
+
+ MyMoneyFileTransaction ft;
+ try {
+ bool needCreate = true;
+
+ MyMoneyAccount acc = m_account;
+ // in case we're dealing with an investment account, we better use
+ // the accompanying brokerage account for the opening balance
+ acc = file->accountByName(m_account.brokerageName());
+
+ // check if we already have an opening balance transaction
+ QString tid = file->openingBalanceTransaction(acc);
+ MyMoneyTransaction ot;
+ if(!tid.isEmpty()) {
+ ot = file->transaction(tid);
+ MyMoneySplit s0 = ot.splitByAccount(acc.id());
+ // if the value is the same, we can silently skip this transaction
+ if(s0.shares() == m_qifProfile.value('T', extractLine('T'))) {
+ needCreate = false;
+ }
+ if(needCreate) {
+ // in case we create it anyway, we issue a warning to the user to check it manually
+ KMessageBox::sorry(0, QString("<qt>%1</qt>").arg(i18n("KMyMoney has imported a second opening balance transaction into account <b>%1</b> which differs from the one found already on file. Please correct this manually once the import is done.").arg(acc.name())), i18n("Opening balance problem"));
+ }
+ }
+
+ if(needCreate) {
+ acc.setOpeningDate(m_qifProfile.date(extractLine('D')));
+ file->modifyAccount(acc);
+ MyMoneyTransaction t = file->createOpeningBalanceTransaction(acc, m_qifProfile.value('T', extractLine('T')));
+ if(!t.id().isEmpty()) {
+ t.setImported();
+ file->modifyTransaction(t);
+ }
+ ft.commit();
+ }
+
+ // make sure to use the updated version of the account
+ if(m_account.id() == acc.id())
+ m_account = acc;
+
+ // remember which account we created
+ d->st.m_accountId = m_account.id();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedError(0,
+ i18n("Error while creating opening balance transaction"),
+ QString("%1(%2):%3").arg(e->file()).arg(e->line()).arg(e->what()),
+ i18n("File access error"));
+ delete e;
+ }
+}
+
+void MyMoneyQifReader::processTransactionEntry(void)
+{
+ ++m_transactionsProcessed;
+ // in case the user selected to skip the account or the account
+ // was not found we skip this transaction
+/*
+ if(m_account.id().isEmpty()) {
+ m_transactionsSkipped++;
+ return;
+ }
+*/
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyStatement::Split s1;
+ MyMoneyStatement::Transaction tr;
+ QString tmp;
+ QString accountId;
+ int pos;
+ QString payee = extractLine('P');
+ unsigned long h;
+
+ h = MyMoneyTransaction::hash(m_qifEntry.join(";"));
+
+ QString hashBase;
+ hashBase.sprintf("%s-%07lx", m_qifProfile.date(extractLine('D')).toString(Qt::ISODate).data(), h);
+ int idx = 1;
+ QString hash;
+ for(;;) {
+ hash = QString("%1-%2").arg(hashBase).arg(idx);
+ QMap<QString, bool>::const_iterator it;
+ it = d->m_hashMap.find(hash);
+ if(it == d->m_hashMap.end()) {
+ d->m_hashMap[hash] = true;
+ break;
+ }
+ ++idx;
+ }
+ tr.m_strBankID = hash;
+
+ if(d->firstTransaction) {
+ // check if this is an opening balance transaction and process it out of the statement
+ if(!payee.isEmpty() && ((payee.lower() == "opening balance") || KMyMoneyGlobalSettings::qifOpeningBalance().lower().contains(payee.lower()))) {
+ createOpeningBalance();
+ d->firstTransaction = false;
+ return;
+ }
+ }
+
+ // Process general transaction data
+
+ if(d->st.m_accountId.isEmpty())
+ d->st.m_accountId = m_account.id();
+
+ s1.m_accountId = d->st.m_accountId;
+
+ d->st.m_eType = MyMoneyStatement::etCheckings;
+ tr.m_datePosted = (m_qifProfile.date(extractLine('D')));
+ if(!tr.m_datePosted.isValid())
+ {
+ int rc = KMessageBox::warningContinueCancel(0,
+ i18n("The date entry \"%1\" read from the file cannot be interpreted through the current "
+ "date profile setting of \"%2\".\n\nPressing \"Continue\" will "
+ "assign todays date to the transaction. Pressing \"Cancel\" will abort "
+ "the import operation. You can then restart the import and select a different "
+ "QIF profile or create a new one.")
+ .arg(extractLine('D')).arg(m_qifProfile.inputDateFormat()),
+ i18n("Invalid date format"));
+ switch(rc) {
+ case KMessageBox::Continue:
+ tr.m_datePosted = (QDate::currentDate());
+ break;
+
+ case KMessageBox::Cancel:
+ throw new MYMONEYEXCEPTION("USERABORT");
+ break;
+ }
+ }
+
+ tmp = extractLine('L');
+ pos = tmp.findRev("--");
+ if(tmp.left(1) == m_qifProfile.accountDelimiter().left(1)) {
+ // it's a transfer, so we wipe the memo
+// tmp = ""; why??
+// st.m_strAccountName = tmp;
+ } else if(pos != -1) {
+// what's this?
+// t.setValue("Dialog", tmp.mid(pos+2));
+ tmp = tmp.left(pos);
+ }
+// t.setMemo(tmp);
+
+ // Assign the "#" field to the transaction's bank id
+ // This is the custom KMM extension to QIF for a unique ID
+ tmp = extractLine('#');
+ if(!tmp.isEmpty())
+ {
+ tr.m_strBankID = QString("ID %1").arg(tmp);
+ }
+
+#if 0
+ // Collect data for the account's split
+ s1.m_accountId = m_account.id();
+ tmp = extractLine('S');
+ pos = tmp.findRev("--");
+ if(pos != -1) {
+ tmp = tmp.left(pos);
+ }
+ if(tmp.left(1) == m_qifProfile.accountDelimiter().left(1))
+ // it's a transfer, extract the account name
+ tmp = tmp.mid(1, tmp.length()-2);
+ s1.m_strCategoryName = tmp;
+#endif
+ // TODO (Ace) Deal with currencies more gracefully. QIF cannot deal with multiple
+ // currencies, so we should assume that transactions imported into a given
+ // account are in THAT ACCOUNT's currency. If one of those involves a transfer
+ // to an account with a different currency, value and shares should be
+ // different. (Shares is in the target account's currency, value is in the
+ // transaction's)
+
+
+ s1.m_amount = m_qifProfile.value('T', extractLine('T'));
+ tr.m_amount = m_qifProfile.value('T', extractLine('T'));
+ tr.m_shares = m_qifProfile.value('T', extractLine('T'));
+ tmp = extractLine('N');
+ if (!tmp.isEmpty())
+ tr.m_strNumber = tmp;
+
+ if(!payee.isEmpty()) {
+ tr.m_strPayee = payee;
+ }
+
+ tr.m_reconcile = d->reconcileState(extractLine('C'));
+ tr.m_strMemo = extractLine('M');
+ d->fixMultiLineMemo(tr.m_strMemo);
+ s1.m_strMemo = tr.m_strMemo;
+ // tr.m_listSplits.append(s1);
+
+ if(extractLine('$').isEmpty()) {
+ MyMoneyAccount account;
+ // use the same values for the second split, but clear the ID and reverse the value
+ MyMoneyStatement::Split s2 = s1;
+ s2.m_reconcile = tr.m_reconcile;
+ s2.m_amount = (-s1.m_amount);
+// s2.clearId();
+
+ // standard transaction
+ tmp = extractLine('L');
+ if(d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1))) {
+ accountId = transferAccount(tmp, false);
+
+ } else {
+/* pos = tmp.findRev("--");
+ if(pos != -1) {
+ t.setValue("Dialog", tmp.mid(pos+2));
+ tmp = tmp.left(pos);
+ }*/
+
+ // it's an expense / income
+ tmp = tmp.stripWhiteSpace();
+ accountId = checkCategory(tmp, s1.m_amount, s2.m_amount);
+ }
+
+ if(!accountId.isEmpty()) {
+ try {
+ MyMoneyAccount account = file->account(accountId);
+ // FIXME: check that the type matches and ask if not
+
+ if ( account.accountType() == MyMoneyAccount::Investment )
+ {
+ kdDebug(0) << "Line " << m_linenumber << ": Cannot transfer to/from an investment account. Transaction ignored." << endl;
+ return;
+ }
+ if ( account.id() == m_account.id() )
+ {
+ kdDebug(0) << "Line " << m_linenumber << ": Cannot transfer to the same account. Transfer ignored." << endl;
+ accountId = QString();
+ }
+
+ } catch (MyMoneyException *e) {
+ kdDebug(0) << "Line " << m_linenumber << ": Account with id " << accountId.data() << " not found" << endl;
+ accountId = QString();
+ delete e;
+ }
+ }
+
+ if(!accountId.isEmpty()) {
+ s2.m_accountId = accountId;
+ s2.m_strCategoryName = tmp;
+ tr.m_listSplits.append(s2);
+ }
+
+ } else {
+ // split transaction
+ QValueList<qSplit> listqSplits;
+
+ extractSplits(listqSplits); // ****** ensure each field is ******
+ // * attached to correct split *
+ int count;
+
+ for(count = 1; !extractLine('$', count).isEmpty(); ++count)
+ {
+ MyMoneyStatement::Split s2 = s1;
+ s2.m_amount = (-m_qifProfile.value('$', listqSplits[count-1].m_amount)); // Amount of split
+ s2.m_strMemo = listqSplits[count-1].m_strMemo; // Memo in split
+ tmp = listqSplits[count-1].m_strCategoryName; // Category in split
+
+ if(d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1)))
+ {
+ accountId = transferAccount(tmp, false);
+
+ } else {
+ pos = tmp.findRev("--");
+ if(pos != -1) {
+/// t.setValue("Dialog", tmp.mid(pos+2));
+ tmp = tmp.left(pos);
+ }
+ tmp = tmp.stripWhiteSpace();
+ accountId = checkCategory(tmp, s1.m_amount, s2.m_amount);
+ }
+
+ if(!accountId.isEmpty()) {
+ try {
+ MyMoneyAccount account = file->account(accountId);
+ // FIXME: check that the type matches and ask if not
+
+ if ( account.accountType() == MyMoneyAccount::Investment )
+ {
+ kdDebug(0) << "Line " << m_linenumber << ": Cannot convert a split transfer to/from an investment account. Split removed. Total amount adjusted from " << tr.m_amount.formatMoney("", 2) << " to " << (tr.m_amount + s2.m_amount).formatMoney("", 2) << "\n";
+ tr.m_amount += s2.m_amount;
+ continue;
+ }
+ if ( account.id() == m_account.id() )
+ {
+ kdDebug(0) << "Line " << m_linenumber << ": Cannot transfer to the same account. Transfer ignored." << endl;
+ accountId = QString();
+ }
+
+ } catch (MyMoneyException *e) {
+ kdDebug(0) << "Line " << m_linenumber << ": Account with id " << accountId.data() << " not found" << endl;
+ accountId = QString();
+ delete e;
+ }
+ }
+ if(!accountId.isEmpty())
+ {
+ s2.m_accountId = accountId;
+ s2.m_strCategoryName = tmp;
+ tr.m_listSplits += s2;
+ // in case the transaction does not have a memo and we
+ // process the first split just copy the memo over
+ if(tr.m_listSplits.count() == 1 && tr.m_strMemo.isEmpty())
+ tr.m_strMemo = s2.m_strMemo;
+ }
+ else
+ {
+ // TODO add an option to create a "Unassigned" category
+ // for now, we just drop the split which will show up as unbalanced
+ // transaction in the KMyMoney ledger view
+ }
+ }
+ }
+
+ // Add the transaction to the statement
+ d->st.m_listTransactions +=tr;
+}
+
+void MyMoneyQifReader::processInvestmentTransactionEntry(void)
+{
+// kdDebug(2) << "Investment Transaction:" << m_qifEntry.count() << " lines" << endl;
+ /*
+ Items for Investment Accounts
+ Field Indicator Explanation
+ D Date
+ N Action
+ Y Security (NAME, not symbol)
+ I Price
+ Q Quantity (number of shares or split ratio)
+ T Transaction amount
+ C Cleared status
+ P Text in the first line for transfers and reminders (Payee)
+ M Memo
+ O Commission
+ L Account for the transfer
+ $ Amount transferred
+ ^ End of the entry
+
+ It will be presumed all transactions are to the associated cash account, if
+ one exists, unless otherwise noted by the 'L' field.
+
+ Expense/Income categories will be automatically generated, "_Dividend",
+ "_InterestIncome", etc.
+
+ */
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MyMoneyStatement::Transaction tr;
+ d->st.m_eType = MyMoneyStatement::etInvestment;
+
+// t.setCommodity(m_account.currencyId());
+ // 'D' field: Date
+ QDate date = m_qifProfile.date(extractLine('D'));
+ if(date.isValid())
+ tr.m_datePosted = date;
+ else
+ {
+ int rc = KMessageBox::warningContinueCancel(0,
+ i18n("The date entry \"%1\" read from the file cannot be interpreted through the current "
+ "date profile setting of \"%2\".\n\nPressing \"Continue\" will "
+ "assign todays date to the transaction. Pressing \"Cancel\" will abort "
+ "the import operation. You can then restart the import and select a different "
+ "QIF profile or create a new one.")
+ .arg(extractLine('D')).arg(m_qifProfile.inputDateFormat()),
+ i18n("Invalid date format"));
+ switch(rc) {
+ case KMessageBox::Continue:
+ tr.m_datePosted = QDate::currentDate();
+ break;
+
+ case KMessageBox::Cancel:
+ throw new MYMONEYEXCEPTION("USERABORT");
+ break;
+ }
+ }
+
+ // 'M' field: Memo
+ QString memo = extractLine('M');
+ d->fixMultiLineMemo(memo);
+ tr.m_strMemo = memo;
+ unsigned long h;
+
+ h = MyMoneyTransaction::hash(m_qifEntry.join(";"));
+
+ QString hashBase;
+ hashBase.sprintf("%s-%07lx", m_qifProfile.date(extractLine('D')).toString(Qt::ISODate).data(), h);
+ int idx = 1;
+ QString hash;
+ for(;;) {
+ hash = QString("%1-%2").arg(hashBase).arg(idx);
+ QMap<QString, bool>::const_iterator it;
+ it = d->m_hashMap.find(hash);
+ if(it == d->m_hashMap.end()) {
+ d->m_hashMap[hash] = true;
+ break;
+ }
+ ++idx;
+ }
+ tr.m_strBankID = hash;
+
+ // '#' field: BankID
+ QString tmp = extractLine('#');
+ if ( ! tmp.isEmpty() )
+ tr.m_strBankID = QString("ID %1").arg(tmp);
+
+ // Reconciliation flag
+ tr.m_reconcile = d->reconcileState(extractLine('C'));
+
+ // 'O' field: Fees
+ tr.m_fees = m_qifProfile.value('T', extractLine('O'));
+ // 'T' field: Amount
+ MyMoneyMoney amount = m_qifProfile.value('T', extractLine('T'));
+ tr.m_amount = amount;
+
+ MyMoneyStatement::Price price;
+
+ price.m_date = date;
+ price.m_strSecurity = extractLine('Y');
+ price.m_amount = m_qifProfile.value('T', extractLine('I'));
+
+#if 0 // we must check for that later, because certain activities don't need a security
+ // 'Y' field: Security name
+
+ QString securityname = extractLine('Y').lower();
+ if ( securityname.isEmpty() )
+ {
+ kdDebug(2) << "Line " << m_linenumber << ": Investment transaction without a security is not supported." << endl;
+ return;
+ }
+ tr.m_strSecurity = securityname;
+#endif
+
+#if 0
+
+ // For now, we let the statement reader take care of that.
+
+ // The big problem here is that the Y field is not the SYMBOL, it's the NAME.
+ // The name is not very unique, because people could have used slightly different
+ // abbreviations or ordered words differently, etc.
+ //
+ // If there is a perfect name match with a subordinate stock account, great.
+ // More likely, we have to rely on the QIF file containing !Type:Security
+ // records, which tell us the mapping from name to symbol.
+ //
+ // Therefore, generally it is not recommended to import a QIF file containing
+ // investment transactions but NOT containing security records.
+
+ QString securitysymbol = m_investmentMap[securityname];
+
+ // the correct account is the stock account which matches two criteria:
+ // (1) it is a sub-account of the selected investment account, and either
+ // (2a) the security name of the transaction matches the name of the security, OR
+ // (2b) the security name of the transaction maps to a symbol which matches the symbol of the security
+
+ // search through each subordinate account
+ bool found = false;
+ MyMoneyAccount thisaccount = m_account;
+ QStringList accounts = thisaccount.accountList();
+ QStringList::const_iterator it_account = accounts.begin();
+ while( !found && it_account != accounts.end() )
+ {
+ QString currencyid = file->account(*it_account).currencyId();
+ MyMoneySecurity security = file->security( currencyid );
+ QString symbol = security.tradingSymbol().lower();
+ QString name = security.name().lower();
+
+ if ( securityname == name || securitysymbol == symbol )
+ {
+ d->st_AccountId = *it_account;
+ s1.m_accountId = *it_account;
+ thisaccount = file->account(*it_account);
+ found = true;
+
+#if 0
+ // update the price, while we're here. in the future, this should be
+ // an option
+ QString basecurrencyid = file->baseCurrency().id();
+ MyMoneyPrice price = file->price( currencyid, basecurrencyid, t_in.m_datePosted, true );
+ if ( !price.isValid() )
+ {
+ MyMoneyPrice newprice( currencyid, basecurrencyid, t_in.m_datePosted, t_in.m_moneyAmount / t_in.m_dShares, i18n("Statement Importer") );
+ file->addPrice(newprice);
+ }
+#endif
+ }
+
+ ++it_account;
+ }
+
+ if (!found)
+ {
+ kdDebug(2) << "Line " << m_linenumber << ": Security " << securityname << " not found in this account. Transaction ignored." << endl;
+
+ // If the security is not known, notify the user
+ // TODO (Ace) A "SelectOrCreateAccount" interface for investments
+ KMessageBox::information(0, i18n("This investment account does not contain the \"%1\" security. "
+ "Transactions involving this security will be ignored.").arg(securityname),
+ i18n("Security not found"),
+ QString("MissingSecurity%1").arg(securityname.stripWhiteSpace()));
+ return;
+ }
+#endif
+
+ // 'Y' field: Security
+ tr.m_strSecurity = extractLine('Y');
+
+ // 'Q' field: Quantity
+ MyMoneyMoney quantity = m_qifProfile.value('T', extractLine('Q'));
+
+ // 'N' field: Action
+ QString action = extractLine('N').lower();
+
+ // remove trailing X, which seems to have no purpose (?!)
+ bool xAction = false;
+ if ( action.endsWith("x") ) {
+ action = action.left( action.length() - 1 );
+ xAction = true;
+ }
+
+ // Whether to create a cash split for the other side of the value
+ QString accountname ;//= extractLine('L');
+ if ( action == "reinvdiv" || action == "reinvlg" || action == "reinvsh" )
+ {
+ d->st.m_listPrices += price;
+ tr.m_shares = quantity;
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaReinvestDividend);
+ tr.m_price = m_qifProfile.value('I', extractLine('I'));
+
+ tr.m_strInterestCategory = extractLine('L');
+ if(tr.m_strInterestCategory.isEmpty()) {
+ tr.m_strInterestCategory = d->typeToAccountName(action);
+ }
+ }
+ else if ( action == "div" || action == "cgshort" || action == "cgmid" || action == "cglong" || action == "rtrncap")
+ {
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaCashDividend);
+
+ QString tmp = extractLine('L');
+ // if the action ends in an X, the L-Record contains the asset account
+ // to which the dividend should be transferred. In the other cases, it
+ // may contain a category that identifies the income category for the
+ // dividend payment
+ if((xAction == true)
+ && (d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1)) == true)) {
+ tr.m_strBrokerageAccount = tmp;
+ transferAccount(tmp); // make sure the account exists
+ } else {
+ tr.m_strInterestCategory = tmp;
+ }
+
+ // make sure, we have valid category. Either taken from the L-Record above,
+ // or derived from the action code
+ if(tr.m_strInterestCategory.isEmpty()) {
+ tr.m_strInterestCategory = d->typeToAccountName(action);
+ }
+
+ // For historic reasons (coming from the OFX importer) the statement
+ // reader expects the dividend with a reverse sign. So we just do that.
+ tr.m_amount = -(amount - tr.m_fees);
+
+ // We need an extra split which will be the zero-amount investment split
+ // that serves to mark this transaction as a cash dividend and note which
+ // stock account it belongs to.
+ MyMoneyStatement::Split s2;
+ s2.m_amount = MyMoneyMoney();
+ s2.m_strCategoryName = extractLine('Y');
+ tr.m_listSplits.append(s2);
+ }
+ else if ( action == "intinc" || action == "miscinc" || action == "miscexp")
+ {
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaInterest);
+ if(action == "miscexp")
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaFees);
+
+ QString tmp = extractLine('L');
+ // if the action ends in an X, the L-Record contains the asset account
+ // to which the dividend should be transferred. In the other cases, it
+ // may contain a category that identifies the income category for the
+ // payment
+ if((xAction == true)
+ && (d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1)) == true)) {
+ tr.m_strBrokerageAccount = tmp;
+ transferAccount(tmp); // make sure the account exists
+ } else {
+ tr.m_strInterestCategory = tmp;
+ }
+
+ // make sure, we have a valid category. Either taken from the L-Record above,
+ // or derived from the action code
+ if(tr.m_strInterestCategory.isEmpty()) {
+ tr.m_strInterestCategory = d->typeToAccountName(action);
+ }
+
+
+ // For historic reasons (coming from the OFX importer) the statement
+ // reader expects the dividend with a reverse sign. So we just do that.
+ if(action != "miscexp")
+ tr.m_amount = -(amount - tr.m_fees);
+
+ if(tr.m_strMemo.isEmpty())
+ tr.m_strMemo = (QString("%1 %2").arg(extractLine('Y')).arg(d->typeToAccountName(action))).stripWhiteSpace();
+ }
+ else if (action == "xin" || action == "xout")
+ {
+ QString payee = extractLine('P');
+ if(!payee.isEmpty() && ((payee.lower() == "opening balance") || KMyMoneyGlobalSettings::qifOpeningBalance().lower().contains(payee.lower()))) {
+ createOpeningBalance(MyMoneyAccount::Investment);
+ return;
+ }
+
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaNone);
+ MyMoneyStatement::Split s2;
+ QString tmp = extractLine('L');
+ if(d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1))) {
+ s2.m_accountId = transferAccount(tmp);
+ s2.m_strCategoryName = tmp;
+ } else {
+ s2.m_strCategoryName = extractLine('L');
+ if(tr.m_strInterestCategory.isEmpty()) {
+ s2.m_strCategoryName = d->typeToAccountName(action);
+ }
+ }
+
+ if(action == "xout")
+ tr.m_amount = -tr.m_amount;
+
+ s2.m_amount = -tr.m_amount;
+ tr.m_listSplits.append(s2);
+ }
+ else if (action == "buy")
+ {
+ QString tmp = extractLine('L');
+ if(d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1)) == true) {
+ tr.m_strBrokerageAccount = tmp;
+ transferAccount(tmp); // make sure the account exists
+ }
+
+ d->st.m_listPrices += price;
+ tr.m_shares = quantity;
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaBuy);
+ }
+ else if (action == "sell")
+ {
+ QString tmp = extractLine('L');
+ if(d->isTransfer(tmp, m_qifProfile.accountDelimiter().left(1), m_qifProfile.accountDelimiter().mid(1, 1)) == true) {
+ tr.m_strBrokerageAccount = tmp;
+ transferAccount(tmp); // make sure the account exists
+ }
+
+ d->st.m_listPrices += price;
+ tr.m_shares = -quantity;
+ tr.m_amount = -amount;
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaSell);
+ }
+ else if ( action == "shrsin" )
+ {
+ tr.m_shares = quantity;
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaShrsin);
+ }
+ else if ( action == "shrsout" )
+ {
+ tr.m_shares = -quantity;
+ tr.m_eAction = (MyMoneyStatement::Transaction::eaShrsout);
+ }
+ else if ( action == "stksplit" )
+ {
+ MyMoneyMoney splitfactor = (quantity / MyMoneyMoney(10,1)).reduce();
+
+ // Stock splits not supported
+// kdDebug(2) << "Line " << m_linenumber << ": Stock split not supported (date=" << date << " security=" << securityname << " factor=" << splitfactor.toString() << ")" << endl;
+
+// s1.setShares(splitfactor);
+// s1.setValue(0);
+// s1.setAction(MyMoneySplit::ActionSplitShares);
+
+// return;
+ }
+ else
+ {
+ // Unsupported action type
+ kdDebug(0) << "Line " << m_linenumber << ": Unsupported transaction action (" << action << ")" << endl;
+ return;
+ }
+ d->st.m_strAccountName = accountname;
+ d->st.m_listTransactions +=tr;
+
+ /*************************************************************************
+ *
+ * These transactions are natively supported by KMyMoney
+ *
+ *************************************************************************/
+ /*
+ D1/ 3' 5
+ NShrsIn
+ YGENERAL MOTORS CORP 52BR1
+ I20
+ Q200
+ U4,000.00
+ T4,000.00
+ M200 shares added to account @ $20/share
+ ^
+ */
+ /*
+ ^
+ D1/14' 5
+ NShrsOut
+ YTEMPLETON GROWTH 97GJ0
+ Q50
+90 ^
+ */
+ /*
+ D1/28' 5
+ NBuy
+ YGENERAL MOTORS CORP 52BR1
+ I24.35
+ Q100
+ U2,435.00
+ T2,435.00
+ ^
+ */
+ /*
+ D1/ 5' 5
+ NSell
+ YUnited Vanguard
+ I8.41
+ Q50
+ U420.50
+ T420.50
+ ^
+ */
+ /*
+ D1/ 7' 5
+ NReinvDiv
+ YFRANKLIN INCOME 97GM2
+ I38
+ Q1
+ U38.00
+ T38.00
+ ^
+ */
+ /*************************************************************************
+ *
+ * These transactions are all different kinds of income. (Anything that
+ * follows the DNYUT pattern). They are all handled the same, the only
+ * difference is which income account the income is placed into. By
+ * default, it's placed into _xxx where xxx is the right side of the
+ * N field. e.g. NDiv transaction goes into the _Div account
+ *
+ *************************************************************************/
+ /*
+ D1/10' 5
+ NDiv
+ YTEMPLETON GROWTH 97GJ0
+ U10.00
+ T10.00
+ ^
+ */
+ /*
+ D1/10' 5
+ NIntInc
+ YTEMPLETON GROWTH 97GJ0
+ U20.00
+ T20.00
+ ^
+ */
+ /*
+ D1/10' 5
+ NCGShort
+ YTEMPLETON GROWTH 97GJ0
+ U111.00
+ T111.00
+ ^
+ */
+ /*
+ D1/10' 5
+ NCGLong
+ YTEMPLETON GROWTH 97GJ0
+ U333.00
+ T333.00
+ ^
+ */
+ /*
+ D1/10' 5
+ NCGMid
+ YTEMPLETON GROWTH 97GJ0
+ U222.00
+ T222.00
+ ^
+ */
+ /*
+ D2/ 2' 5
+ NRtrnCap
+ YFRANKLIN INCOME 97GM2
+ U1,234.00
+ T1,234.00
+ ^
+ */
+ /*************************************************************************
+ *
+ * These transactions deal with miscellaneous activity that KMyMoney
+ * does not support, but may support in the future.
+ *
+ *************************************************************************/
+ /* Note the Q field is the split ratio per 10 shares, so Q12.5 is a
+ 12.5:10 split, otherwise known as 5:4.
+ D1/14' 5
+ NStkSplit
+ YIBM
+ Q12.5
+ ^
+ */
+ /*************************************************************************
+ *
+ * These transactions deal with short positions and options, which are
+ * not supported at all by KMyMoney. They will be ignored for now.
+ * There may be a way to hack around this, by creating a new security
+ * "IBM_Short".
+ *
+ *************************************************************************/
+ /*
+ D1/21' 5
+ NShtSell
+ YIBM
+ I92.38
+ Q100
+ U9,238.00
+ T9,238.00
+ ^
+ */
+ /*
+ D1/28' 5
+ NCvrShrt
+ YIBM
+ I92.89
+ Q100
+ U9,339.00
+ T9,339.00
+ O50.00
+ ^
+ */
+ /*
+ D6/ 1' 5
+ NVest
+ YIBM Option
+ Q20
+ ^
+ */
+ /*
+ D6/ 8' 5
+ NExercise
+ YIBM Option
+ I60.952381
+ Q20
+ MFrom IBM Option Grant 6/1/2004
+ ^
+ */
+ /*
+ D6/ 1'14
+ NExpire
+ YIBM Option
+ Q5
+ ^
+ */
+ /*************************************************************************
+ *
+ * These transactions do not have an associated investment ("Y" field)
+ * so presumably they are only valid for the cash account. Once I
+ * understand how these are really implemented, they can probably be
+ * handled without much trouble.
+ *
+ *************************************************************************/
+ /*
+ D1/14' 5
+ NCash
+ U-100.00
+ T-100.00
+ LBank Chrg
+ ^
+ */
+ /*
+ D1/15' 5
+ NXOut
+ U500.00
+ T500.00
+ L[CU Savings]
+ $500.00
+ ^
+ */
+ /*
+ D1/28' 5
+ NXIn
+ U1,000.00
+ T1,000.00
+ L[CU Checking]
+ $1,000.00
+ ^
+ */
+ /*
+ D1/25' 5
+ NMargInt
+ U25.00
+ T25.00
+ ^
+ */
+}
+
+const QString MyMoneyQifReader::findOrCreateIncomeAccount(const QString& searchname)
+{
+ QString result;
+
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ // First, try to find this account as an income account
+ MyMoneyAccount acc = file->income();
+ QStringList list = acc.accountList();
+ QStringList::ConstIterator it_accid = list.begin();
+ while ( it_accid != list.end() )
+ {
+ acc = file->account(*it_accid);
+ if ( acc.name() == searchname )
+ {
+ result = *it_accid;
+ break;
+ }
+ ++it_accid;
+ }
+
+ // If we did not find the account, now we must create one.
+ if ( result.isEmpty() )
+ {
+ MyMoneyAccount acc;
+ acc.setName( searchname );
+ acc.setAccountType( MyMoneyAccount::Income );
+ MyMoneyAccount income = file->income();
+ MyMoneyFileTransaction ft;
+ file->addAccount( acc, income );
+ ft.commit();
+ result = acc.id();
+ }
+
+ return result;
+}
+
+// TODO (Ace) Combine this and the previous function
+
+const QString MyMoneyQifReader::findOrCreateExpenseAccount(const QString& searchname)
+{
+ QString result;
+
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ // First, try to find this account as an income account
+ MyMoneyAccount acc = file->expense();
+ QStringList list = acc.accountList();
+ QStringList::ConstIterator it_accid = list.begin();
+ while ( it_accid != list.end() )
+ {
+ acc = file->account(*it_accid);
+ if ( acc.name() == searchname )
+ {
+ result = *it_accid;
+ break;
+ }
+ ++it_accid;
+ }
+
+ // If we did not find the account, now we must create one.
+ if ( result.isEmpty() )
+ {
+ MyMoneyAccount acc;
+ acc.setName( searchname );
+ acc.setAccountType( MyMoneyAccount::Expense );
+ MyMoneyFileTransaction ft;
+ MyMoneyAccount expense = file->expense();
+ file->addAccount( acc, expense );
+ ft.commit();
+ result = acc.id();
+ }
+
+ return result;
+}
+
+QString MyMoneyQifReader::checkCategory(const QString& name, const MyMoneyMoney value, const MyMoneyMoney value2)
+{
+ QString accountId;
+ MyMoneyFile *file = MyMoneyFile::instance();
+ MyMoneyAccount account;
+ bool found = true;
+
+ if(!name.isEmpty()) {
+ // The category might be constructed with an arbitraty depth (number of
+ // colon delimited fields). We try to find a parent account within this
+ // hierarchy by searching the following sequence:
+ //
+ // aaaa:bbbb:cccc:ddddd
+ //
+ // 1. search aaaa:bbbb:cccc:dddd, create nothing
+ // 2. search aaaa:bbbb:cccc , create dddd
+ // 3. search aaaa:bbbb , create cccc:dddd
+ // 4. search aaaa , create bbbb:cccc:dddd
+ // 5. don't search , create aaaa:bbbb:cccc:dddd
+
+ account.setName(name);
+ QString accName; // part to be created (right side in above list)
+ QString parent(name); // a possible parent part (left side in above list)
+ do {
+ accountId = file->categoryToAccount(parent);
+ if(accountId.isEmpty()) {
+ found = false;
+ // prepare next step
+ if(!accName.isEmpty())
+ accName.prepend(':');
+ accName.prepend(parent.section(':', -1));
+ account.setName(accName);
+ parent = parent.section(':', 0, -2);
+ } else if(!accName.isEmpty()) {
+ account.setParentAccountId(accountId);
+ }
+ }
+ while(!parent.isEmpty() && accountId.isEmpty());
+
+ // if we did not find the category, we create it
+ if(!found) {
+ MyMoneyAccount parent;
+ if(account.parentAccountId().isEmpty()) {
+ if(!value.isNegative() && value2.isNegative())
+ parent = file->income();
+ else
+ parent = file->expense();
+ } else {
+ parent = file->account(account.parentAccountId());
+ }
+ account.setAccountType((!value.isNegative() && value2.isNegative()) ? MyMoneyAccount::Income : MyMoneyAccount::Expense);
+ MyMoneyAccount brokerage;
+ // clear out the parent id, because createAccount() does not like that
+ account.setParentAccountId(QString());
+ kmymoney2->createAccount(account, parent, brokerage, MyMoneyMoney());
+ accountId = account.id();
+ }
+ }
+
+ return accountId;
+}
+
+QString MyMoneyQifReader::processAccountEntry(bool resetAccountId)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MyMoneyAccount account;
+ QString tmp;
+
+ account.setName(extractLine('N'));
+ // qDebug("Process account '%s'", account.name().data());
+
+ account.setDescription(extractLine('D'));
+
+ tmp = extractLine('$');
+ if(tmp.length() > 0)
+ account.setValue("lastStatementBalance", tmp);
+
+ tmp = extractLine('/');
+ if(tmp.length() > 0)
+ account.setValue("lastStatementDate", m_qifProfile.date(tmp).toString("yyyy-MM-dd"));
+
+ QifEntryTypeE transactionType = EntryTransaction;
+ QString type = extractLine('T').lower().remove(QRegExp("\\s+"));
+ if(type == m_qifProfile.profileType().lower().remove(QRegExp("\\s+"))) {
+ account.setAccountType(MyMoneyAccount::Checkings);
+ } else if(type == "ccard" || type == "creditcard") {
+ account.setAccountType(MyMoneyAccount::CreditCard);
+ } else if(type == "cash") {
+ account.setAccountType(MyMoneyAccount::Cash);
+ } else if(type == "otha") {
+ account.setAccountType(MyMoneyAccount::Asset);
+ } else if(type == "othl") {
+ account.setAccountType(MyMoneyAccount::Liability);
+ } else if(type == "invst" || type == "port") {
+ account.setAccountType(MyMoneyAccount::Investment);
+ transactionType = EntryInvestmentTransaction;
+ } else if(type == "mutual") { // stock account w/o umbrella investment account
+ account.setAccountType(MyMoneyAccount::Stock);
+ transactionType = EntryInvestmentTransaction;
+ } else if(type == "unknown") {
+ // don't do anything with the type, leave it unknown
+ } else {
+ account.setAccountType(MyMoneyAccount::Checkings);
+ kdDebug(2) << "Line " << m_linenumber << ": Unknown account type '" << type << "', checkings assumed" << endl;
+ }
+
+ // check if we can find the account already in the file
+ MyMoneyAccount acc = kmymoney2->findAccount(account, MyMoneyAccount());
+ if(acc.id().isEmpty()) {
+ // in case the account is not found by name and the type is
+ // unknown, we have to assume something and create a checking account.
+ // this might be wrong, but we have no choice at this point.
+ if(account.accountType() == MyMoneyAccount::UnknownAccountType)
+ account.setAccountType(MyMoneyAccount::Checkings);
+
+ MyMoneyAccount parentAccount;
+ MyMoneyAccount brokerage;
+ MyMoneyMoney balance;
+ // in case it's a stock account, we need to setup a fix investment account
+ if(account.isInvest()) {
+ acc.setName(i18n("%1 (Investment)").arg(account.name())); // use the same name for the investment account
+ acc.setDescription(i18n("Autogenerated by QIF importer from type Mutual account entry"));
+ acc.setAccountType(MyMoneyAccount::Investment);
+ parentAccount = file->asset();
+ kmymoney2->createAccount(acc, parentAccount, brokerage, MyMoneyMoney());
+ parentAccount = acc;
+ qDebug("We still need to create the stock account in MyMoneyQifReader::processAccountEntry()");
+ } else {
+ // setup parent according the type of the account
+ switch(account.accountGroup()) {
+ case MyMoneyAccount::Asset:
+ default:
+ parentAccount = file->asset();
+ break;
+ case MyMoneyAccount::Liability:
+ parentAccount = file->liability();
+ break;
+ case MyMoneyAccount::Equity:
+ parentAccount = file->equity();
+ break;
+ }
+ }
+
+ // investment accounts will receive a brokerage account, as KMyMoney
+ // currently does not allow to store funds in the investment account directly
+ if(account.accountType() == MyMoneyAccount::Investment) {
+ brokerage.setName(account.brokerageName());
+ brokerage.setAccountType(MyMoneyAccount::Checkings);
+ brokerage.setCurrencyId(MyMoneyFile::instance()->baseCurrency().id());
+ }
+ kmymoney2->createAccount(account, parentAccount, brokerage, balance);
+ acc = account;
+ // qDebug("Account created");
+ } else {
+ // qDebug("Existing account found");
+ }
+
+ if(resetAccountId) {
+ // possibly start a new statement
+ d->finishStatement();
+ m_account = acc;
+ d->st.m_accountId = m_account.id();
+ d->transactionType = transactionType;
+ }
+ return acc.id();
+}
+
+void MyMoneyQifReader::selectOrCreateAccount(const SelectCreateMode mode, MyMoneyAccount& account, const MyMoneyMoney& balance)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString accountId;
+ QString msg;
+ QString typeStr;
+ QString leadIn;
+ KMyMoneyUtils::categoryTypeE type;
+
+ QMap<QString, QString>::ConstIterator it;
+
+ type = KMyMoneyUtils::none;
+ switch(account.accountGroup()) {
+ default:
+ type = KMyMoneyUtils::asset;
+ type = (KMyMoneyUtils::categoryTypeE) (type | KMyMoneyUtils::liability);
+ typeStr = i18n("account");
+ leadIn = i18n("al");
+ break;
+
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ type = KMyMoneyUtils::income;
+ type = (KMyMoneyUtils::categoryTypeE) (type | KMyMoneyUtils::expense);
+ typeStr = i18n("category");
+ leadIn = i18n("ei");
+ msg = i18n("Category selection");
+ break;
+ }
+
+ KAccountSelectDlg accountSelect(type, "QifImport", kmymoney2);
+ if(!msg.isEmpty())
+ accountSelect.setCaption(msg);
+
+ it = m_accountTranslation.find((leadIn + MyMoneyFile::AccountSeperator + account.name()).lower());
+ if(it != m_accountTranslation.end()) {
+ try {
+ account = file->account(*it);
+ return;
+
+ } catch (MyMoneyException *e) {
+ QString message(i18n("Account \"%1\" disappeared: ").arg(account.name()));
+ message += e->what();
+ KMessageBox::error(0, message);
+ delete e;
+ }
+ }
+
+ if(!account.name().isEmpty()) {
+ if(type & (KMyMoneyUtils::income | KMyMoneyUtils::expense)) {
+ accountId = file->categoryToAccount(account.name());
+ } else {
+ accountId = file->nameToAccount(account.name());
+ }
+
+ if(mode == Create) {
+ if(!accountId.isEmpty()) {
+ account = file->account(accountId);
+ return;
+
+ } else {
+ switch(KMessageBox::questionYesNo(0,
+ i18n("The %1 '%2' does not exist. Do you "
+ "want to create it?").arg(typeStr).arg(account.name()))) {
+ case KMessageBox::Yes:
+ break;
+ case KMessageBox::No:
+ return;
+ }
+ }
+ } else {
+ accountSelect.setHeader(i18n("Select %1").arg(typeStr));
+ if(!accountId.isEmpty()) {
+ msg = i18n("The %1 <b>%2</b> currently exists. Do you want "
+ "to import transactions to this account?")
+ .arg(typeStr).arg(account.name());
+
+ } else {
+ msg = i18n("The %1 <b>%2</b> currently does not exist. You can "
+ "create a new %3 by pressing the <b>Create</b> button "
+ "or select another %4 manually from the selection box.")
+ .arg(typeStr).arg(account.name()).arg(typeStr).arg(typeStr);
+ }
+ }
+ } else {
+ accountSelect.setHeader(i18n("Import transactions to %1").arg(typeStr));
+ msg = i18n("No %1 information has been found in the selected QIF file. "
+ "Please select an account using the selection box in the dialog or "
+ "create a new %2 by pressing the <b>Create</b> button.")
+ .arg(typeStr).arg(typeStr);
+ }
+
+ accountSelect.setDescription(msg);
+ accountSelect.setAccount(account, accountId);
+ accountSelect.setMode(mode == Create);
+ accountSelect.showAbortButton(true);
+
+ // display current entry in widget, the offending line (if any) will be shown in red
+ QStringList::Iterator it_e;
+ int i = 0;
+ for(it_e = m_qifEntry.begin(); it_e != m_qifEntry.end(); ++it_e) {
+ if(m_extractedLine == i)
+ accountSelect.m_qifEntry->setColor(QColor("red"));
+ accountSelect.m_qifEntry->append(*it_e);
+ accountSelect.m_qifEntry->setColor(QColor("black"));
+ ++i;
+ }
+
+ for(;;) {
+ if(accountSelect.exec() == QDialog::Accepted) {
+ if(!accountSelect.selectedAccount().isEmpty()) {
+ accountId = accountSelect.selectedAccount();
+
+ m_accountTranslation[(leadIn + MyMoneyFile::AccountSeperator + account.name()).lower()] = accountId;
+
+ // MMAccount::openingBalance() is where the accountSelect dialog has
+ // stashed the opening balance that the user chose.
+ MyMoneyAccount importedAccountData(account);
+ // MyMoneyMoney balance = importedAccountData.openingBalance();
+ account = file->account(accountId);
+ if ( ! balance.isZero() )
+ {
+ QString openingtxid = file->openingBalanceTransaction(account);
+ MyMoneyFileTransaction ft;
+ if ( ! openingtxid.isEmpty() )
+ {
+ MyMoneyTransaction openingtx = file->transaction(openingtxid);
+ MyMoneySplit split = openingtx.splitByAccount(account.id());
+
+ if ( split.shares() != balance )
+ {
+ const MyMoneySecurity& sec = file->security(account.currencyId());
+ if ( KMessageBox::questionYesNo(
+ qApp->mainWidget(),
+ i18n("The %1 account currently has an opening balance of %2. This QIF file reports an opening balance of %3. Would you like to overwrite the current balance with the one from the QIF file?").arg(account.name(), split.shares().formatMoney(account, sec), balance.formatMoney(account, sec)),
+ i18n("Overwrite opening balance"),
+ KStdGuiItem::yes(),
+ KStdGuiItem::no(),
+ "OverwriteOpeningBalance" )
+ == KMessageBox::Yes )
+ {
+ file->removeTransaction( openingtx );
+ file->createOpeningBalanceTransaction( account, balance );
+ }
+ }
+ }
+ else
+ {
+ // Add an opening balance
+ file->createOpeningBalanceTransaction( account, balance );
+ }
+ ft.commit();
+ }
+ break;
+ }
+
+ } else if(accountSelect.aborted())
+ throw new MYMONEYEXCEPTION("USERABORT");
+
+ if(typeStr == i18n("account")) {
+ KMessageBox::error(0, i18n("You must select or create an account."));
+ } else {
+ KMessageBox::error(0, i18n("You must select or create a category."));
+ }
+ }
+}
+
+void MyMoneyQifReader::setProgressCallback(void(*callback)(int, int, const QString&))
+{
+ m_progressCallback = callback;
+}
+
+void MyMoneyQifReader::signalProgress(int current, int total, const QString& msg)
+{
+ if(m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+}
+
+void MyMoneyQifReader::processPriceEntry(void)
+{
+/*
+ !Type:Prices
+ "IBM",141 9/16,"10/23/98"
+ ^
+ !Type:Prices
+ "GMW",21.28," 3/17' 5"
+ ^
+ !Type:Prices
+ "GMW",71652181.001,"67/128/ 0"
+ ^
+
+ Note that Quicken will often put in a price with a bogus date and number. We will ignore
+ prices with bogus dates. Hopefully that will catch all of these.
+
+ Also note that prices can be in fractional units, e.g. 141 9/16.
+
+*/
+
+ QStringList::const_iterator it_line = m_qifEntry.begin();
+
+ // Make a price for each line
+ QRegExp priceExp("\"(.*)\",(.*),\"(.*)\"");
+ while ( it_line != m_qifEntry.end() )
+ {
+ if(priceExp.search(*it_line) != -1) {
+ MyMoneyStatement::Price price;
+ price.m_strSecurity = priceExp.cap(1);
+ QString pricestr = priceExp.cap(2);
+ QString datestr = priceExp.cap(3);
+ kdDebug(0) << "Price:" << price.m_strSecurity << " / " << pricestr << " / " << datestr << endl;
+
+ // Only add the price if the date is valid. If invalid, fail silently. See note above.
+ // Also require the price value to not have any slashes. Old prices will be something like
+ // "25 9/16", which we do not support. So we'll skip the price for now.
+ QDate date = m_qifProfile.date(datestr);
+ MyMoneyMoney rate(m_qifProfile.value('P', pricestr));
+ if(date.isValid() && !rate.isZero())
+ {
+ price.m_amount = rate;
+ price.m_date = date;
+ d->st.m_listPrices += price;
+ }
+ }
+ ++it_line;
+ }
+}
+
+void MyMoneyQifReader::processSecurityEntry(void)
+{
+ /*
+ !Type:Security
+ NVANGUARD 500 INDEX
+ SVFINX
+ TMutual Fund
+ ^
+ */
+
+ MyMoneyStatement::Security security;
+ security.m_strName = extractLine('N');
+ security.m_strSymbol = extractLine('S');
+
+ d->st.m_listSecurities += security;
+}
+
+#include "mymoneyqifreader.moc"
diff --git a/kmymoney2/converter/mymoneyqifreader.h b/kmymoney2/converter/mymoneyqifreader.h
new file mode 100644
index 0000000..77bf5ad
--- /dev/null
+++ b/kmymoney2/converter/mymoneyqifreader.h
@@ -0,0 +1,394 @@
+/***************************************************************************
+ mymoneyqifreader.h - description
+ -------------------
+ begin : Mon Jan 27 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYQIFREADER_H
+#define MYMONEYQIFREADER_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <ktempfile.h>
+#include <kprocess.h>
+#include <kurl.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "mymoneyqifprofile.h"
+#include "../mymoney/mymoneyaccount.h"
+#include "../mymoney/mymoneytransaction.h"
+
+class MyMoneyFileTransaction;
+
+/**
+ * @author Thomas Baumgart
+ */
+class MyMoneyQifReader : public QObject
+{
+ Q_OBJECT
+ friend class Private;
+
+private:
+ typedef enum {
+ EntryUnknown = 0,
+ EntryAccount,
+ EntryTransaction,
+ EntryCategory,
+ EntryMemorizedTransaction,
+ EntryInvestmentTransaction,
+ EntrySecurity,
+ EntryPrice,
+ EntryPayee,
+ EntryClass,
+ EntrySkip
+ } QifEntryTypeE;
+
+ struct qSplit
+ {
+ QString m_strCategoryName;
+ QString m_strMemo;
+ QString m_amount;
+ };
+
+
+public:
+ MyMoneyQifReader();
+ ~MyMoneyQifReader();
+
+ /**
+ * This method is used to store the filename into the object.
+ * The file should exist. If it does and an external filter
+ * program is specified with the current selected profile,
+ * the file is send through this filter and the result
+ * is stored in the m_tempFile file.
+ *
+ * @param url URL of the file to be imported
+ */
+ void setURL(const KURL& url);
+
+ /**
+ * This method is used to store the name of the profile into the object.
+ * The selected profile will be loaded if it exists. If an external
+ * filter program is specified with the current selected profile,
+ * the file is send through this filter and the result
+ * is stored in the m_tempFile file.
+ *
+ * @param name QString reference to the name of the profile
+ */
+ void setProfile(const QString& name);
+
+ /**
+ * This method actually starts the import of data from the selected file
+ * into the MyMoney engine.
+ *
+ * This method also starts the user defined import filter program
+ * defined in the QIF profile. If none is defined, the file is read
+ * as is (actually the UNIX command 'cat -' is used as the filter).
+ *
+ * If data from the filter program is available, the slot
+ * slotReceivedDataFromFilter() will be called.
+ *
+ * Make sure to connect the signal importFinished() to detect when
+ * the import actually ended. Call the method finishImport() to clean
+ * things up and get the overall result of the import.
+ *
+ * @retval true the import was started successfully
+ * @retval false the import could not be started.
+ */
+ bool startImport(void);
+
+ /**
+ * This method must be called once the signal importFinished() has
+ * been emitted. It will clean up the reader state and determines
+ * the actual return code of the import.
+ *
+ * @retval true Import was successful.
+ * @retval false Import failed because the filter program terminated
+ * abnormally or the user aborted the import process.
+ */
+ bool finishImport(void);
+
+ void setCategoryMapping(bool map);
+
+ const MyMoneyAccount& account() const { return m_account; };
+
+ void setProgressCallback(void(*callback)(int, int, const QString&));
+
+private:
+ /**
+ * This method is used to update the progress information. It
+ * checks if an appropriate function is known and calls it.
+ *
+ * For a parameter description see KMyMoneyView::progressCallback().
+ */
+ void signalProgress(int current, int total, const QString& = "");
+
+ /**
+ * This method scans a transaction contained in
+ * a QIF file formatted as an account record. This
+ * format is used by MS-Money. If the specific data
+ * is not found, then the data in the entry is treated
+ * as a transaction. In this case, the user will be asked to
+ * specify the account to which the transactions should be imported.
+ * The entry data is found in m_qifEntry.
+ *
+ * @param accountType see MyMoneyAccount() for details. Defaults to MyMoneyAccount::Checkings
+ */
+ void processMSAccountEntry(const MyMoneyAccount::accountTypeE accountType = MyMoneyAccount::Checkings);
+
+ /**
+ * This method scans the m_qifEntry object as a payee record specified by Quicken
+ */
+ void processPayeeEntry(void);
+
+ /**
+ * This method scans the m_qifEntry object as an account record specified
+ * by Quicken. In case @p resetAccountId is @p true (the default), the
+ * global account id will be reset.
+ *
+ * The id of the account will be returned.
+ */
+ QString processAccountEntry(bool resetAccountId = true);
+
+ /**
+ * This method scans the m_qifEntry object as a category record specified
+ * by Quicken.
+ */
+ void processCategoryEntry(void);
+
+ /**
+ * This method scans the m_qifEntry object as a transaction record specified
+ * by Quicken.
+ */
+ void processTransactionEntry(void);
+
+ /**
+ * This method scans the m_qifEntry object as an investment transaction
+ * record specified by Quicken.
+ */
+ void processInvestmentTransactionEntry(void);
+
+ /**
+ * This method scans the m_qifEntry object as a price record specified
+ * by Quicken.
+ */
+ void processPriceEntry(void);
+
+ /**
+ * This method scans the m_qifEntry object as a security record specified
+ * by Quicken.
+ */
+ void processSecurityEntry(void);
+
+ /**
+ * This method processes the lines previously collected in
+ * the member variable m_qifEntry. If further information
+ * by the user is required to process the entry it will
+ * be collected.
+ */
+ void processQifEntry(void);
+
+ /**
+ * This method process a line starting with an exclamation mark
+ */
+ void processQifSpecial(const QString& _line);
+
+ /**
+ * This method is used to get the account id of the split for
+ * a transaction from the text found in the QIF $ or L record.
+ * If an account with the name is not found, the user is asked
+ * if it should be created.
+ *
+ * @param name name of account as found in the QIF file
+ * @param value value found in the T record
+ * @param value2 value found in the $ record for splitted transactions
+ *
+ * @return id of the account for the split. If no name is specified
+ * or the account was not found and not created the
+ * return value will be "".
+ */
+ QString checkCategory(const QString& name, const MyMoneyMoney value, const MyMoneyMoney value2);
+
+ /**
+ * This method extracts the line beginning with the letter @p id
+ * from the lines contained in the QStringList object @p m_qifEntry.
+ * An empty QString is returned, if the line is not found.
+ *
+ * @param id QChar containing the letter to be found
+ * @param cnt return cnt'th of occurance of id in lines. cnt defaults to 1.
+ *
+ * @return QString with the remainder of the line or empty if
+ * @p id is not found in @p lines
+ */
+ const QString extractLine(const QChar id, int cnt = 1);
+
+ /**
+ * This method examines each line in the QStringList object @p m_qifEntry,
+ * searching for split entries, which it extracts into a struct qSplit and
+ * stores all splits found in @p listqSplits .
+ */
+ void extractSplits(QValueList<qSplit>& listqSplits) const;
+
+ enum SelectCreateMode {
+ Create = 0,
+ Select
+ };
+ /**
+ * This method is used to find an account using the account's name
+ * stored in @p account in the current MyMoneyFile object. If it does not
+ * exist, the user has the chance to create it or to skip processing
+ * of this account.
+ *
+ * If an account has been selected, account will be set to contain it's data.
+ * If the skip operation was requested, account will be empty.
+ *
+ * Depending on @p mode the bahaviour of this method is slightly different.
+ * The following table shows the dependencies:
+ *
+ * @code
+ * case mode operation
+ * -----------------------------------------------------------------------------
+ * account with same name exists Create returns immediately
+ * m_account contains data
+ * of existing account
+ *
+ * account does not exist Create immediately calls dialog
+ * to create account
+ *
+ * account with same name exists Select User will be asked if
+ * he wants to use the existing
+ * account or create a new one
+ *
+ * account does not exist Select User will be asked to
+ * select a different account
+ * or create a new one
+ *
+ * @endcode
+ *
+ * @param mode Is either Create or Select depending on the above table
+ * @param account Reference to MyMoneyAccount object
+ */
+
+ void selectOrCreateAccount(const SelectCreateMode mode, MyMoneyAccount& account, const MyMoneyMoney& openingBalance = MyMoneyMoney());
+
+ /**
+ * This method looks up the @p searchname account by name and returns its id
+ * if it was found. If it was not found, it creates a new income account using
+ * @p searchname as a name, and returns the id if the newly created account
+ *
+ * @param searchname The name of the account to find or create
+ * @return QString id of the found or created account
+ */
+ static const QString findOrCreateIncomeAccount(const QString& searchname);
+
+ /**
+ * This method looks up the @p searchname account by name and returns its id
+ * if it was found. If it was not found, it creates a new expense account using
+ * @p searchname as a name, and returns the id if the newly created account
+ *
+ * @param searchname The name of the account to find or create
+ * @return QString id of the found or created account
+ */
+ static const QString findOrCreateExpenseAccount(const QString& searchname);
+
+ /**
+ * This method returns the account id for a given account @a name. In
+ * case @a name references an investment account and @a useBrokerage is @a true
+ * (the default), the id of the corresponding brokerage account will be
+ * returned. In case an account is not existant, it will be created.
+ */
+ QString transferAccount(QString name, bool useBrokerage = true);
+
+ // void processQifLine(void);
+ void createOpeningBalance(MyMoneyAccount::_accountTypeE accType = MyMoneyAccount::Checkings);
+
+signals:
+ /**
+ * This signal will be emitted when the import is finished.
+ */
+ void importFinished(void);
+
+private slots:
+ void slotSendDataToFilter(void);
+ void slotReceivedDataFromFilter(KProcess* /* proc */, char *buff, int len);
+ void slotReceivedErrorFromFilter(KProcess* /* proc */, char *buff, int len);
+ // void slotReceivedDataFromFilter(void);
+ // void slotReceivedErrorFromFilter(void);
+ void slotProcessData(void);
+
+ /**
+ * This slot is used to be informed about the end of the filtering process.
+ * It emits the signal importFinished()
+ */
+ void slotImportFinished(void);
+
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ KProcess m_filter;
+ QString m_filename;
+ KURL m_url;
+ MyMoneyQifProfile m_qifProfile;
+ MyMoneyAccount m_account;
+ unsigned long m_transactionsSkipped;
+ unsigned long m_transactionsProcessed;
+ QStringList m_dontAskAgain;
+ QMap<QString, QString> m_accountTranslation;
+ QMap<QString, QString> m_investmentMap;
+ QFile *m_file;
+ char m_buffer[1024];
+ QCString m_lineBuffer;
+ QStringList m_qifEntry;
+ int m_extractedLine;
+ QString m_qifLine;
+ QStringList m_qifLines;
+ QifEntryTypeE m_entryType;
+ bool m_skipAccount;
+ bool m_processingData;
+ bool m_userAbort;
+ bool m_autoCreatePayee;
+ unsigned long m_pos;
+ unsigned m_linenumber;
+ bool m_warnedInvestment;
+ bool m_warnedSecurity;
+ bool m_warnedPrice;
+ QValueList<MyMoneyTransaction> m_transactionCache;
+
+ QValueList<QByteArray> m_data;
+
+ void (*m_progressCallback)(int, int, const QString&);
+
+ MyMoneyFileTransaction* m_ft;
+};
+
+#endif
diff --git a/kmymoney2/converter/mymoneyqifwriter.cpp b/kmymoney2/converter/mymoneyqifwriter.cpp
new file mode 100644
index 0000000..9526acd
--- /dev/null
+++ b/kmymoney2/converter/mymoneyqifwriter.cpp
@@ -0,0 +1,254 @@
+/***************************************************************************
+ mymoneyqifwriter.cpp - description
+ -------------------
+ begin : Sun Jan 5 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "mymoneyqifwriter.h"
+#include "../mymoney/mymoneyfile.h"
+
+MyMoneyQifWriter::MyMoneyQifWriter()
+{
+}
+
+MyMoneyQifWriter::~MyMoneyQifWriter()
+{
+}
+
+void MyMoneyQifWriter::write(const QString& filename, const QString& profile,
+ const QString& accountId, const bool accountData,
+ const bool categoryData,
+ const QDate& startDate, const QDate& endDate)
+{
+ m_qifProfile.loadProfile("Profile-" + profile);
+
+ QFile qifFile(filename);
+ if(qifFile.open(IO_WriteOnly)) {
+ QTextStream s(&qifFile);
+
+ try {
+ if(categoryData) {
+ writeCategoryEntries(s);
+ }
+
+ if(accountData) {
+ writeAccountEntry(s, accountId, startDate, endDate);
+ }
+ emit signalProgress(-1, -1);
+
+ } catch(MyMoneyException *e) {
+ QString errMsg = i18n("Unexpected exception '%1' thrown in %2, line %3 "
+ "caught in MyMoneyQifWriter::write()")
+ .arg(e->what()).arg(e->file()).arg(e->line());
+
+ KMessageBox::error(0, errMsg);
+ delete e;
+ }
+
+ qifFile.close();
+ } else {
+ KMessageBox::error(0, i18n("Unable to open file '%1' for writing").arg(filename));
+ }
+}
+
+void MyMoneyQifWriter::writeAccountEntry(QTextStream &s, const QString& accountId, const QDate& startDate, const QDate& endDate)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount account;
+
+ account = file->account(accountId);
+ MyMoneyTransactionFilter filter(accountId);
+ filter.setDateFilter(startDate, endDate);
+ QValueList<MyMoneyTransaction> list = file->transactionList(filter);
+ QString openingBalanceTransactionId;
+
+ s << "!Type:" << m_qifProfile.profileType() << endl;
+ if(!startDate.isValid() || startDate <= account.openingDate()) {
+ s << "D" << m_qifProfile.date(account.openingDate()) << endl;
+ openingBalanceTransactionId = file->openingBalanceTransaction(account);
+ MyMoneySplit split;
+ if(!openingBalanceTransactionId.isEmpty()) {
+ MyMoneyTransaction openingBalanceTransaction = file->transaction(openingBalanceTransactionId);
+ split = openingBalanceTransaction.splitByAccount(account.id(), true /* match */);
+ }
+ s << "T" << m_qifProfile.value('T', split.value()) << endl;
+ } else {
+ s << "D" << m_qifProfile.date(startDate) << endl;
+ s << "T" << m_qifProfile.value('T', file->balance(accountId, startDate.addDays(-1))) << endl;
+ }
+ s << "CX" << endl;
+ s << "P" << m_qifProfile.openingBalanceText() << endl;
+ s << "L";
+ if(m_qifProfile.accountDelimiter().length())
+ s << m_qifProfile.accountDelimiter()[0];
+ s << account.name();
+ if(m_qifProfile.accountDelimiter().length() > 1)
+ s << m_qifProfile.accountDelimiter()[1];
+ s << endl;
+ s << "^" << endl;
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ signalProgress(0, list.count());
+ int count = 0;
+ for(it = list.begin(); it != list.end(); ++it) {
+ // don't include the openingBalanceTransaction again
+ if((*it).id() != openingBalanceTransactionId)
+ writeTransactionEntry(s, *it, accountId);
+ signalProgress(++count, 0);
+ }
+}
+
+void MyMoneyQifWriter::writeCategoryEntries(QTextStream &s)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount income;
+ MyMoneyAccount expense;
+
+ income = file->income();
+ expense = file->expense();
+
+ s << "!Type:Cat" << endl;
+ QStringList list = income.accountList() + expense.accountList();
+ emit signalProgress(0, list.count());
+ QStringList::Iterator it;
+ int count = 0;
+ for(it = list.begin(); it != list.end(); ++it) {
+ writeCategoryEntry(s, *it, "");
+ emit signalProgress(++count, 0);
+ }
+}
+
+void MyMoneyQifWriter::writeCategoryEntry(QTextStream &s, const QString& accountId, const QString& leadIn)
+{
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(accountId);
+ QString name = acc.name();
+
+ s << "N" << leadIn << name << endl;
+ s << (MyMoneyAccount::accountGroup(acc.accountType()) == MyMoneyAccount::Expense ? "E" : "I") << endl;
+ s << "^" << endl;
+
+ QStringList list = acc.accountList();
+ QStringList::Iterator it;
+ name += ":";
+ for(it = list.begin(); it != list.end(); ++it) {
+ writeCategoryEntry(s, *it, name);
+ }
+}
+
+void MyMoneyQifWriter::writeTransactionEntry(QTextStream &s, const MyMoneyTransaction& t, const QString& accountId)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneySplit split = t.splitByAccount(accountId);
+
+ s << "D" << m_qifProfile.date(t.postDate()) << endl;
+
+ switch(split.reconcileFlag()) {
+ case MyMoneySplit::Cleared:
+ s << "C*" << endl;
+ break;
+
+ case MyMoneySplit::Reconciled:
+ case MyMoneySplit::Frozen:
+ s << "CX" << endl;
+ break;
+
+ default:
+ break;
+ }
+
+ if(split.memo().length() > 0) {
+ QString m = split.memo();
+ m.replace('\n', "\\n");
+ s << "M" << m << endl;
+ }
+
+ s << "T" << m_qifProfile.value('T', split.value()) << endl;
+
+ if(split.number().length() > 0)
+ s << "N" << split.number() << endl;
+
+ if(!split.payeeId().isEmpty()) {
+ MyMoneyPayee payee = file->payee(split.payeeId());
+ s << "P" << payee.name() << endl;
+ }
+
+ QValueList<MyMoneySplit> list = t.splits();
+ if(list.count() > 1) {
+ MyMoneySplit sp = t.splitByAccount(accountId, false);
+ MyMoneyAccount acc = file->account(sp.accountId());
+ if(acc.accountGroup() != MyMoneyAccount::Income
+ && acc.accountGroup() != MyMoneyAccount::Expense) {
+ s << "L" << m_qifProfile.accountDelimiter()[0]
+ << MyMoneyFile::instance()->accountToCategory(sp.accountId())
+ << m_qifProfile.accountDelimiter()[1] << endl;
+ } else {
+ s << "L" << file->accountToCategory(sp.accountId()) << endl;
+ }
+ if(list.count() > 2) {
+ QValueList<MyMoneySplit>::ConstIterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ if(!((*it) == split)) {
+ writeSplitEntry(s, *it);
+ }
+ }
+ }
+ }
+ s << "^" << endl;
+}
+
+void MyMoneyQifWriter::writeSplitEntry(QTextStream& s, const MyMoneySplit& split)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ s << "S";
+ MyMoneyAccount acc = file->account(split.accountId());
+ if(acc.accountGroup() != MyMoneyAccount::Income
+ && acc.accountGroup() != MyMoneyAccount::Expense) {
+ s << m_qifProfile.accountDelimiter()[0]
+ << file->accountToCategory(split.accountId())
+ << m_qifProfile.accountDelimiter()[1];
+ } else {
+ s << file->accountToCategory(split.accountId());
+ }
+ s << endl;
+
+ if(split.memo().length() > 0) {
+ QString m = split.memo();
+ m.replace('\n', "\\n");
+ s << "E" << m << endl;
+ }
+
+ s << "$" << m_qifProfile.value('$', -split.value()) << endl;
+}
+
+#include "mymoneyqifwriter.moc"
diff --git a/kmymoney2/converter/mymoneyqifwriter.h b/kmymoney2/converter/mymoneyqifwriter.h
new file mode 100644
index 0000000..f77e612
--- /dev/null
+++ b/kmymoney2/converter/mymoneyqifwriter.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+ mymoneyqifwriter.h - description
+ -------------------
+ begin : Sun Jan 5 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYQIFWRITER_H
+#define MYMONEYQIFWRITER_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qobject.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+class MyMoneyTransaction;
+class MyMoneySplit;
+#include "mymoneyqifprofile.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents the QIF writer. All conversion between the
+ * internal representation of accounts, transactions is handled in this
+ * object. The conversion is controlled using a MyMoneyQifProfile to allow
+ * the user to control the conversion.
+ */
+class MyMoneyQifWriter : public QObject
+{
+ Q_OBJECT
+
+public:
+ MyMoneyQifWriter();
+ ~MyMoneyQifWriter();
+
+ /**
+ * This method is used to start the conversion. The parameters control
+ * the destination of the data and the parts that will be exported.
+ * Individual errors will be reported using message boxes.
+ *
+ * @param filename The name of the output file with full path information
+ * @param profile The name of the profile to be used for conversion
+ * @param accountId The id of the account that will be exported
+ * @param accountData If true, the transactions will be exported
+ * @param categoryData If true, the categories will be exported as well
+ * @param startDate Transations before this date will not be exported
+ * @param endDate Transactions after this date will not be exported
+ */
+ void write(const QString& filename, const QString& profile,
+ const QString& accountId, const bool accountData,
+ const bool categoryData,
+ const QDate& startDate, const QDate& endDate);
+
+private:
+ /**
+ * This method writes the entries necessary for an account. First
+ * the leadin, and then the transactions that are in the account
+ * specified by @p accountId in the range from @p startDate to @p
+ * endDate.
+ *
+ * @param s reference to textstream
+ * @param accountId id of the account to be written
+ * @param startDate date from which entries are written
+ * @param endDate date until which entries are written
+ */
+ void writeAccountEntry(QTextStream& s, const QString& accountId, const QDate& startDate, const QDate& endDate);
+
+ /**
+ * This method writes the category entries to the stream
+ * @p s. It writes the leadin and uses writeCategoryEntries()
+ * to write the entries and emits signalProgess() where needed.
+ *
+ * @param s reference to textstream
+ */
+ void writeCategoryEntries(QTextStream& s);
+
+ /**
+ * This method writes the category entry for account with
+ * the ID @p accountId to the stream @p s. All subaccounts
+ * are processed as well.
+ *
+ * @param s reference to textstream
+ * @param accountId id of the account to be written
+ * @param leadIn constant text that will be prepended to the account's name
+ */
+ void writeCategoryEntry(QTextStream& s, const QString& accountId, const QString& leadIn);
+
+ void writeTransactionEntry(QTextStream &s, const MyMoneyTransaction& t, const QString& accountId);
+ void writeSplitEntry(QTextStream &s, const MyMoneySplit& t);
+
+signals:
+ /**
+ * This signal is emitted while the operation progresses.
+ * When the operation starts, the signal is emitted with
+ * @p current being 0 and @p max having the maximum value.
+ *
+ * During the operation, the signal is emitted with @p current
+ * containing the current value on the way to the maximum value.
+ * @p max will be 0 in this case.
+ *
+ * When the operation is finished, the signal is emitted with
+ * @p current and @p max set to -1 to identify the end of the
+ * operation.
+ *
+ * @param current see above
+ * @param max see above
+ */
+ void signalProgress(int current, int max);
+
+private:
+ MyMoneyQifProfile m_qifProfile;
+};
+
+#endif
diff --git a/kmymoney2/converter/mymoneystatementreader.cpp b/kmymoney2/converter/mymoneystatementreader.cpp
new file mode 100644
index 0000000..b804a59
--- /dev/null
+++ b/kmymoney2/converter/mymoneystatementreader.cpp
@@ -0,0 +1,1354 @@
+/***************************************************************************
+ mymoneystatementreader.cpp
+ -------------------
+ begin : Mon Aug 30 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <typeinfo>
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <qtextedit.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <qvbox.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "mymoneystatementreader.h"
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneystatement.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/kmymoneyedit.h>
+#include "../dialogs/kaccountselectdlg.h"
+#include "../dialogs/transactionmatcher.h"
+#include "../dialogs/kenterscheduledlg.h"
+#include "../kmymoney2.h"
+#include <kmymoney/kmymoneyaccountcombo.h>
+
+class MyMoneyStatementReader::Private
+{
+ public:
+ Private() :
+ transactionsCount(0),
+ transactionsAdded(0),
+ transactionsMatched(0),
+ transactionsDuplicate(0),
+ scannedCategories(false)
+ {}
+
+ const QString& feeId(const MyMoneyAccount& invAcc);
+ const QString& interestId(const MyMoneyAccount& invAcc);
+ QString interestId(const QString& name);
+ QString feeId(const QString& name);
+ void assignUniqueBankID(MyMoneySplit& s, const MyMoneyStatement::Transaction& t_in);
+
+ MyMoneyAccount lastAccount;
+ QValueList<MyMoneyTransaction> transactions;
+ QValueList<MyMoneyPayee> payees;
+ int transactionsCount;
+ int transactionsAdded;
+ int transactionsMatched;
+ int transactionsDuplicate;
+ QMap<QString, bool> uniqIds;
+ QMap<QString, MyMoneySecurity> securitiesBySymbol;
+ QMap<QString, MyMoneySecurity> securitiesByName;
+ bool m_skipCategoryMatching;
+ private:
+ void scanCategories(QString& id, const MyMoneyAccount& invAcc, const MyMoneyAccount& parentAccount, const QString& defaultName);
+ QString nameToId(const QString&name, MyMoneyAccount& parent);
+ private:
+ QString m_feeId;
+ QString m_interestId;
+ bool scannedCategories;
+};
+
+
+const QString& MyMoneyStatementReader::Private::feeId(const MyMoneyAccount& invAcc)
+{
+ scanCategories(m_feeId, invAcc, MyMoneyFile::instance()->expense(), i18n("_Fees"));
+ return m_feeId;
+}
+
+const QString& MyMoneyStatementReader::Private::interestId(const MyMoneyAccount& invAcc)
+{
+ scanCategories(m_interestId, invAcc, MyMoneyFile::instance()->income(), i18n("_Dividend"));
+ return m_interestId;
+}
+
+QString MyMoneyStatementReader::Private::nameToId(const QString&name, MyMoneyAccount& parent)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount acc = file->accountByName(name);
+ // if it does not exist, we have to create it
+ if(acc.id().isEmpty()) {
+ acc.setName( name );
+ acc.setAccountType( parent.accountType() );
+ acc.setCurrencyId(parent.currencyId());
+ file->addAccount(acc, parent);
+ }
+ return acc.id();
+}
+
+QString MyMoneyStatementReader::Private::interestId(const QString& name)
+{
+ MyMoneyAccount parent = MyMoneyFile::instance()->income();
+ return nameToId(name, parent);
+}
+
+QString MyMoneyStatementReader::Private::feeId(const QString& name)
+{
+ MyMoneyAccount parent = MyMoneyFile::instance()->expense();
+ return nameToId(name, parent);
+}
+
+
+void MyMoneyStatementReader::Private::scanCategories(QString& id, const MyMoneyAccount& invAcc, const MyMoneyAccount& parentAccount, const QString& defaultName)
+{
+ if(!scannedCategories) {
+ KMyMoneyUtils::previouslyUsedCategories(invAcc.id(), m_feeId, m_interestId);
+ scannedCategories = true;
+ }
+
+ if(id.isEmpty()) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount acc = file->accountByName(defaultName);
+ // if it does not exist, we have to create it
+ if(acc.id().isEmpty()) {
+ MyMoneyAccount parent = parentAccount;
+ acc.setName( defaultName );
+ acc.setAccountType( parent.accountType() );
+ acc.setCurrencyId(parent.currencyId());
+ file->addAccount(acc, parent);
+ }
+ id = acc.id();
+ }
+}
+
+void MyMoneyStatementReader::Private::assignUniqueBankID(MyMoneySplit& s, const MyMoneyStatement::Transaction& t_in)
+{
+ if( ! t_in.m_strBankID.isEmpty() ) {
+ // make sure that id's are unique from this point on by appending a -#
+ // postfix if needed
+ QString base(t_in.m_strBankID);
+ QString hash(base);
+ int idx = 1;
+ for(;;) {
+ QMap<QString, bool>::const_iterator it;
+ it = uniqIds.find(hash);
+ if(it == uniqIds.end()) {
+ uniqIds[hash] = true;
+ break;
+ }
+ hash = QString("%1-%2").arg(base).arg(idx);
+ ++idx;
+ }
+
+ s.setBankID(hash);
+ }
+}
+
+
+MyMoneyStatementReader::MyMoneyStatementReader() :
+ d(new Private),
+ m_userAbort(false),
+ m_autoCreatePayee(false),
+ m_ft(0),
+ m_progressCallback(0)
+{
+ m_askPayeeCategory = KMyMoneyGlobalSettings::askForPayeeCategory();
+}
+
+MyMoneyStatementReader::~MyMoneyStatementReader()
+{
+ delete d;
+}
+
+bool MyMoneyStatementReader::anyTransactionAdded(void) const
+{
+ return (d->transactionsAdded != 0) ? true : false;
+}
+
+void MyMoneyStatementReader::setAutoCreatePayee(bool create)
+{
+ m_autoCreatePayee = create;
+}
+
+void MyMoneyStatementReader::setAskPayeeCategory(bool ask)
+{
+ m_askPayeeCategory = ask;
+}
+
+bool MyMoneyStatementReader::import(const MyMoneyStatement& s, QStringList& messages)
+{
+ //
+ // For testing, save the statement to an XML file
+ // (uncomment this line)
+ //
+ //MyMoneyStatement::writeXMLFile(s,"Imported.Xml");
+
+ //
+ // Select the account
+ //
+
+ m_account = MyMoneyAccount();
+
+ m_ft = new MyMoneyFileTransaction();
+ d->m_skipCategoryMatching = s.m_skipCategoryMatching;
+
+ // if the statement source left some information about
+ // the account, we use it to get the current data of it
+ if(!s.m_accountId.isEmpty()) {
+ try {
+ m_account = MyMoneyFile::instance()->account(s.m_accountId);
+ } catch(MyMoneyException* e) {
+ qDebug("Received reference '%s' to unknown account in statement", s.m_accountId.data());
+ delete e;
+ }
+ }
+
+ if(m_account.id().isEmpty())
+ {
+ m_account.setName(s.m_strAccountName);
+ m_account.setNumber(s.m_strAccountNumber);
+
+ switch ( s.m_eType )
+ {
+ case MyMoneyStatement::etCheckings:
+ m_account.setAccountType(MyMoneyAccount::Checkings);
+ break;
+ case MyMoneyStatement::etSavings:
+ m_account.setAccountType(MyMoneyAccount::Savings);
+ break;
+ case MyMoneyStatement::etInvestment:
+ //testing support for investment statements!
+ //m_userAbort = true;
+ //KMessageBox::error(kmymoney2, i18n("This is an investment statement. These are not supported currently."), i18n("Critical Error"));
+ m_account.setAccountType(MyMoneyAccount::Investment);
+ break;
+ case MyMoneyStatement::etCreditCard:
+ m_account.setAccountType(MyMoneyAccount::CreditCard);
+ break;
+ default:
+ m_account.setAccountType(MyMoneyAccount::Checkings);
+ break;
+ }
+
+
+ // we ask the user only if we have some transactions to process
+ if ( !m_userAbort && s.m_listTransactions.count() > 0)
+ m_userAbort = ! selectOrCreateAccount(Select, m_account);
+ }
+
+ // see if we need to update some values stored with the account
+ if(m_account.value("lastStatementBalance") != s.m_closingBalance.toString()
+ || m_account.value("lastImportedTransactionDate") != s.m_dateEnd.toString(Qt::ISODate)) {
+ if(s.m_closingBalance != MyMoneyMoney::autoCalc) {
+ m_account.setValue("lastStatementBalance", s.m_closingBalance.toString());
+ if ( s.m_dateEnd.isValid() ) {
+ m_account.setValue("lastImportedTransactionDate", s.m_dateEnd.toString(Qt::ISODate));
+ }
+ }
+
+ try {
+ MyMoneyFile::instance()->modifyAccount(m_account);
+ } catch(MyMoneyException* e) {
+ qDebug("Updating account in MyMoneyStatementReader::startImport failed");
+ delete e;
+ }
+ }
+
+
+ if(!m_account.name().isEmpty())
+ messages += i18n("Importing statement for account %1").arg(m_account.name());
+ else if(s.m_listTransactions.count() == 0)
+ messages += i18n("Importing statement without transactions");
+
+ qDebug("Importing statement for '%s'", m_account.name().data());
+
+ //
+ // Process the securities
+ //
+ signalProgress(0, s.m_listSecurities.count(), "Importing Statement ...");
+ int progress = 0;
+ QValueList<MyMoneyStatement::Security>::const_iterator it_s = s.m_listSecurities.begin();
+ while ( it_s != s.m_listSecurities.end() )
+ {
+ processSecurityEntry(*it_s);
+ signalProgress(++progress, 0);
+ ++it_s;
+ }
+ signalProgress(-1, -1);
+
+ //
+ // Process the transactions
+ //
+
+ if ( !m_userAbort )
+ {
+ try {
+ qDebug("Processing transactions (%s)", m_account.name().data());
+ signalProgress(0, s.m_listTransactions.count(), "Importing Statement ...");
+ int progress = 0;
+ QValueList<MyMoneyStatement::Transaction>::const_iterator it_t = s.m_listTransactions.begin();
+ while ( it_t != s.m_listTransactions.end() )
+ {
+ processTransactionEntry(*it_t);
+ signalProgress(++progress, 0);
+ ++it_t;
+ }
+ qDebug("Processing transactions done (%s)", m_account.name().data());
+
+ } catch(MyMoneyException* e) {
+ if(e->what() == "USERABORT")
+ m_userAbort = true;
+ else
+ qDebug("Caught exception from processTransactionEntry() not caused by USERABORT: %s", e->what().data());
+ delete e;
+ }
+ signalProgress(-1, -1);
+ }
+
+ //
+ // process price entries
+ //
+ if ( !m_userAbort )
+ {
+ try {
+ signalProgress(0, s.m_listPrices.count(), "Importing Statement ...");
+ QValueList<MyMoneySecurity> slist = MyMoneyFile::instance()->securityList();
+ QValueList<MyMoneySecurity>::const_iterator it_s;
+ for(it_s = slist.begin(); it_s != slist.end(); ++it_s) {
+ d->securitiesBySymbol[(*it_s).tradingSymbol()] = *it_s;
+ d->securitiesByName[(*it_s).name()] = *it_s;
+ }
+
+ int progress = 0;
+ QValueList<MyMoneyStatement::Price>::const_iterator it_p = s.m_listPrices.begin();
+ while(it_p != s.m_listPrices.end()) {
+ processPriceEntry(*it_p);
+ signalProgress(++progress, 0);
+ ++it_p;
+ }
+ } catch(MyMoneyException* e) {
+ if(e->what() == "USERABORT")
+ m_userAbort = true;
+ else
+ qDebug("Caught exception from processPriceEntry() not caused by USERABORT: %s", e->what().data());
+ delete e;
+ }
+ signalProgress(-1, -1);
+ }
+
+ bool rc = false;
+
+ // delete all payees created in vain
+ int payeeCount = d->payees.count();
+ QValueList<MyMoneyPayee>::const_iterator it_p;
+ for(it_p = d->payees.begin(); it_p != d->payees.end(); ++it_p) {
+ try {
+ MyMoneyFile::instance()->removePayee(*it_p);
+ --payeeCount;
+ } catch(MyMoneyException* e) {
+ // if we can't delete it, it must be in use which is ok for us
+ delete e;
+ }
+ }
+
+ if(s.m_closingBalance.isAutoCalc()) {
+ messages += i18n(" Statement balance is not contained in statement.");
+ } else {
+ messages += i18n(" Statement balance on %1 is reported to be %2").arg(s.m_dateEnd.toString(Qt::ISODate)).arg(s.m_closingBalance.formatMoney("",2));
+ }
+ messages += i18n(" Transactions");
+ messages += i18n(" %1 processed").arg(d->transactionsCount);
+ messages += i18n(" %1 added").arg(d->transactionsAdded);
+ messages += i18n(" %1 matched").arg(d->transactionsMatched);
+ messages += i18n(" %1 duplicates").arg(d->transactionsDuplicate);
+ messages += i18n(" Payees");
+ messages += i18n(" %1 created").arg(payeeCount);
+ messages += QString();
+
+ // remove the Don't ask again entries
+ KConfig* config = KGlobal::config();
+ config->setGroup(QString::fromLatin1("Notification Messages"));
+ QStringList::ConstIterator it;
+
+ for(it = m_dontAskAgain.begin(); it != m_dontAskAgain.end(); ++it) {
+ config->deleteEntry(*it);
+ }
+ config->sync();
+ m_dontAskAgain.clear();
+
+ rc = !m_userAbort;
+
+ // finish the transaction
+ if(rc)
+ m_ft->commit();
+ delete m_ft;
+ m_ft = 0;
+
+ qDebug("Importing statement for '%s' done", m_account.name().data());
+
+ return rc;
+}
+
+void MyMoneyStatementReader::processPriceEntry(const MyMoneyStatement::Price& p_in)
+{
+ if(d->securitiesBySymbol.contains(p_in.m_strSecurity)) {
+
+ MyMoneyPrice price(d->securitiesBySymbol[p_in.m_strSecurity].id(),
+ MyMoneyFile::instance()->baseCurrency().id(),
+ p_in.m_date,
+ p_in.m_amount, "QIF");
+ MyMoneyFile::instance()->addPrice(price);
+
+ } else if(d->securitiesByName.contains(p_in.m_strSecurity)) {
+
+ MyMoneyPrice price(d->securitiesByName[p_in.m_strSecurity].id(),
+ MyMoneyFile::instance()->baseCurrency().id(),
+ p_in.m_date,
+ p_in.m_amount, "QIF");
+ MyMoneyFile::instance()->addPrice(price);
+ }
+
+}
+
+void MyMoneyStatementReader::processSecurityEntry(const MyMoneyStatement::Security& sec_in)
+{
+ // For a security entry, we will just make sure the security exists in the
+ // file. It will not get added to the investment account until it's called
+ // for in a transaction.
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // check if we already have the security
+ // In a statement, we do not know what type of security this is, so we will
+ // not use type as a matching factor.
+ MyMoneySecurity security;
+ QValueList<MyMoneySecurity> list = file->securityList();
+ QValueList<MyMoneySecurity>::ConstIterator it = list.begin();
+ while ( it != list.end() && security.id().isEmpty() )
+ {
+ if(sec_in.m_strSymbol.isEmpty()) {
+ if((*it).name() == sec_in.m_strName)
+ security = *it;
+ } else if((*it).tradingSymbol() == sec_in.m_strSymbol)
+ security = *it;
+ ++it;
+ }
+
+ // if the security was not found, we have to create it while not forgetting
+ // to setup the type
+ if(security.id().isEmpty())
+ {
+ security.setName(sec_in.m_strName);
+ security.setTradingSymbol(sec_in.m_strSymbol);
+ security.setSmallestAccountFraction(1000);
+ security.setTradingCurrency(file->baseCurrency().id());
+ security.setValue("kmm-security-id", sec_in.m_strId);
+ security.setValue("kmm-online-source", "Yahoo");
+ security.setSecurityType(MyMoneySecurity::SECURITY_STOCK);
+ MyMoneyFileTransaction ft;
+ try {
+ file->addSecurity(security);
+ ft.commit();
+ kdDebug(0) << "Created " << security.name() << " with id " << security.id() << endl;
+ } catch(MyMoneyException *e) {
+ KMessageBox::error(0, i18n("Error creating security record: %1").arg(e->what()), i18n("Error"));
+ }
+ } else {
+ kdDebug(0) << "Found " << security.name() << " with id " << security.id() << endl;
+ }
+}
+
+void MyMoneyStatementReader::processTransactionEntry(const MyMoneyStatement::Transaction& t_in)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MyMoneyTransaction t;
+
+#if 0
+ QString dbgMsg;
+ dbgMsg = QString("Process %1, '%3', %2").arg(t_in.m_datePosted.toString(Qt::ISODate)).arg(t_in.m_amount.formatMoney("", 2)).arg(t_in.m_strBankID);
+ qDebug("%s", dbgMsg.data());
+#endif
+
+ // mark it imported for the view
+ t.setImported();
+
+ // TODO (Ace) We can get the commodity from the statement!!
+ // Although then we would need UI to verify
+ t.setCommodity(m_account.currencyId());
+
+ t.setPostDate(t_in.m_datePosted);
+ t.setMemo(t_in.m_strMemo);
+
+#if 0
+ // (acejones) removing this code. keeping it around for reference.
+ //
+ // this is the OLD way of handling bank ID's, which unfortunately was wrong.
+ // bank ID's actually need to go on the split which corresponds with the
+ // account we're importing into.
+ //
+ // thus anywhere "this account" is put into a split is also where we need
+ // to put the bank ID in.
+ //
+ if ( ! t_in.m_strBankID.isEmpty() )
+ t.setBankID(t_in.m_strBankID);
+#endif
+
+ MyMoneySplit s1;
+
+ s1.setMemo(t_in.m_strMemo);
+ s1.setValue(t_in.m_amount - t_in.m_fees);
+ s1.setShares(s1.value());
+ s1.setNumber(t_in.m_strNumber);
+
+ // set these values if a transfer split is needed at the very end.
+ MyMoneyMoney transfervalue;
+
+ // If the user has chosen to import into an investment account, determine the correct account to use
+ MyMoneyAccount thisaccount = m_account;
+ QString brokerageactid;
+
+ if ( thisaccount.accountType() == MyMoneyAccount::Investment )
+ {
+ // determine the brokerage account
+ brokerageactid = m_account.value("kmm-brokerage-account").utf8();
+ if (brokerageactid.isEmpty() )
+ {
+ brokerageactid = file->accountByName(m_account.brokerageName()).id();
+ }
+
+ // find the security transacted, UNLESS this transaction didn't
+ // involve any security.
+ if ( (t_in.m_eAction != MyMoneyStatement::Transaction::eaNone)
+ && (t_in.m_eAction != MyMoneyStatement::Transaction::eaInterest)
+ && (t_in.m_eAction != MyMoneyStatement::Transaction::eaFees))
+ {
+ // the correct account is the stock account which matches two criteria:
+ // (1) it is a sub-account of the selected investment account, and
+ // (2a) the symbol of the underlying security matches the security of the
+ // transaction, or
+ // (2b) the name of the security matches the name of the security of the transaction.
+
+ // search through each subordinate account
+ bool found = false;
+ QStringList accounts = thisaccount.accountList();
+ QStringList::const_iterator it_account = accounts.begin();
+ while( !found && it_account != accounts.end() )
+ {
+ QString currencyid = file->account(*it_account).currencyId();
+ MyMoneySecurity security = file->security( currencyid );
+ if((t_in.m_strSymbol.lower() == security.tradingSymbol().lower())
+ || (t_in.m_strSecurity.lower() == security.name().lower()))
+ {
+ thisaccount = file->account(*it_account);
+ found = true;
+
+ // Don't update price if there is no price information contained in the transaction
+ if(t_in.m_eAction != MyMoneyStatement::Transaction::eaCashDividend
+ && t_in.m_eAction != MyMoneyStatement::Transaction::eaShrsin
+ && t_in.m_eAction != MyMoneyStatement::Transaction::eaShrsout)
+ {
+ // update the price, while we're here. in the future, this should be
+ // an option
+ QString basecurrencyid = file->baseCurrency().id();
+ MyMoneyPrice price = file->price( currencyid, basecurrencyid, t_in.m_datePosted, true );
+ if ( !price.isValid() && ((!t_in.m_amount.isZero() && !t_in.m_shares.isZero()) || !t_in.m_price.isZero()))
+ {
+ MyMoneyPrice newprice;
+ if(!t_in.m_price.isZero()) {
+ newprice = MyMoneyPrice( currencyid, basecurrencyid, t_in.m_datePosted,
+ t_in.m_price.abs(), i18n("Statement Importer") );
+ } else {
+ newprice = MyMoneyPrice( currencyid, basecurrencyid, t_in.m_datePosted,
+ (t_in.m_amount / t_in.m_shares).abs(), i18n("Statement Importer") );
+ }
+ file->addPrice(newprice);
+ }
+ }
+ }
+
+ ++it_account;
+ }
+
+ // If there was no stock account under the m_acccount investment account,
+ // add one using the security.
+ if (!found)
+ {
+ // The security should always be available, because the statement file
+ // should separately list all the securities referred to in the file,
+ // and when we found a security, we added it to the file.
+
+ if ( t_in.m_strSecurity.isEmpty() )
+ {
+ KMessageBox::information(0, i18n("This imported statement contains investment transactions with no security. These transactions will be ignored.").arg(t_in.m_strSecurity),i18n("Security not found"),QString("BlankSecurity"));
+ return;
+ }
+ else
+ {
+ MyMoneySecurity security;
+ QValueList<MyMoneySecurity> list = MyMoneyFile::instance()->securityList();
+ QValueList<MyMoneySecurity>::ConstIterator it = list.begin();
+ while ( it != list.end() && security.id().isEmpty() )
+ {
+ if(t_in.m_strSecurity.lower() == (*it).tradingSymbol().lower()
+ || t_in.m_strSecurity.lower() == (*it).name().lower()) {
+ security = *it;
+ }
+ ++it;
+ }
+ if(!security.id().isEmpty())
+ {
+ thisaccount = MyMoneyAccount();
+ thisaccount.setName(security.name());
+ thisaccount.setAccountType(MyMoneyAccount::Stock);
+ thisaccount.setCurrencyId(security.id());
+
+ file->addAccount(thisaccount, m_account);
+ kdDebug(0) << __func__ << ": created account " << thisaccount.id() << " for security " << t_in.m_strSecurity << " under account " << m_account.id() << endl;
+ }
+ // this security does not exist in the file.
+ else
+ {
+ // This should be rare. A statement should have a security entry for any
+ // of the securities referred to in the transactions. The only way to get
+ // here is if that's NOT the case.
+ KMessageBox::information(0, i18n("This investment account does not contain the \"%1\" security. Transactions involving this security will be ignored.").arg(t_in.m_strSecurity),i18n("Security not found"),QString("MissingSecurity%1").arg(t_in.m_strSecurity.stripWhiteSpace()));
+ return;
+ }
+ }
+ }
+ }
+
+ s1.setAccountId(thisaccount.id());
+ d->assignUniqueBankID(s1, t_in);
+
+ if (t_in.m_eAction==MyMoneyStatement::Transaction::eaReinvestDividend)
+ {
+ s1.setAction(MyMoneySplit::ActionReinvestDividend);
+ s1.setShares(t_in.m_shares);
+
+ if(!t_in.m_price.isZero()) {
+ s1.setPrice(t_in.m_price);
+ } else {
+ s1.setPrice(((t_in.m_amount - t_in.m_fees) / t_in.m_shares).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())));
+ }
+
+
+ MyMoneySplit s2;
+ s2.setMemo(t_in.m_strMemo);
+ if(t_in.m_strInterestCategory.isEmpty())
+ s2.setAccountId(d->interestId(thisaccount));
+ else
+ s2.setAccountId(d->interestId(t_in.m_strInterestCategory));
+
+ s2.setShares(-t_in.m_amount - t_in.m_fees);
+ s2.setValue(s2.shares());
+ t.addSplit(s2);
+ }
+ else if (t_in.m_eAction==MyMoneyStatement::Transaction::eaCashDividend)
+ {
+ // Cash dividends require setting 2 splits to get all of the information
+ // in. Split #1 will be the income split, and we'll set it to the first
+ // income account. This is a hack, but it's needed in order to get the
+ // amount into the transaction.
+
+ // There are some sign issues. The OFX plugin universally reverses the sign
+ // for investment transactions.
+ //
+ // The way we interpret the sign on 'amount' is the s1 split, which is always
+ // the thing that's NOT the cash account. For dividends, it's the income
+ // category, for buy/sell it's the stock account.
+ //
+ // For cash account transactions, the s1 split IS the cash account split,
+ // which explains why they have to be reversed for investment transactions
+ //
+ // Ergo, the 'amount' is negative at this point and needs to stay negative.
+ // The 'fees' is positive.
+ //
+ // This should probably change. It would be more consistent to ALWAYS
+ // interpret the 'amount' as the cash account part.
+
+ if(t_in.m_strInterestCategory.isEmpty())
+ s1.setAccountId(d->interestId(thisaccount));
+ else
+ s1.setAccountId(d->interestId(t_in.m_strInterestCategory));
+ s1.setShares(t_in.m_amount);
+ s1.setValue(t_in.m_amount);
+
+ // Split 2 will be the zero-amount investment split that serves to
+ // mark this transaction as a cash dividend and note which stock account
+ // it belongs to.
+ MyMoneySplit s2;
+ s2.setMemo(t_in.m_strMemo);
+ s2.setAction(MyMoneySplit::ActionDividend);
+ s2.setAccountId(thisaccount.id());
+ t.addSplit(s2);
+
+ transfervalue = -t_in.m_amount - t_in.m_fees;
+ }
+ else if (t_in.m_eAction==MyMoneyStatement::Transaction::eaInterest)
+ {
+ if(t_in.m_strInterestCategory.isEmpty())
+ s1.setAccountId(d->interestId(thisaccount));
+ else
+ s1.setAccountId(d->interestId(t_in.m_strInterestCategory));
+ s1.setShares(t_in.m_amount);
+ s1.setValue(t_in.m_amount);
+
+ transfervalue = -t_in.m_amount;
+
+ }
+ else if (t_in.m_eAction==MyMoneyStatement::Transaction::eaFees)
+ {
+ if(t_in.m_strInterestCategory.isEmpty())
+ s1.setAccountId(d->feeId(thisaccount));
+ else
+ s1.setAccountId(d->feeId(t_in.m_strInterestCategory));
+ s1.setShares(t_in.m_amount);
+ s1.setValue(t_in.m_amount);
+
+ transfervalue = -t_in.m_amount;
+
+ }
+ else if ((t_in.m_eAction==MyMoneyStatement::Transaction::eaBuy ) ||
+ (t_in.m_eAction==MyMoneyStatement::Transaction::eaSell))
+ {
+ if(!t_in.m_price.isZero()) {
+ s1.setPrice(t_in.m_price.abs());
+ } else {
+ MyMoneyMoney total;
+ total = t_in.m_amount - t_in.m_fees;
+ if(!t_in.m_shares.isZero())
+ s1.setPrice((total / t_in.m_shares).abs().convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())));
+ }
+
+ s1.setAction(MyMoneySplit::ActionBuyShares);
+
+ // Make sure to setup the sign correctly
+ if(t_in.m_eAction==MyMoneyStatement::Transaction::eaBuy ) {
+ s1.setShares(t_in.m_shares.abs());
+ s1.setValue(s1.value().abs());
+ transfervalue = -(t_in.m_amount.abs());
+ } else {
+ s1.setShares(-(t_in.m_shares.abs()));
+ s1.setValue(-(s1.value().abs()));
+ transfervalue = t_in.m_amount.abs();
+ }
+
+ }
+ else if ((t_in.m_eAction==MyMoneyStatement::Transaction::eaShrsin) ||
+ (t_in.m_eAction==MyMoneyStatement::Transaction::eaShrsout))
+ {
+ s1.setValue(MyMoneyMoney());
+ s1.setShares(t_in.m_shares);
+ s1.setAction(MyMoneySplit::ActionAddShares);
+ }
+ else if (t_in.m_eAction==MyMoneyStatement::Transaction::eaNone)
+ {
+ // User is attempting to import a non-investment transaction into this
+ // investment account. This is not supportable the way KMyMoney is
+ // written. However, if a user has an associated brokerage account,
+ // we can stuff the transaction there.
+
+ QString brokerageactid = m_account.value("kmm-brokerage-account").utf8();
+ if (brokerageactid.isEmpty() )
+ {
+ brokerageactid = file->accountByName(m_account.brokerageName()).id();
+ }
+ if ( ! brokerageactid.isEmpty() )
+ {
+ s1.setAccountId(brokerageactid);
+ d->assignUniqueBankID(s1, t_in);
+
+ // Needed to satisfy the bankid check below.
+ thisaccount = file->account(brokerageactid);
+ }
+ else
+ {
+ // Warning!! Your transaction is being thrown away.
+ }
+ }
+ if ( !t_in.m_fees.isZero() )
+ {
+ MyMoneySplit s;
+ s.setMemo(i18n("(Fees) ") + t_in.m_strMemo);
+ s.setValue(t_in.m_fees);
+ s.setShares(t_in.m_fees);
+ s.setAccountId(d->feeId(thisaccount));
+ t.addSplit(s);
+ }
+ }
+ else
+ {
+ // For non-investment accounts, just use the selected account
+ // Note that it is perfectly reasonable to import an investment statement into a non-investment account
+ // if you really want. The investment-specific information, such as number of shares and action will
+ // be discarded in that case.
+ s1.setAccountId(m_account.id());
+ d->assignUniqueBankID(s1, t_in);
+ }
+
+
+ QString payeename = t_in.m_strPayee;
+ if(!payeename.isEmpty())
+ {
+ QString payeeid;
+ try {
+ QValueList<MyMoneyPayee> pList = file->payeeList();
+ QValueList<MyMoneyPayee>::const_iterator it_p;
+ QMap<int, QString> matchMap;
+ for(it_p = pList.begin(); it_p != pList.end(); ++it_p) {
+ bool ignoreCase;
+ QStringList keys;
+ QStringList::const_iterator it_s;
+ switch((*it_p).matchData(ignoreCase, keys)) {
+ case MyMoneyPayee::matchDisabled:
+ break;
+
+ case MyMoneyPayee::matchName:
+ keys << QString("%1").arg(QRegExp::escape((*it_p).name()));
+ // tricky fall through here
+
+ case MyMoneyPayee::matchKey:
+ for(it_s = keys.begin(); it_s != keys.end(); ++it_s) {
+ QRegExp exp(*it_s, !ignoreCase);
+ if(exp.search(payeename) != -1) {
+ matchMap[exp.matchedLength()] = (*it_p).id();
+ }
+ }
+ break;
+ }
+ }
+
+ // at this point we can have several scenarios:
+ // a) multiple matches
+ // b) a single match
+ // c) no match at all
+ //
+ // for c) we just do nothing, for b) we take the one we found
+ // in case of a) we take the one with the largest matchedLength()
+ // which happens to be the last one in the map
+ if(matchMap.count() > 1) {
+ QMap<int, QString>::const_iterator it_m = matchMap.end();
+ --it_m;
+ payeeid = *it_m;
+ } else if(matchMap.count() == 1)
+ payeeid = *(matchMap.begin());
+
+ // if we did not find a matching payee, we throw an exception and try to create it
+ if(payeeid.isEmpty())
+ throw new MYMONEYEXCEPTION("payee not matched");
+
+ s1.setPayeeId(payeeid);
+ }
+ catch (MyMoneyException *e)
+ {
+ MyMoneyPayee payee;
+ int rc = KMessageBox::Yes;
+
+ if(m_autoCreatePayee == false) {
+ // Ask the user if that is what he intended to do?
+ QString msg = i18n("Do you want to add \"%1\" as payee/receiver?\n\n").arg(payeename);
+ msg += i18n("Selecting \"Yes\" will create the payee, \"No\" will skip "
+ "creation of a payee record and remove the payee information "
+ "from this transaction. Selecting \"Cancel\" aborts the import "
+ "operation.\n\nIf you select \"No\" here and mark the \"Don't ask "
+ "again\" checkbox, the payee information for all following transactions "
+ "referencing \"%1\" will be removed.").arg(payeename);
+
+ QString askKey = QString("Statement-Import-Payee-")+payeename;
+ if(!m_dontAskAgain.contains(askKey)) {
+ m_dontAskAgain += askKey;
+ }
+ rc = KMessageBox::questionYesNoCancel(0, msg, i18n("New payee/receiver"),
+ KStdGuiItem::yes(), KStdGuiItem::no(), askKey);
+ }
+ delete e;
+
+ if(rc == KMessageBox::Yes) {
+ // for now, we just add the payee to the pool and turn
+ // on simple name matching, so that future transactions
+ // with the same name don't get here again.
+ //
+ // In the future, we could open a dialog and ask for
+ // all the other attributes of the payee, but since this
+ // is called in the context of an automatic procedure it
+ // might distract the user.
+ payee.setName(payeename);
+ payee.setMatchData(MyMoneyPayee::matchName, true, QStringList());
+ if (m_askPayeeCategory) {
+ // We use a QGuardedPtr because the dialog may get deleted
+ // during exec() if the parent of the dialog gets deleted.
+ // In that case the guarded ptr will reset to 0.
+ QGuardedPtr<KDialogBase> dialog = new KDialogBase(
+ "Default Category for Payee",
+ KDialogBase::Yes | KDialogBase::No | KDialogBase::Cancel,
+ KDialogBase::Yes, KDialogBase::Cancel,
+ 0, "questionYesNoCancel", true, true,
+ KGuiItem(i18n("Save Category")),
+ KGuiItem(i18n("No Category")),
+ KGuiItem(i18n("Abort")));
+ QVBox *topcontents = new QVBox (dialog);
+ topcontents->setSpacing(KDialog::spacingHint()*2);
+ topcontents->setMargin(KDialog::marginHint());
+
+ //add in caption? and account combo here
+ QLabel *label1 = new QLabel( topcontents);
+ label1->setText(i18n("Please select a default category for payee '%1':").arg(payee.name().data()));
+
+ QGuardedPtr<KMyMoneyAccountCombo> accountCombo = new KMyMoneyAccountCombo(topcontents);
+ dialog->setMainWidget(topcontents);
+
+ int result = dialog->exec();
+
+ QString accountId;
+ if (accountCombo && !accountCombo->selectedAccounts().isEmpty()) {
+ accountId = accountCombo->selectedAccounts().front();
+ }
+ if (dialog) {
+ delete dialog;
+ }
+ //if they hit yes instead of no, then grab setting of account combo
+ if (result == KDialogBase::Yes) {
+ payee.setDefaultAccountId(accountId);
+ }
+ else if (result != KDialogBase::No) {
+ //add cancel button? and throw exception like below
+ throw new MYMONEYEXCEPTION("USERABORT");
+ }
+ }
+
+ try {
+ file->addPayee(payee);
+ qDebug("Payee '%s' created", payee.name().data());
+ d->payees << payee;
+ payeeid = payee.id();
+ s1.setPayeeId(payeeid);
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to add payee/receiver"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+
+ }
+
+ } else if(rc == KMessageBox::No) {
+ s1.setPayeeId(QString());
+
+ } else {
+ throw new MYMONEYEXCEPTION("USERABORT");
+
+ }
+ }
+
+ if(thisaccount.accountType() != MyMoneyAccount::Stock ) {
+ //
+ // Fill in other side of the transaction (category/etc) based on payee
+ //
+ // Note, this logic is lifted from KLedgerView::slotPayeeChanged(),
+ // however this case is more complicated, because we have an amount and
+ // a memo. We just don't have the other side of the transaction.
+ //
+ // We'll search for the most recent transaction in this account with
+ // this payee. If this reference transaction is a simple 2-split
+ // transaction, it's simple. If it's a complex split, and the amounts
+ // are different, we have a problem. Somehow we have to balance the
+ // transaction. For now, we'll leave it unbalanced, and let the user
+ // handle it.
+ //
+ const MyMoneyPayee& payeeObj = MyMoneyFile::instance()->payee(payeeid);
+ if (t_in.m_listSplits.isEmpty() && payeeObj.defaultAccountEnabled()) {
+ MyMoneySplit s;
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ s.clearId();
+ s.setBankID(QString());
+ s.setShares(-s1.shares());
+ s.setValue(-s1.value());
+ s.setAccountId(payeeObj.defaultAccountId());
+ t.addSplit(s);
+ }
+ else if (t_in.m_listSplits.isEmpty() && !d->m_skipCategoryMatching) {
+ MyMoneyTransactionFilter filter(thisaccount.id());
+ filter.addPayee(payeeid);
+ QValueList<MyMoneyTransaction> list = file->transactionList(filter);
+ if(!list.empty())
+ {
+ // Default to using the most recent transaction as the reference
+ MyMoneyTransaction t_old = list.last();
+
+ // if there is more than one matching transaction, try to be a little
+ // smart about which one we take. for now, we'll see if there's one
+ // with the same VALUE as our imported transaction, and if so take that one.
+ if ( list.count() > 1 )
+ {
+ QValueList<MyMoneyTransaction>::ConstIterator it_trans = list.fromLast();
+ while ( it_trans != list.end() )
+ {
+ MyMoneySplit s = (*it_trans).splitByAccount(thisaccount.id());
+ if ( s.value() == s1.value() )
+ {
+ t_old = *it_trans;
+ break;
+ }
+ --it_trans;
+ }
+ }
+
+ QValueList<MyMoneySplit>::ConstIterator it_split;
+ for(it_split = t_old.splits().begin(); it_split != t_old.splits().end(); ++it_split)
+ {
+ // We don't need the split that covers this account,
+ // we just need the other ones.
+ if ( (*it_split).accountId() != thisaccount.id() )
+ {
+ MyMoneySplit s(*it_split);
+ s.setReconcileFlag(MyMoneySplit::NotReconciled);
+ s.clearId();
+ s.setBankID(QString());
+
+ if ( t_old.splits().count() == 2 )
+ {
+ s.setShares(-s1.shares());
+ s.setValue(-s1.value());
+ s.setMemo(s1.memo());
+ }
+ t.addSplit(s);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ s1.setReconcileFlag(t_in.m_reconcile);
+ t.addSplit(s1);
+
+ // Add the 'account' split if it's needed
+ if ( ! transfervalue.isZero() )
+ {
+ // in case the transaction has a reference to the brokerage account, we use it
+ if(!t_in.m_strBrokerageAccount.isEmpty()) {
+ brokerageactid = file->accountByName(t_in.m_strBrokerageAccount).id();
+ }
+
+ if ( !brokerageactid.isEmpty() )
+ {
+ // FIXME This may not deal with foreign currencies properly
+ MyMoneySplit s;
+ s.setMemo(t_in.m_strMemo);
+ s.setValue(transfervalue);
+ s.setShares(transfervalue);
+ s.setAccountId(brokerageactid);
+ s.setReconcileFlag(t_in.m_reconcile);
+ t.addSplit(s);
+ }
+ }
+
+ if ((t_in.m_eAction != MyMoneyStatement::Transaction::eaReinvestDividend) && (t_in.m_eAction!=MyMoneyStatement::Transaction::eaCashDividend)
+ )
+ {
+ //******************************************
+ // process splits
+ //******************************************
+
+ QValueList<MyMoneyStatement::Split>::const_iterator it_s;
+ for(it_s = t_in.m_listSplits.begin(); it_s != t_in.m_listSplits.end(); ++it_s) {
+ MyMoneySplit s2;
+ s2.setAccountId((*it_s).m_accountId);
+ MyMoneyAccount acc = file->account(s2.accountId());
+ if(acc.isAssetLiability()) {
+ s2.setPayeeId(s1.payeeId());
+ }
+ s2.setMemo((*it_s).m_strMemo);
+ s2.setShares((*it_s).m_amount);
+ s2.setValue((*it_s).m_amount);
+ s2.setReconcileFlag((*it_s).m_reconcile);
+ t.addSplit(s2);
+ }
+
+#if 0
+ QString accountId;
+ int count;
+ int cnt = 0;
+ count = t_in.m_listSplits.count();
+
+ for(cnt = 0; cnt < count; ++cnt )
+ {
+ MyMoneySplit s2 = s1;
+ s2.setMemo(t_in.m_listSplits[cnt].m_strMemo);
+ s2.clearId();
+ s2.setValue(t_in.m_listSplits[cnt].m_amount);
+ s2.setShares(t_in.m_listSplits[cnt].m_amount);
+ s2.setAccountId(QString(t_in.m_listSplits[cnt].m_accountId));
+#if 0
+ accountId = file->nameToAccount(t_in.m_listSplits[cnt].m_strCategoryName);
+ if (accountId.isEmpty())
+ accountId = checkCategory(t_in.m_listSplits[cnt].m_strCategoryName, t_in.m_listSplits[0].m_amount, t_in.m_listSplits[cnt].m_amount);
+
+ s2.setAccountId(accountId);
+#endif
+ t.addSplit(s2);
+ }
+#endif
+ }
+
+ // Add the transaction
+ try {
+
+ // check for matches already stored in the engine
+ MyMoneySplit matchedSplit;
+ TransactionMatcher::autoMatchResultE result;
+ TransactionMatcher matcher(thisaccount);
+ matcher.setMatchWindow(KMyMoneyGlobalSettings::matchInterval());
+ const MyMoneyObject *o = matcher.findMatch(t, s1, matchedSplit, result);
+ d->transactionsCount++;
+
+ // if we did not already find this one, we need to process it
+ if(result != TransactionMatcher::matchedDuplicate) {
+ d->transactionsAdded++;
+ file->addTransaction(t);
+
+ if(o) {
+ if(typeid(*o) == typeid(MyMoneyTransaction)) {
+ // it matched a simple transaction. that's the easy case
+ MyMoneyTransaction tm(*(dynamic_cast<const MyMoneyTransaction*>(o)));
+ switch(result) {
+ case TransactionMatcher::notMatched:
+ case TransactionMatcher::matchedDuplicate:
+ // no need to do anything here
+ break;
+ case TransactionMatcher::matched:
+ case TransactionMatcher::matchedExact:
+ qDebug("Detected as match to transaction '%s'", tm.id().data());
+ matcher.match(tm, matchedSplit, t, s1, true);
+ d->transactionsMatched++;
+ break;
+ }
+
+ } else if(typeid(*o) == typeid(MyMoneySchedule)) {
+ // a match has been found in a pending schedule. We'll ask the user if she wants
+ // to enter the schedule and match it agains the new transaction. Otherwise, we
+ // just leave the transaction as imported.
+ MyMoneySchedule schedule(*(dynamic_cast<const MyMoneySchedule*>(o)));
+ if(KMessageBox::questionYesNo(0, QString("<qt>%1</qt>").arg(i18n("KMyMoney has found a scheduled transaction named <b>%1</b> which matches an imported transaction. Do you want KMyMoney to enter this schedule now so that the transaction can be matched? ").arg(schedule.name())), i18n("Schedule found")) == KMessageBox::Yes) {
+ KEnterScheduleDlg dlg(0, schedule);
+ TransactionEditor* editor = dlg.startEdit();
+ if(editor) {
+ MyMoneyTransaction torig;
+ // in case the amounts of the scheduled transaction and the
+ // imported transaction differ, we need to update the amount
+ // using the transaction editor.
+ if(matchedSplit.shares() != s1.shares() && !schedule.isFixed()) {
+ // for now this only works with regular transactions and not
+ // for investment transactions. As of this, we don't have
+ // scheduled investment transactions anyway.
+ StdTransactionEditor* se = dynamic_cast<StdTransactionEditor*>(editor);
+ if(se) {
+ // the following call will update the amount field in the
+ // editor and also adjust a possible VAT assignment. Make
+ // sure to use only the absolute value of the amount, because
+ // the editor keeps the sign in a different position (deposit,
+ // withdrawal tab)
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(se->haveWidget("amount"));
+ if(amount) {
+ amount->setValue(s1.shares().abs());
+ se->slotUpdateAmount(s1.shares().abs().toString());
+
+ // we also need to update the matchedSplit variable to
+ // have the modified share/value.
+ matchedSplit.setShares(s1.shares());
+ matchedSplit.setValue(s1.value());
+ }
+ }
+ }
+
+ editor->createTransaction(torig, dlg.transaction(), dlg.transaction().splits()[0], true);
+ QString newId;
+ if(editor->enterTransactions(newId, false, true)) {
+ if(!newId.isEmpty()) {
+ torig = MyMoneyFile::instance()->transaction(newId);
+ schedule.setLastPayment(torig.postDate());
+ }
+ schedule.setNextDueDate(schedule.nextPayment(schedule.nextDueDate()));
+ MyMoneyFile::instance()->modifySchedule(schedule);
+ }
+
+ // now match the two transactions
+ matcher.match(torig, matchedSplit, t, s1);
+ d->transactionsMatched++;
+ }
+ delete editor;
+ }
+ }
+ }
+ } else {
+ d->transactionsDuplicate++;
+ qDebug("Detected as duplicate");
+ }
+ delete o;
+ } catch (MyMoneyException *e) {
+ QString message(i18n("Problem adding or matching imported transaction with id '%1': %2").arg(t_in.m_strBankID).arg(e->what()));
+ qDebug("%s", message.data());
+ delete e;
+
+ int result = KMessageBox::warningContinueCancel(0, message);
+ if ( result == KMessageBox::Cancel )
+ throw new MYMONEYEXCEPTION("USERABORT");
+ }
+}
+
+bool MyMoneyStatementReader::selectOrCreateAccount(const SelectCreateMode /*mode*/, MyMoneyAccount& account)
+{
+ bool result = false;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString accountId;
+
+ // Try to find an existing account in the engine which matches this one.
+ // There are two ways to be a "matching account". The account number can
+ // match the statement account OR the "StatementKey" property can match.
+ // Either way, we'll update the "StatementKey" property for next time.
+
+ QString accountNumber = account.number();
+ if ( ! accountNumber.isEmpty() )
+ {
+ // Get a list of all accounts
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+
+ // Iterate through them
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+ while ( it_account != accounts.end() )
+ {
+ if (
+ ( (*it_account).value("StatementKey") == accountNumber ) ||
+ ( (*it_account).number() == accountNumber )
+ )
+ {
+ MyMoneyAccount newAccount((*it_account).id(), account);
+ account = newAccount;
+ accountId = (*it_account).id();
+ break;
+ }
+
+ ++it_account;
+ }
+ }
+
+ QString msg = i18n("<b>You have downloaded a statement for the following account:</b><br><br>");
+ msg += i18n(" - Account Name: %1").arg(account.name()) + "<br>";
+ msg += i18n(" - Account Type: %1").arg(KMyMoneyUtils::accountTypeToString(account.accountType())) + "<br>";
+ msg += i18n(" - Account Number: %1").arg(account.number()) + "<br>";
+ msg += "<br>";
+
+ QString header;
+
+ if(!account.name().isEmpty())
+ {
+ if(!accountId.isEmpty())
+ msg += i18n("Do you want to import transactions to this account?");
+ else
+ msg += i18n("KMyMoney cannot determine which of your accounts to use. You can "
+ "create a new account by pressing the <b>Create</b> button "
+ "or select another one manually from the selection box below.");
+ }
+ else
+ {
+ msg += i18n("No account information has been found in the selected statement file. "
+ "Please select an account using the selection box in the dialog or "
+ "create a new account by pressing the <b>Create</b> button.");
+ }
+
+ KMyMoneyUtils::categoryTypeE type = static_cast<KMyMoneyUtils::categoryTypeE>(KMyMoneyUtils::asset|KMyMoneyUtils::liability);
+ KAccountSelectDlg accountSelect(type, "StatementImport", kmymoney2);
+ accountSelect.setHeader(i18n("Import transactions"));
+ accountSelect.setDescription(msg);
+ accountSelect.setAccount(account, accountId);
+ accountSelect.setMode(false);
+ accountSelect.showAbortButton(true);
+ accountSelect.m_qifEntry->hide();
+ QString accname;
+ bool done = false;
+ while ( !done )
+ {
+ if ( accountSelect.exec() == QDialog::Accepted && !accountSelect.selectedAccount().isEmpty() )
+ {
+ result = true;
+ done = true;
+ accountId = accountSelect.selectedAccount();
+ account = file->account(accountId);
+ if ( ! accountNumber.isEmpty() && account.value("StatementKey") != accountNumber )
+ {
+ account.setValue("StatementKey", accountNumber);
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifyAccount(account);
+ ft.commit();
+ accname = account.name();
+ } catch(MyMoneyException* e) {
+ qDebug("Updating account in MyMoneyStatementReader::selectOrCreateAccount failed");
+ delete e;
+ }
+ }
+ }
+ else
+ {
+ if(accountSelect.aborted())
+ //throw new MYMONEYEXCEPTION("USERABORT");
+ done = true;
+ else
+ KMessageBox::error(0, QString("<qt>%1</qt>").arg(i18n("You must select an account, create a new one, or press the <b>Abort</b> button.")));
+ }
+ }
+ return result;
+}
+
+void MyMoneyStatementReader::setProgressCallback(void(*callback)(int, int, const QString&))
+{
+ m_progressCallback = callback;
+}
+
+void MyMoneyStatementReader::signalProgress(int current, int total, const QString& msg)
+{
+ if(m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+}
+
+
+#include "mymoneystatementreader.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/converter/mymoneystatementreader.h b/kmymoney2/converter/mymoneystatementreader.h
new file mode 100644
index 0000000..46d74d7
--- /dev/null
+++ b/kmymoney2/converter/mymoneystatementreader.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+ mymoneystatementreader
+ -------------------
+ begin : Mon Aug 30 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSTATEMENTREADER_H
+#define MYMONEYSTATEMENTREADER_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <ktempfile.h>
+#include <kprocess.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "mymoneyqifprofile.h"
+#include "../mymoney/mymoneyaccount.h"
+#include "../mymoney/mymoneystatement.h"
+
+class MyMoneyFileTransaction;
+class QStringList;
+
+/**
+ * This is a pared-down version of a MyMoneyQifReader object
+ *
+ * @author Ace Jones
+ */
+class MyMoneyStatementReader : public QObject
+{
+ Q_OBJECT
+
+public:
+ MyMoneyStatementReader();
+ ~MyMoneyStatementReader();
+
+ /**
+ * This method imports data from the MyMoneyStatement object @a s
+ * into the MyMoney engine. It leaves some statistical information
+ * in the @a messages string list
+ *
+ * @retval true the import was processed successfully
+ * @retval false the import resulted in a failure.
+ */
+ bool import(const MyMoneyStatement& s, QStringList& messages);
+
+ /**
+ * This method is used to modify the auto payee creation flag.
+ * If this flag is set, records for payees that are not currently
+ * found in the engine will be automatically created with no
+ * further user interaction required. If this flag is no set,
+ * the user will be asked if the payee should be created or not.
+ * If the MyMoneyQifReader object is created auto payee creation
+ * is turned off.
+ *
+ * @param create flag if this feature should be turned on (@p true)
+ * or turned off (@p false)
+ */
+ void setAutoCreatePayee(bool create);
+ void setAskPayeeCategory(bool ask);
+
+ const MyMoneyAccount& account() const { return m_account; };
+
+ void setProgressCallback(void(*callback)(int, int, const QString&));
+
+ /**
+ * Returns true in case any transaction has been added to the engine
+ * during the import of the statement. Only returns useful result
+ * after import() has been called.
+ */
+ bool anyTransactionAdded(void) const;
+
+private:
+ /**
+ * This method is used to update the progress information. It
+ * checks if an appropriate function is known and calls it.
+ *
+ * For a parameter description see KMyMoneyView::progressCallback().
+ */
+ void signalProgress(int current, int total, const QString& = "");
+
+ void processTransactionEntry(const MyMoneyStatement::Transaction& t_in);
+ void processSecurityEntry(const MyMoneyStatement::Security& s_in);
+ void processPriceEntry(const MyMoneyStatement::Price& p_in);
+
+ enum SelectCreateMode {
+ Create = 0,
+ Select
+ };
+ /**
+ * This method is used to find an account using the account's name
+ * stored in @p account in the current MyMoneyFile object. If it does not
+ * exist, the user has the chance to create it or to skip processing
+ * of this account.
+ *
+ * Please see the documentation for this function in MyMoneyQifReader
+ *
+ * @param mode Is either Create or Select depending on the above table
+ * @param account Reference to MyMoneyAccount object
+ */
+ bool selectOrCreateAccount(const SelectCreateMode mode, MyMoneyAccount& account);
+
+signals:
+ /**
+ * This signal will be emitted when the import is finished.
+ */
+ void importFinished(void);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+ MyMoneyAccount m_account;
+ QStringList m_dontAskAgain;
+ bool m_skipAccount;
+ bool m_userAbort;
+ bool m_autoCreatePayee;
+ bool m_askPayeeCategory;
+ MyMoneyFileTransaction* m_ft;
+
+ void (*m_progressCallback)(int, int, const QString&);
+};
+
+#endif
diff --git a/kmymoney2/converter/mymoneytemplate.cpp b/kmymoney2/converter/mymoneytemplate.cpp
new file mode 100644
index 0000000..63305c6
--- /dev/null
+++ b/kmymoney2/converter/mymoneytemplate.cpp
@@ -0,0 +1,420 @@
+/***************************************************************************
+ mymoneytemplate.cpp - description
+ -------------------
+ begin : Sat Aug 14 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+#include <ksavefile.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneytemplate.h"
+
+MyMoneyTemplate::MyMoneyTemplate() :
+ m_progressCallback(0)
+{
+}
+
+MyMoneyTemplate::MyMoneyTemplate(const KURL& url) :
+ m_progressCallback(0)
+{
+ loadTemplate(url);
+}
+
+MyMoneyTemplate::~MyMoneyTemplate()
+{
+}
+
+bool MyMoneyTemplate::loadTemplate(const KURL& url)
+{
+ QString filename;
+
+ if(!url.isValid()) {
+ qDebug("Invalid template URL '%s'", url.url().latin1());
+ return false;
+ }
+
+ m_source = url;
+ if(url.isLocalFile()) {
+ filename = url.path();
+
+ } else {
+ bool rc;
+ rc = KIO::NetAccess::download(url, filename, qApp->mainWidget());
+ if(!rc) {
+ KMessageBox::detailedError(qApp->mainWidget(),
+ i18n("Error while loading file '%1'!").arg(url.url()),
+ KIO::NetAccess::lastErrorString(),
+ i18n("File access error"));
+ return false;
+ }
+ }
+
+ bool rc = true;
+ QFile file(filename);
+ QFileInfo info(file);
+ if(!info.isFile()) {
+ QString msg=i18n("<b>%1</b> is not a template file.").arg(filename);
+ KMessageBox::error(qApp->mainWidget(), QString("<p>")+msg, i18n("Filetype Error"));
+ return false;
+ }
+
+ if(file.open(IO_ReadOnly)) {
+ QString errMsg;
+ int errLine, errColumn;
+ if(!m_doc.setContent(&file, &errMsg, &errLine, &errColumn)) {
+ QString msg=i18n("Error while reading template file <b>%1</b> in line %2, column %3").arg(filename).arg(errLine).arg(errColumn);
+ KMessageBox::detailedError(qApp->mainWidget(), QString("<p>")+msg, errMsg, i18n("Template Error"));
+ rc = false;
+ } else {
+ rc = loadDescription();
+ }
+ file.close();
+ } else {
+ KMessageBox::sorry(qApp->mainWidget(), i18n("File '%1' not found!").arg(filename));
+ rc = false;
+ }
+
+ // if a temporary file was constructed by NetAccess::download,
+ // then it will be removed with the next call. Otherwise, it
+ // stays untouched on the local filesystem
+ KIO::NetAccess::removeTempFile(filename);
+ return rc;
+}
+
+bool MyMoneyTemplate::loadDescription(void)
+{
+ int validMask = 0x00;
+ const int validAccount = 0x01;
+ const int validTitle = 0x02;
+ const int validShort = 0x04;
+ const int validLong = 0x08;
+ const int invalid = 0x10;
+ const int validHeader = 0x0F;
+
+ QDomElement rootElement = m_doc.documentElement();
+ if(!rootElement.isNull()
+ && rootElement.tagName() == "kmymoney-account-template") {
+ QDomNode child = rootElement.firstChild();
+ while(!child.isNull() && child.isElement()) {
+ QDomElement childElement = child.toElement();
+ // qDebug("MyMoneyTemplate::import: Processing child node %s", childElement.tagName().data());
+ if(childElement.tagName() == "accounts") {
+ m_accounts = childElement.firstChild();
+ validMask |= validAccount;
+ } else if(childElement.tagName() == "title") {
+ m_title = childElement.text();
+ validMask |= validTitle;
+ } else if(childElement.tagName() == "shortdesc") {
+ m_shortDesc = childElement.text();
+ validMask |= validShort;
+ } else if(childElement.tagName() == "longdesc") {
+ m_longDesc = childElement.text();
+ validMask |= validLong;
+ } else {
+ KMessageBox::error(qApp->mainWidget(), QString("<p>")+i18n("Invalid tag <b>%1</b> in template file <b>%2</b>!").arg(childElement.tagName()).arg(m_source.prettyURL()));
+ validMask |= invalid;
+ }
+ child = child.nextSibling();
+ }
+ }
+ return validMask == validHeader;
+}
+
+bool MyMoneyTemplate::hierarchy(QMap<QString, QListViewItem*>& list, const QString& parent, QDomNode account)
+{
+ bool rc = true;
+ while(rc == true && !account.isNull()) {
+ if(account.isElement()) {
+ QDomElement accountElement = account.toElement();
+ if(accountElement.tagName() == "account") {
+ QString name = QString("%1:%2").arg(parent).arg(accountElement.attribute("name"));
+ list[name] = 0;
+ hierarchy(list, name, account.firstChild());
+ }
+ }
+ account = account.nextSibling();
+ }
+ return rc;
+}
+
+void MyMoneyTemplate::hierarchy(QMap<QString, QListViewItem*>& list)
+{
+ bool rc = !m_accounts.isNull();
+ QDomNode accounts = m_accounts;
+ while(rc == true && !accounts.isNull() && accounts.isElement()) {
+ QDomElement childElement = accounts.toElement();
+ if(childElement.tagName() == "account"
+ && childElement.attribute("name") == "") {
+ switch(childElement.attribute("type").toUInt()) {
+ case MyMoneyAccount::Asset:
+ list[i18n("Asset")] = 0;
+ rc = hierarchy(list, i18n("Asset"), childElement.firstChild());
+ break;
+ case MyMoneyAccount::Liability:
+ list[i18n("Liability")] = 0;
+ rc = hierarchy(list, i18n("Liability"), childElement.firstChild());
+ break;
+ case MyMoneyAccount::Income:
+ list[i18n("Income")] = 0;
+ rc = hierarchy(list, i18n("Income"), childElement.firstChild());
+ break;
+ case MyMoneyAccount::Expense:
+ list[i18n("Expense")] = 0;
+ rc = hierarchy(list, i18n("Expense"), childElement.firstChild());
+ break;
+ case MyMoneyAccount::Equity:
+ list[i18n("Equity")] = 0;
+ rc = hierarchy(list, i18n("Equity"), childElement.firstChild());
+ break;
+
+ default:
+ rc = false;
+ break;
+ }
+ } else {
+ rc = false;
+ }
+ accounts = accounts.nextSibling();
+ }
+}
+
+bool MyMoneyTemplate::importTemplate(void(*callback)(int, int, const QString&))
+{
+ m_progressCallback = callback;
+ bool rc = !m_accounts.isNull();
+ MyMoneyFile* file = MyMoneyFile::instance();
+ signalProgress(0, m_doc.elementsByTagName("account").count(), i18n("Loading template %1").arg(m_source.url()));
+ m_accountsRead = 0;
+
+ while(rc == true && !m_accounts.isNull() && m_accounts.isElement()) {
+ QDomElement childElement = m_accounts.toElement();
+ if(childElement.tagName() == "account"
+ && childElement.attribute("name") == "") {
+ ++m_accountsRead;
+ MyMoneyAccount parent;
+ switch(childElement.attribute("type").toUInt()) {
+ case MyMoneyAccount::Asset:
+ parent = file->asset();
+ break;
+ case MyMoneyAccount::Liability:
+ parent = file->liability();
+ break;
+ case MyMoneyAccount::Income:
+ parent = file->income();
+ break;
+ case MyMoneyAccount::Expense:
+ parent = file->expense();
+ break;
+ case MyMoneyAccount::Equity:
+ parent = file->equity();
+ break;
+
+ default:
+ KMessageBox::error(qApp->mainWidget(), QString("<p>")+i18n("Invalid top-level account type <b>%1</b> in template file <b>%2</b>!").arg(childElement.attribute("type")).arg(m_source.prettyURL()));
+ rc = false;
+ }
+
+ if(rc == true) {
+ rc = createAccounts(parent, childElement.firstChild());
+ }
+ } else {
+ rc = false;
+ }
+ m_accounts = m_accounts.nextSibling();
+ }
+ signalProgress(-1, -1);
+ return rc;
+}
+
+bool MyMoneyTemplate::createAccounts(MyMoneyAccount& parent, QDomNode account)
+{
+ bool rc = true;
+ while(rc == true && !account.isNull()) {
+ MyMoneyAccount acc;
+ if(account.isElement()) {
+ QDomElement accountElement = account.toElement();
+ if(accountElement.tagName() == "account") {
+ signalProgress(++m_accountsRead, 0);
+ QValueList<MyMoneyAccount> subAccountList;
+ QValueList<MyMoneyAccount>::ConstIterator it;
+ it = subAccountList.end();
+ if(!parent.accountList().isEmpty()) {
+ MyMoneyFile::instance()->accountList(subAccountList, parent.accountList());
+ for(it = subAccountList.begin(); it != subAccountList.end(); ++it) {
+ if((*it).name() == accountElement.attribute("name")) {
+ acc = *it;
+ break;
+ }
+ }
+ }
+ if(it == subAccountList.end()) {
+ // not found, we need to create it
+ acc.setName(accountElement.attribute("name"));
+ acc.setAccountType(static_cast<MyMoneyAccount::_accountTypeE>(accountElement.attribute("type").toUInt()));
+ setFlags(acc, account.firstChild());
+ try {
+ MyMoneyFile::instance()->addAccount(acc, parent);
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+ createAccounts(acc, account.firstChild());
+ }
+ }
+ account = account.nextSibling();
+ }
+ return rc;
+}
+
+bool MyMoneyTemplate::setFlags(MyMoneyAccount& acc, QDomNode flags)
+{
+ bool rc = true;
+ while(rc == true && !flags.isNull()) {
+ if(flags.isElement()) {
+ QDomElement flagElement = flags.toElement();
+ if(flagElement.tagName() == "flag") {
+ // make sure, we only store flags we know!
+ QString value = flagElement.attribute("name");
+ if(value == "Tax") {
+ acc.setValue(value.latin1(), "Yes");
+ } else {
+ KMessageBox::error(qApp->mainWidget(), QString("<p>")+i18n("Invalid flag type <b>%1</b> for account <b>%3</b> in template file <b>%2</b>!").arg(flagElement.attribute("name")).arg(m_source.prettyURL()).arg(acc.name()));
+ rc = false;
+ }
+ }
+ }
+ flags = flags.nextSibling();
+ }
+ return rc;
+}
+
+void MyMoneyTemplate::signalProgress(int current, int total, const QString& msg)
+{
+ if(m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+}
+
+bool MyMoneyTemplate::exportTemplate(void(*callback)(int, int, const QString&))
+{
+ m_progressCallback = callback;
+
+ m_doc = QDomDocument("KMYMONEY-TEMPLATE");
+
+ QDomProcessingInstruction instruct = m_doc.createProcessingInstruction(QString("xml"), QString("version=\"1.0\" encoding=\"utf-8\""));
+ m_doc.appendChild(instruct);
+
+ QDomElement mainElement = m_doc.createElement("kmymoney-account-template");
+ m_doc.appendChild(mainElement);
+
+ QDomElement title = m_doc.createElement("title");
+ mainElement.appendChild(title);
+
+ QDomElement shortDesc = m_doc.createElement("shortdesc");
+ mainElement.appendChild(shortDesc);
+
+ QDomElement longDesc = m_doc.createElement("longdesc");
+ mainElement.appendChild(longDesc);
+
+ QDomElement accounts = m_doc.createElement("accounts");
+ mainElement.appendChild(accounts);
+
+ // addAccountStructure(accounts, MyMoneyFile::instance()->asset());
+ // addAccountStructure(accounts, MyMoneyFile::instance()->liability());
+ addAccountStructure(accounts, MyMoneyFile::instance()->income());
+ addAccountStructure(accounts, MyMoneyFile::instance()->expense());
+ // addAccountStructure(accounts, MyMoneyFile::instance()->equity());
+
+ return true;
+}
+
+bool MyMoneyTemplate::addAccountStructure(QDomElement& parent, const MyMoneyAccount& acc)
+{
+ QDomElement account = m_doc.createElement("account");
+ parent.appendChild(account);
+
+ if(MyMoneyFile::instance()->isStandardAccount(acc.id()))
+ account.setAttribute(QString("name"), QString());
+ else
+ account.setAttribute(QString("name"), acc.name());
+ account.setAttribute(QString("type"), acc.accountType());
+
+ // FIXME: add tax flag stuff
+
+ // any child accounts?
+ if(acc.accountList().count() > 0) {
+ QValueList<MyMoneyAccount> list;
+ MyMoneyFile::instance()->accountList(list, acc.accountList(), false);
+ QValueList<MyMoneyAccount>::Iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ addAccountStructure(account, *it);
+ }
+ }
+ return true;
+}
+
+bool MyMoneyTemplate::saveTemplate(const KURL& url)
+{
+ QString filename;
+
+ if(!url.isValid()) {
+ qDebug("Invalid template URL '%s'", url.url().latin1());
+ return false;
+ }
+
+ if(url.isLocalFile()) {
+ filename = url.path();
+ KSaveFile qfile(filename, 0600);
+ if(qfile.status() == 0) {
+ saveToLocalFile(qfile.file());
+ if(!qfile.close()) {
+ throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").arg(filename));
+ }
+ } else {
+ throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").arg(filename));
+ }
+ } else {
+ KTempFile tmpfile;
+ saveToLocalFile(tmpfile.file());
+ if(!KIO::NetAccess::upload(tmpfile.name(), url, NULL))
+ throw new MYMONEYEXCEPTION(i18n("Unable to upload to '%1'").arg(url.url()));
+ tmpfile.unlink();
+ }
+ return true;
+}
+
+bool MyMoneyTemplate::saveToLocalFile(QFile* qfile)
+{
+ QTextStream stream(qfile);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << m_doc.toString();
+
+ return true;
+}
diff --git a/kmymoney2/converter/mymoneytemplate.h b/kmymoney2/converter/mymoneytemplate.h
new file mode 100644
index 0000000..5c96b1f
--- /dev/null
+++ b/kmymoney2/converter/mymoneytemplate.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ mymoneytemplate.h - description
+ -------------------
+ begin : Sat Aug 14 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYTEMPLATE_H
+#define MYMONEYTEMPLATE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdom.h>
+class QFile;
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kurl.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyfile.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents an account template handler. It is capable
+ * to read an XML formatted account template file and import it into
+ * the current engine. Also, it can save the current account structure
+ * of the engine to an XML formatted template file.
+ */
+class MyMoneyTemplate
+{
+public:
+ MyMoneyTemplate();
+ MyMoneyTemplate(const KURL& url);
+ ~MyMoneyTemplate();
+
+ bool loadTemplate(const KURL& url);
+ bool saveTemplate(const KURL& url);
+ bool importTemplate(void(*callback)(int, int, const QString&));
+ bool exportTemplate(void(*callback)(int, int, const QString&));
+
+ const QString& title(void) const { return m_title; }
+ const QString& shortDescription(void) const { return m_shortDesc; }
+ const QString& longDescription(void) const { return m_longDesc; }
+
+ void hierarchy(QMap<QString, QListViewItem*>& list);
+
+protected:
+ bool loadDescription(void);
+ bool createAccounts(MyMoneyAccount& parent, QDomNode account);
+ bool setFlags(MyMoneyAccount& acc, QDomNode flags);
+ bool saveToLocalFile(QFile* qfile);
+ bool addAccountStructure(QDomElement& parent, const MyMoneyAccount& acc);
+ bool hierarchy(QMap<QString, QListViewItem*>& list, const QString& parent, QDomNode account);
+
+ /**
+ * This method is used to update the progress information. It
+ * checks if an appropriate function is known and calls it.
+ *
+ * For a parameter description see KMyMoneyView::progressCallback().
+ */
+ void signalProgress(int current, int total, const QString& = "");
+
+private:
+ QDomDocument m_doc;
+ QDomNode m_accounts;
+ QString m_title;
+ QString m_shortDesc;
+ QString m_longDesc;
+ KURL m_source;
+ void (*m_progressCallback)(int, int, const QString&);
+ int m_accountsRead;
+};
+
+#endif
diff --git a/kmymoney2/converter/webpricequote.cpp b/kmymoney2/converter/webpricequote.cpp
new file mode 100644
index 0000000..de30963
--- /dev/null
+++ b/kmymoney2/converter/webpricequote.cpp
@@ -0,0 +1,1050 @@
+/***************************************************************************
+ webpricequote.cpp
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Ace Jones
+ email : Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qprocess.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kio/netaccess.h>
+#include <kio/scheduler.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kcalendarsystem.h>
+#include <ktempfile.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "../mymoney/mymoneyexception.h"
+#include "mymoneyqifprofile.h"
+#include "webpricequote.h"
+
+// define static members
+QString WebPriceQuote::m_financeQuoteScriptPath;
+QStringList WebPriceQuote::m_financeQuoteSources;
+
+QString * WebPriceQuote::lastErrorMsg;
+int WebPriceQuote::lastErrorCode = 0;
+
+WebPriceQuote::WebPriceQuote( QObject* _parent, const char* _name ):
+ QObject( _parent, _name )
+{
+ m_financeQuoteScriptPath =
+ KGlobal::dirs()->findResource("appdata", QString("misc/financequote.pl"));
+ connect(&m_filter,SIGNAL(processExited(const QString&)),this,SLOT(slotParseQuote(const QString&)));
+}
+
+WebPriceQuote::~WebPriceQuote()
+{
+}
+
+bool WebPriceQuote::launch( const QString& _symbol, const QString& _id, const QString& _sourcename )
+{
+ if (_sourcename.contains("Finance::Quote"))
+ return (launchFinanceQuote (_symbol, _id, _sourcename));
+ else
+ return (launchNative (_symbol, _id, _sourcename));
+}
+
+bool WebPriceQuote::launchNative( const QString& _symbol, const QString& _id, const QString& _sourcename ) {
+ bool result = true;
+ m_symbol = _symbol;
+ m_id = _id;
+
+// emit status(QString("(Debug) symbol=%1 id=%2...").arg(_symbol,_id));
+
+ // if we're running normally, with a UI, we can just get these the normal way,
+ // from the config file
+ if ( kapp )
+ {
+ QString sourcename = _sourcename;
+ if ( sourcename.isEmpty() )
+ sourcename = "Yahoo";
+
+ if ( quoteSources().contains(sourcename) )
+ m_source = WebPriceQuoteSource(sourcename);
+ else
+ emit error(QString("Source <%1> does not exist.").arg(sourcename));
+ }
+ // otherwise, if we have no kapp, we have no config. so we just get them from
+ // the defaults
+ else
+ {
+ if ( _sourcename.isEmpty() )
+ m_source = defaultQuoteSources()["Yahoo"];
+ else
+ m_source = defaultQuoteSources()[_sourcename];
+ }
+
+ KURL url;
+
+ // if the source has room for TWO symbols..
+ if ( m_source.m_url.contains("%2") )
+ {
+ // this is a two-symbol quote. split the symbol into two. valid symbol
+ // characters are: 0-9, A-Z and the dot. anything else is a separator
+ QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)",false /*case sensitive*/);
+
+ // if we've truly found 2 symbols delimited this way...
+ if ( splitrx.search(m_symbol) != -1 )
+ url = KURL::fromPathOrURL(m_source.m_url.arg(splitrx.cap(1),splitrx.cap(2)));
+ else
+ kdDebug(2) << "WebPriceQuote::launch() did not find 2 symbols" << endl;
+ }
+ else
+ // a regular one-symbol quote
+ url = KURL::fromPathOrURL(m_source.m_url.arg(m_symbol));
+
+ // If we're running a non-interactive session (with no UI), we can't
+ // use KIO::NetAccess, so we have to get our web data the old-fashioned
+ // way... with 'wget'.
+ //
+ // Note that a 'non-interactive' session right now means only the test
+ // cases. Although in the future if KMM gains a non-UI mode, this would
+ // still be useful
+ if ( ! kapp && ! url.isLocalFile() )
+ url = KURL::fromPathOrURL("/usr/bin/wget -O - " + url.prettyURL());
+
+ if ( url.isLocalFile() )
+ {
+ emit status(QString("Executing %1...").arg(url.path()));
+
+ m_filter.clearArguments();
+ m_filter << QStringList::split(" ",url.path());
+ m_filter.setSymbol(m_symbol);
+
+ // if we're running non-interactive, we'll need to block.
+ // otherwise, just let us know when it's done.
+ KProcess::RunMode mode = KProcess::NotifyOnExit;
+ if ( ! kapp )
+ mode = KProcess::Block;
+
+ if(m_filter.start(mode, KProcess::All))
+ {
+ result = true;
+ m_filter.resume();
+ }
+ else
+ {
+ emit error(QString("Unable to launch: %1").arg(url.path()));
+ slotParseQuote(QString());
+ }
+ }
+ else
+ {
+ emit status(QString("Fetching URL %1...").arg(url.prettyURL()));
+
+ QString tmpFile;
+ if( download( url, tmpFile, NULL ) )
+ {
+ kdDebug(2) << "Downloaded " << tmpFile << endl;
+ QFile f(tmpFile);
+ if ( f.open( IO_ReadOnly ) )
+ {
+ result = true;
+ QString quote = QTextStream(&f).read();
+ f.close();
+ slotParseQuote(quote);
+ }
+ else
+ {
+ slotParseQuote(QString());
+ }
+ removeTempFile( tmpFile );
+ }
+ else
+ {
+ emit error(KIO::NetAccess::lastErrorString());
+ slotParseQuote(QString());
+ }
+ }
+ return result;
+}
+
+void WebPriceQuote::removeTempFile(const QString& tmpFile)
+{
+ if(tmpFile == m_tmpFile) {
+ unlink(tmpFile);
+ m_tmpFile = QString();
+ }
+}
+
+bool WebPriceQuote::download(const KURL& u, QString & target, QWidget* window)
+{
+ m_tmpFile = QString();
+
+ // the following code taken and adapted from KIO::NetAccess::download()
+ if (target.isEmpty())
+ {
+ KTempFile tmpFile;
+ target = tmpFile.name();
+ m_tmpFile = target;
+ }
+
+ KURL dest;
+ dest.setPath( target );
+
+
+ // the following code taken and adapted from KIO::NetAccess::filecopyInternal()
+ bJobOK = true; // success unless further error occurs
+
+ KIO::Scheduler::checkSlaveOnHold(true);
+ KIO::Job * job = KIO::file_copy( u, dest, -1, true, false, false );
+ job->setWindow (window);
+ job->addMetaData("cache", "reload"); // bypass cache
+ connect( job, SIGNAL( result (KIO::Job *) ),
+ this, SLOT( slotResult (KIO::Job *) ) );
+
+ enter_loop();
+ return bJobOK;
+
+}
+
+// The following parts are copied and adjusted from KIO::NetAccess
+
+// If a troll sees this, he kills me
+void qt_enter_modal( QWidget *widget );
+void qt_leave_modal( QWidget *widget );
+
+void WebPriceQuote::enter_loop(void)
+{
+ QWidget dummy(0,0,WType_Dialog | WShowModal);
+ dummy.setFocusPolicy( QWidget::NoFocus );
+ qt_enter_modal(&dummy);
+ qApp->enter_loop();
+ qt_leave_modal(&dummy);
+}
+
+void WebPriceQuote::slotResult( KIO::Job * job )
+{
+ lastErrorCode = job->error();
+ bJobOK = !job->error();
+ if ( !bJobOK )
+ {
+ if ( !lastErrorMsg )
+ lastErrorMsg = new QString;
+ *lastErrorMsg = job->errorString();
+ }
+
+ qApp->exit_loop();
+}
+// The above parts are copied and adjusted from KIO::NetAccess
+
+bool WebPriceQuote::launchFinanceQuote ( const QString& _symbol, const QString& _id,
+ const QString& _sourcename ) {
+ bool result = true;
+ m_symbol = _symbol;
+ m_id = _id;
+ QString FQSource = _sourcename.section (" ", 1);
+ m_source = WebPriceQuoteSource (_sourcename, m_financeQuoteScriptPath,
+ "\"([^,\"]*)\",.*", // symbol regexp
+ "[^,]*,[^,]*,\"([^\"]*)\"", // price regexp
+ "[^,]*,([^,]*),.*", // date regexp
+ "%y-%m-%d"); // date format
+
+ //emit status(QString("(Debug) symbol=%1 id=%2...").arg(_symbol,_id));
+
+
+ m_filter.clearArguments();
+ m_filter << "perl" << m_financeQuoteScriptPath << FQSource << KProcess::quote(_symbol);
+ m_filter.setUseShell(true);
+ m_filter.setSymbol(m_symbol);
+ emit status(QString("Executing %1 %2 %3...").arg(m_financeQuoteScriptPath).arg(FQSource).arg(_symbol));
+
+ // if we're running non-interactive, we'll need to block.
+ // otherwise, just let us know when it's done.
+ KProcess::RunMode mode = KProcess::NotifyOnExit;
+ if ( ! kapp )
+ mode = KProcess::Block;
+
+ if(m_filter.start(mode, KProcess::All))
+ {
+ result = true;
+ m_filter.resume();
+ }
+ else
+ {
+ emit error(QString("Unable to launch: %1").arg(m_financeQuoteScriptPath));
+ slotParseQuote(QString());
+ }
+
+ return result;
+}
+
+void WebPriceQuote::slotParseQuote(const QString& _quotedata)
+{
+ QString quotedata = _quotedata;
+ bool gotprice = false;
+ bool gotdate = false;
+
+// kdDebug(2) << "WebPriceQuote::slotParseQuote( " << _quotedata << " ) " << endl;
+
+ if ( ! quotedata.isEmpty() )
+ {
+ if(!m_source.m_skipStripping) {
+ //
+ // First, remove extranous non-data elements
+ //
+
+ // HTML tags
+ quotedata.remove(QRegExp("<[^>]*>"));
+
+ // &...;'s
+ quotedata.replace(QRegExp("&\\w+;")," ");
+
+ // Extra white space
+ quotedata = quotedata.simplifyWhiteSpace();
+ }
+
+#if KMM_DEBUG
+ // Enable to get a look at the data coming back from the source after it's stripped
+ QFile file("stripped.txt");
+ if ( file.open( IO_WriteOnly ) )
+ {
+ QTextStream( &file ) << quotedata;
+ file.close();
+ }
+#endif
+
+ QRegExp symbolRegExp(m_source.m_sym);
+ QRegExp dateRegExp(m_source.m_date);
+ QRegExp priceRegExp(m_source.m_price);
+
+ if( symbolRegExp.search(quotedata) > -1)
+ emit status(i18n("Symbol found: %1").arg(symbolRegExp.cap(1)));
+
+ if(priceRegExp.search(quotedata)> -1)
+ {
+ gotprice = true;
+
+ // Deal with european quotes that come back as X.XXX,XX or XX,XXX
+ //
+ // We will make the assumption that ALL prices have a decimal separator.
+ // So "1,000" always means 1.0, not 1000.0.
+ //
+ // Remove all non-digits from the price string except the last one, and
+ // set the last one to a period.
+ QString pricestr = priceRegExp.cap(1);
+
+ int pos = pricestr.findRev(QRegExp("\\D"));
+ if ( pos > 0 )
+ {
+ pricestr[pos] = '.';
+ pos = pricestr.findRev(QRegExp("\\D"),pos-1);
+ }
+ while ( pos > 0 )
+ {
+ pricestr.remove(pos,1);
+ pos = pricestr.findRev(QRegExp("\\D"),pos);
+ }
+
+ m_price = pricestr.toDouble();
+ emit status(i18n("Price found: %1 (%2)").arg(pricestr).arg(m_price));
+ }
+
+ if(dateRegExp.search(quotedata) > -1)
+ {
+ QString datestr = dateRegExp.cap(1);
+
+ MyMoneyDateFormat dateparse(m_source.m_dateformat);
+ try
+ {
+ m_date = dateparse.convertString( datestr,false /*strict*/ );
+ gotdate = true;
+ emit status(i18n("Date found: %1").arg(m_date.toString()));;
+ }
+ catch (MyMoneyException* e)
+ {
+ // emit error(i18n("Unable to parse date %1 using format %2: %3").arg(datestr,dateparse.format(),e->what()));
+ m_date = QDate::currentDate();
+ gotdate = true;
+ delete e;
+ }
+ }
+
+ if ( gotprice && gotdate )
+ {
+ emit quote( m_id, m_symbol, m_date, m_price );
+ }
+ else
+ {
+ emit error(i18n("Unable to update price for %1").arg(m_symbol));
+ emit failed( m_id, m_symbol );
+ }
+ }
+ else
+ {
+ emit error(i18n("Unable to update price for %1").arg(m_symbol));
+ emit failed( m_id, m_symbol );
+ }
+}
+
+QMap<QString,WebPriceQuoteSource> WebPriceQuote::defaultQuoteSources(void)
+{
+ QMap<QString,WebPriceQuoteSource> result;
+
+ result["Yahoo"] = WebPriceQuoteSource("Yahoo",
+ "http://finance.yahoo.com/d/quotes.csv?s=%1&f=sl1d1",
+ "\"([^,\"]*)\",.*", // symbolregexp
+ "[^,]*,([^,]*),.*", // priceregexp
+ "[^,]*,[^,]*,\"([^\"]*)\"", // dateregexp
+ "%m %d %y" // dateformat
+ );
+
+ result["Yahoo Currency"] = WebPriceQuoteSource("Yahoo Currency",
+ "http://finance.yahoo.com/d/quotes.csv?s=%1%2=X&f=sl1d1",
+ "\"([^,\"]*)\",.*", // symbolregexp
+ "[^,]*,([^,]*),.*", // priceregexp
+ "[^,]*,[^,]*,\"([^\"]*)\"", // dateregexp
+ "%m %d %y" // dateformat
+ );
+
+ // 2009-08-20 Yahoo UK has no quotes and has comma separators
+ // sl1d1 format for Yahoo UK doesn't seem to give a date ever
+ // sl1d3 gives US locale time (9:99pm) and date (mm/dd/yyyy)
+ result["Yahoo UK"] = WebPriceQuoteSource("Yahoo UK",
+ "http://uk.finance.yahoo.com/d/quotes.csv?s=%1&f=sl1d3",
+ "^([^,]*),.*", // symbolregexp
+ "^[^,]*,([^,]*),.*", // priceregexp
+ "^[^,]*,[^,]*,(.*)", // dateregexp
+ "%m/%d/%y" // dateformat
+ );
+
+ // sl1d1 format for Yahoo France doesn't seem to give a date ever
+ // sl1d3 gives us time (99h99) and date
+ result["Yahoo France"] = WebPriceQuoteSource("Yahoo France",
+ "http://fr.finance.yahoo.com/d/quotes.csv?s=%1&f=sl1d3",
+ "([^;]*).*", // symbolregexp
+ "[^;]*.([^;]*),*", // priceregexp
+ "[^;]*.[^;]*...h...([^;]*)", // dateregexp
+ "%d/%m/%y" // dateformat
+ );
+
+ result["Globe & Mail"] = WebPriceQuoteSource("Globe & Mail",
+ "http://globefunddb.theglobeandmail.com/gishome/plsql/gis.price_history?pi_fund_id=%1",
+ QString(), // symbolregexp
+ "Reinvestment Price \\w+ \\d+, \\d+ (\\d+\\.\\d+)", // priceregexp
+ "Reinvestment Price (\\w+ \\d+, \\d+)", // dateregexp
+ "%m %d %y" // dateformat
+ );
+
+ result["MSN.CA"] = WebPriceQuoteSource("MSN.CA",
+ "http://ca.moneycentral.msn.com/investor/quotes/quotes.asp?symbol=%1",
+ QString(), // symbolregexp
+ "Net Asset Value (\\d+\\.\\d+)", // priceregexp
+ "NAV update (\\d+\\D+\\d+\\D+\\d+)", // dateregexp
+ "%d %m %y" // dateformat
+ );
+ // Finanztreff (replaces VWD.DE) and boerseonline supplied by Micahel Zimmerman
+ result["Finanztreff"] = WebPriceQuoteSource("Finanztreff",
+ "http://finanztreff.de/kurse_einzelkurs_detail.htn?u=100&i=%1",
+ QString(), // symbolregexp
+ "([0-9]+,\\d+).+Gattung:Fonds", // priceregexp
+ "\\).(\\d+\\D+\\d+\\D+\\d+)", // dateregexp (doesn't work; date in chart
+ "%d.%m.%y" // dateformat
+ );
+
+ result["boerseonline"] = WebPriceQuoteSource("boerseonline",
+ "http://www.boerse-online.de/tools/boerse/einzelkurs_kurse.htm?&s=%1",
+ QString(), // symbolregexp
+ "Akt\\. Kurs.(\\d+,\\d\\d)", // priceregexp
+ "Datum.(\\d+\\.\\d+\\.\\d+)", // dateregexp (doesn't work; date in chart
+ "%d.%m.%y" // dateformat
+ );
+
+ // The following two price sources were contributed by
+ // Marc Zahnlecker <tf2k@users.sourceforge.net>
+
+ result["Wallstreet-Online.DE (Default)"] = WebPriceQuoteSource("Wallstreet-Online.DE (Default)",
+ "http://www.wallstreet-online.de/si/?k=%1&spid=ws",
+ "Symbol:(\\w+)", // symbolregexp
+ "Letzter Kurs: ([0-9.]+,\\d+)", // priceregexp
+ ", (\\d+\\D+\\d+\\D+\\d+)", // dateregexp
+ "%d %m %y" // dateformat
+ );
+
+ // This quote source provided by Peter Lord
+ // The trading symbol will normally be the SEDOL (see wikipedia) but
+ // the flexibility presently (1/2008) in the code will allow use of
+ // the ISIN or MEXID (FT specific) codes
+ result["Financial Times UK Funds"] = WebPriceQuoteSource("Financial Times UK Funds",
+ "http://funds.ft.com/funds/simpleSearch.do?searchArea=%&search=%1",
+ "SEDOL[\\ ]*(\\d+.\\d+)", // symbol regexp
+ "\\(GBX\\)[\\ ]*([0-9,]*.\\d+)[\\ ]*", // price regexp
+ "Valuation date:[\\ ]*(\\d+/\\d+/\\d+)", // date regexp
+ "%d/%m/%y" // date format
+ );
+
+ // This quote source provided by Danny Scott
+ result["Yahoo Canada"] = WebPriceQuoteSource("Yahoo Canada",
+ "http://ca.finance.yahoo.com/q?s=%1",
+ "%1", // symbol regexp
+ "Last Trade: (\\d+\\.\\d+)", // price regexp
+ "day, (.\\D+\\d+\\D+\\d+)", // date regexp
+ "%m %d %y" // date format
+ );
+
+ // (tf2k) The "mpid" is I think the market place id. In this case five
+ // stands for Hamburg.
+ //
+ // Here the id for several market places: 2 Frankfurt, 3 Berlin, 4
+ // Düsseldorf, 5 Hamburg, 6 München/Munich, 7 Hannover, 9 Stuttgart, 10
+ // Xetra, 32 NASDAQ, 36 NYSE
+
+ result["Wallstreet-Online.DE (Hamburg)"] = WebPriceQuoteSource("Wallstreet-Online.DE (Hamburg)",
+ "http://fonds.wallstreet-online.de/si/?k=%1&spid=ws&mpid=5",
+ "Symbol:(\\w+)", // symbolregexp
+ "Fonds \\(EUR\\) ([0-9.]+,\\d+)", // priceregexp
+ ", (\\d+\\D+\\d+\\D+\\d+)", // dateregexp
+ "%d %m %y" // dateformat
+ );
+
+ // The following price quote was contributed by
+ // Piotr Adacha <piotr.adacha@googlemail.com>
+
+ // I would like to post new Online Query Settings for KMyMoney. This set is
+ // suitable to query stooq.com service, providing quotes for stocks, futures,
+ // mutual funds and other financial instruments from Polish Gielda Papierow
+ // Wartosciowych (GPW). Unfortunately, none of well-known international
+ // services provide quotes for this market (biggest one in central and eastern
+ // Europe), thus, I think it could be helpful for Polish users of KMyMoney (and
+ // I am one of them for almost a year).
+
+ result["Gielda Papierow Wartosciowych (GPW)"] = WebPriceQuoteSource("Gielda Papierow Wartosciowych (GPW)",
+ "http://stooq.com/q/?s=%1",
+ QString(), // symbol regexp
+ "Kurs.*(\\d+\\.\\d+).*Data", // price regexp
+ "(\\d{4,4}-\\d{2,2}-\\d{2,2})", // date regexp
+ "%y %m %d" // date format
+ );
+
+ // The following price quote is for getting prices of different funds
+ // at OMX Baltic market.
+ result["OMX Baltic funds"] = WebPriceQuoteSource("OMX Baltic funds",
+ "http://www.baltic.omxgroup.com/market/?pg=nontradeddetails&currency=0&instrument=%1",
+ QString(), // symbolregexp
+ "NAV (\\d+,\\d+)", // priceregexp
+ "Kpv (\\d+.\\d+.\\d+)", // dateregexp
+ "%d.%m.%y" // dateformat
+ );
+
+ // The following price quote was contributed by
+ // Peter Hargreaves <pete.h@pdh-online.info>
+ // The original posting can be found here:
+ // http://sourceforge.net/mailarchive/message.php?msg_name=200806060854.11682.pete.h%40pdh-online.info
+
+ // I have PEP and ISA accounts which I invest in Funds with Barclays
+ // Stockbrokers. They give me Fund data via Financial Express:
+ //
+ // https://webfund6.financialexpress.net/Clients/Barclays/default.aspx
+ //
+ // A typical Fund Factsheet is:
+ //
+ // https://webfund6.financialexpress.net/Clients/Barclays/search_factsheet_summary.aspx?code=0585239
+ //
+ // On the Factsheet to identify the fund you can see ISIN Code GB0005852396.
+ // In the url, this code is shortened by loosing the first four and last
+ // characters.
+ //
+ // Update:
+ //
+ // Nick Elliot has contributed a modified regular expression to cope with values presented
+ // in pounds as well as those presented in pence. The source can be found here:
+ // http://forum.kde.org/update-stock-and-currency-prices-t-32049.html
+
+ result["Financial Express"] = WebPriceQuoteSource("Financial Express",
+ "https://webfund6.financialexpress.net/Clients/Barclays/search_factsheet_summary.aspx?code=%1",
+ "ISIN Code[^G]*(GB..........).*", // symbolregexp
+ "Current Market Information[^0-9]*([0-9,\\.]+).*", // priceregexp
+ "Price Date[^0-9]*(../../....).*", // dateregexp
+ "%d/%m/%y" // dateformat
+ );
+
+ return result;
+}
+
+QStringList WebPriceQuote::quoteSources (const _quoteSystemE _system) {
+ if (_system == Native)
+ return (quoteSourcesNative());
+ else
+ return (quoteSourcesFinanceQuote());
+}
+
+QStringList WebPriceQuote::quoteSourcesNative()
+{
+ KConfig *kconfig = KGlobal::config();
+ QStringList groups = kconfig->groupList();
+
+ QStringList::Iterator it;
+ QRegExp onlineQuoteSource(QString("^Online-Quote-Source-(.*)$"));
+
+ // get rid of all 'non online quote source' entries
+ for(it = groups.begin(); it != groups.end(); it = groups.remove(it)) {
+ if(onlineQuoteSource.search(*it) >= 0) {
+ // Insert the name part
+ groups.insert(it, onlineQuoteSource.cap(1));
+ }
+ }
+
+ // if the user has the OLD quote source defined, now is the
+ // time to remove that entry and convert it to the new system.
+ if ( ! groups.count() && kconfig->hasGroup("Online Quotes Options") )
+ {
+ kconfig->setGroup("Online Quotes Options");
+ QString url(kconfig->readEntry("URL","http://finance.yahoo.com/d/quotes.csv?s=%1&f=sl1d1"));
+ QString symbolRegExp(kconfig->readEntry("SymbolRegex","\"([^,\"]*)\",.*"));
+ QString priceRegExp(kconfig->readEntry("PriceRegex","[^,]*,([^,]*),.*"));
+ QString dateRegExp(kconfig->readEntry("DateRegex","[^,]*,[^,]*,\"([^\"]*)\""));
+ kconfig->deleteGroup("Online Quotes Options");
+
+ groups += "Old Source";
+ kconfig->setGroup(QString("Online-Quote-Source-%1").arg("Old Source"));
+ kconfig->writeEntry("URL", url);
+ kconfig->writeEntry("SymbolRegex", symbolRegExp);
+ kconfig->writeEntry("PriceRegex",priceRegExp);
+ kconfig->writeEntry("DateRegex", dateRegExp);
+ kconfig->writeEntry("DateFormatRegex", "%m %d %y");
+ kconfig->sync();
+ }
+
+ // Set up each of the default sources. These are done piecemeal so that
+ // when we add a new source, it's automatically picked up.
+ QMap<QString,WebPriceQuoteSource> defaults = defaultQuoteSources();
+ QMap<QString,WebPriceQuoteSource>::const_iterator it_source = defaults.begin();
+ while ( it_source != defaults.end() )
+ {
+ if ( ! groups.contains( (*it_source).m_name ) )
+ {
+ groups += (*it_source).m_name;
+ (*it_source).write();
+ kconfig->sync();
+ }
+ ++it_source;
+ }
+
+ return groups;
+}
+
+QStringList WebPriceQuote::quoteSourcesFinanceQuote()
+{
+ if (m_financeQuoteSources.empty()) { // run the process one time only
+ FinanceQuoteProcess getList;
+ m_financeQuoteScriptPath =
+ KGlobal::dirs()->findResource("appdata", QString("misc/financequote.pl"));
+ getList.launch( m_financeQuoteScriptPath );
+ while (!getList.isFinished()) {
+ qApp->processEvents();
+ }
+ m_financeQuoteSources = getList.getSourceList();
+ }
+ return (m_financeQuoteSources);
+}
+
+//
+// Helper class to load/save an individual source
+//
+
+WebPriceQuoteSource::WebPriceQuoteSource(const QString& name, const QString& url, const QString& sym, const QString& price, const QString& date, const QString& dateformat):
+ m_name(name),
+ m_url(url),
+ m_sym(sym),
+ m_price(price),
+ m_date(date),
+ m_dateformat(dateformat)
+{
+}
+
+WebPriceQuoteSource::WebPriceQuoteSource(const QString& name)
+{
+ m_name = name;
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup(QString("Online-Quote-Source-%1").arg(m_name));
+ m_sym = kconfig->readEntry("SymbolRegex");
+ m_date = kconfig->readEntry("DateRegex");
+ m_dateformat = kconfig->readEntry("DateFormatRegex","%m %d %y");
+ m_price = kconfig->readEntry("PriceRegex");
+ m_url = kconfig->readEntry("URL");
+ m_skipStripping = kconfig->readBoolEntry("SkipStripping", false);
+}
+
+void WebPriceQuoteSource::write(void) const
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup(QString("Online-Quote-Source-%1").arg(m_name));
+ kconfig->writeEntry("URL", m_url);
+ kconfig->writeEntry("PriceRegex", m_price);
+ kconfig->writeEntry("DateRegex", m_date);
+ kconfig->writeEntry("DateFormatRegex", m_dateformat);
+ kconfig->writeEntry("SymbolRegex", m_sym);
+ if(m_skipStripping)
+ kconfig->writeEntry("SkipStripping", m_skipStripping);
+ else
+ kconfig->deleteEntry("SkipStripping");
+}
+
+void WebPriceQuoteSource::rename(const QString& name)
+{
+ remove();
+ m_name = name;
+ write();
+}
+
+void WebPriceQuoteSource::remove(void) const
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->deleteGroup(QString("Online-Quote-Source-%1").arg(m_name));
+}
+
+//
+// Helper class to babysit the KProcess used for running the local script in that case
+//
+
+WebPriceQuoteProcess::WebPriceQuoteProcess(void)
+{
+ connect(this, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotReceivedDataFromFilter(KProcess*, char*, int)));
+ connect(this, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)));
+}
+
+void WebPriceQuoteProcess::slotReceivedDataFromFilter(KProcess* /*_process*/, char* _pcbuffer, int _nbufferlen)
+{
+ QByteArray data;
+ data.duplicate(_pcbuffer, _nbufferlen);
+
+// kdDebug(2) << "WebPriceQuoteProcess::slotReceivedDataFromFilter(): " << QString(data) << endl;
+ m_string += QString(data);
+}
+
+void WebPriceQuoteProcess::slotProcessExited(KProcess*)
+{
+// kdDebug(2) << "WebPriceQuoteProcess::slotProcessExited()" << endl;
+ emit processExited(m_string);
+ m_string.truncate(0);
+}
+
+//
+// Helper class to babysit the KProcess used for running the Finance Quote sources script
+//
+
+FinanceQuoteProcess::FinanceQuoteProcess(void)
+{
+ m_isDone = false;
+ m_string = "";
+ m_fqNames["aex"] = "AEX";
+ m_fqNames["aex_futures"] = "AEX Futures";
+ m_fqNames["aex_options"] = "AEX Options";
+ m_fqNames["amfiindia"] = "AMFI India";
+ m_fqNames["asegr"] = "ASE";
+ m_fqNames["asia"] = "Asia (Yahoo, ...)";
+ m_fqNames["asx"] = "ASX";
+ m_fqNames["australia"] = "Australia (ASX, Yahoo, ...)";
+ m_fqNames["bmonesbittburns"] = "BMO NesbittBurns";
+ m_fqNames["brasil"] = "Brasil (Yahoo, ...)";
+ m_fqNames["canada"] = "Canada (Yahoo, ...)";
+ m_fqNames["canadamutual"] = "Canada Mutual (Fund Library, ...)";
+ m_fqNames["deka"] = "Deka Investments";
+ m_fqNames["dutch"] = "Dutch (AEX, ...)";
+ m_fqNames["dwsfunds"] = "DWS";
+ m_fqNames["europe"] = "Europe (Yahoo, ...)";
+ m_fqNames["fidelity"] = "Fidelity (Fidelity, ...)";
+ m_fqNames["fidelity_direct"] = "Fidelity Direct";
+ m_fqNames["financecanada"] = "Finance Canada";
+ m_fqNames["ftportfolios"] = "First Trust (First Trust, ...)";
+ m_fqNames["ftportfolios_direct"] = "First Trust Portfolios";
+ m_fqNames["fundlibrary"] = "Fund Library";
+ m_fqNames["greece"] = "Greece (ASE, ...)";
+ m_fqNames["indiamutual"] = "India Mutual (AMFI, ...)";
+ m_fqNames["maninv"] = "Man Investments";
+ m_fqNames["fool"] = "Motley Fool";
+ m_fqNames["nasdaq"] = "Nasdaq (Yahoo, ...)";
+ m_fqNames["nz"] = "New Zealand (Yahoo, ...)";
+ m_fqNames["nyse"] = "NYSE (Yahoo, ...)";
+ m_fqNames["nzx"] = "NZX";
+ m_fqNames["platinum"] = "Platinum Asset Management";
+ m_fqNames["seb_funds"] = "SEB";
+ m_fqNames["sharenet"] = "Sharenet";
+ m_fqNames["za"] = "South Africa (Sharenet, ...)";
+ m_fqNames["troweprice_direct"] = "T. Rowe Price";
+ m_fqNames["troweprice"] = "T. Rowe Price";
+ m_fqNames["tdefunds"] = "TD Efunds";
+ m_fqNames["tdwaterhouse"] = "TD Waterhouse Canada";
+ m_fqNames["tiaacref"] = "TIAA-CREF";
+ m_fqNames["trustnet"] = "Trustnet";
+ m_fqNames["uk_unit_trusts"] = "U.K. Unit Trusts";
+ m_fqNames["unionfunds"] = "Union Investments";
+ m_fqNames["tsp"] = "US Govt. Thrift Savings Plan";
+ m_fqNames["usfedbonds"] = "US Treasury Bonds";
+ m_fqNames["usa"] = "USA (Yahoo, Fool ...)";
+ m_fqNames["vanguard"] = "Vanguard";
+ m_fqNames["vwd"] = "VWD";
+ m_fqNames["yahoo"] = "Yahoo";
+ m_fqNames["yahoo_asia"] = "Yahoo Asia";
+ m_fqNames["yahoo_australia"] = "Yahoo Australia";
+ m_fqNames["yahoo_brasil"] = "Yahoo Brasil";
+ m_fqNames["yahoo_europe"] = "Yahoo Europe";
+ m_fqNames["yahoo_nz"] = "Yahoo New Zealand";
+ m_fqNames["zifunds"] = "Zuerich Investments";
+ connect(this, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotReceivedDataFromFilter(KProcess*, char*, int)));
+ connect(this, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)));
+}
+
+void FinanceQuoteProcess::slotReceivedDataFromFilter(KProcess* /*_process*/, char* _pcbuffer, int _nbufferlen)
+{
+ QByteArray data;
+ data.duplicate(_pcbuffer, _nbufferlen);
+
+// kdDebug(2) << "WebPriceQuoteProcess::slotReceivedDataFromFilter(): " << QString(data) << endl;
+ m_string += QString(data);
+}
+
+void FinanceQuoteProcess::slotProcessExited(KProcess*)
+{
+// kdDebug(2) << "WebPriceQuoteProcess::slotProcessExited()" << endl;
+ m_isDone = true;
+}
+
+void FinanceQuoteProcess::launch (const QString& scriptPath) {
+ clearArguments();
+ arguments.append(QCString("perl"));
+ arguments.append (QCString(scriptPath));
+ arguments.append (QCString("-l"));
+ if (!start(KProcess::NotifyOnExit, KProcess::Stdout)) qFatal ("Unable to start FQ script");
+ return;
+}
+
+QStringList FinanceQuoteProcess::getSourceList() {
+ QStringList raw = QStringList::split(0x0A, m_string);
+ QStringList sources;
+ QStringList::iterator it;
+ for (it = raw.begin(); it != raw.end(); ++it) {
+ if (m_fqNames[*it].isEmpty()) sources.append(*it);
+ else sources.append(m_fqNames[*it]);
+ }
+ sources.sort();
+ return (sources);
+}
+
+const QString FinanceQuoteProcess::crypticName(const QString& niceName) {
+ QString ret (niceName);
+ fqNameMap::iterator it;
+ for (it = m_fqNames.begin(); it != m_fqNames.end(); ++it) {
+ if (niceName == it.data()) {
+ ret = it.key();
+ break;
+ }
+ }
+ return (ret);
+}
+
+const QString FinanceQuoteProcess::niceName(const QString& crypticName) {
+ QString ret (m_fqNames[crypticName]);
+ if (ret.isEmpty()) ret = crypticName;
+ return (ret);
+}
+//
+// Universal date converter
+//
+
+// In 'strict' mode, this is designed to be compatable with the QIF profile date
+// converter. However, that converter deals with the concept of an apostrophe
+// format in a way I don't understand. So for the moment, they are 99%
+// compatable, waiting on that issue. (acejones)
+
+QDate MyMoneyDateFormat::convertString(const QString& _in, bool _strict, unsigned _centurymidpoint) const
+{
+ //
+ // Break date format string into component parts
+ //
+
+ QRegExp formatrex("%([mdy]+)(\\W+)%([mdy]+)(\\W+)%([mdy]+)",false /* case sensitive */);
+ if ( formatrex.search(m_format) == -1 )
+ {
+ throw new MYMONEYEXCEPTION("Invalid format string");
+ }
+
+ QStringList formatParts;
+ formatParts += formatrex.cap(1);
+ formatParts += formatrex.cap(3);
+ formatParts += formatrex.cap(5);
+
+ QStringList formatDelimiters;
+ formatDelimiters += formatrex.cap(2);
+ formatDelimiters += formatrex.cap(4);
+
+ //
+ // Break input string up into component parts,
+ // using the delimiters found in the format string
+ //
+
+ QRegExp inputrex;
+ inputrex.setCaseSensitive(false);
+
+ // strict mode means we must enforce the delimiters as specified in the
+ // format. non-strict allows any delimiters
+ if ( _strict )
+ inputrex.setPattern(QString("(\\w+)%1(\\w+)%2(\\w+)").arg(formatDelimiters[0],formatDelimiters[1]));
+ else
+ inputrex.setPattern("(\\w+)\\W+(\\w+)\\W+(\\w+)");
+
+ if ( inputrex.search(_in) == -1 )
+ {
+ throw new MYMONEYEXCEPTION("Invalid input string");
+ }
+
+ QStringList scannedParts;
+ scannedParts += inputrex.cap(1).lower();
+ scannedParts += inputrex.cap(2).lower();
+ scannedParts += inputrex.cap(3).lower();
+
+ //
+ // Convert the scanned parts into actual date components
+ //
+
+ unsigned day = 0, month = 0, year = 0;
+ bool ok;
+ QRegExp digitrex("(\\d+)");
+ QStringList::const_iterator it_scanned = scannedParts.begin();
+ QStringList::const_iterator it_format = formatParts.begin();
+ while ( it_scanned != scannedParts.end() )
+ {
+ switch ( (*it_format)[0] )
+ {
+ case 'd':
+ // remove any extraneous non-digits (e.g. read "3rd" as 3)
+ ok = false;
+ if ( digitrex.search(*it_scanned) != -1 )
+ day = digitrex.cap(1).toUInt(&ok);
+ if ( !ok || day > 31 )
+ throw new MYMONEYEXCEPTION(QString("Invalid day entry: %1").arg(*it_scanned));
+ break;
+ case 'm':
+ month = (*it_scanned).toUInt(&ok);
+ if ( !ok )
+ {
+ // maybe it's a textual date
+ unsigned i = 1;
+ while ( i <= 12 )
+ {
+ if(KGlobal::locale()->calendar()->monthName(i, 2000, true).lower() == *it_scanned
+ || KGlobal::locale()->calendar()->monthName(i, 2000, false).lower() == *it_scanned)
+ month = i;
+ ++i;
+ }
+ }
+
+ if ( month < 1 || month > 12 )
+ throw new MYMONEYEXCEPTION(QString("Invalid month entry: %1").arg(*it_scanned));
+
+ break;
+ case 'y':
+ if ( _strict && (*it_scanned).length() != (*it_format).length())
+ throw new MYMONEYEXCEPTION(QString("Length of year (%1) does not match expected length (%2).")
+ .arg(*it_scanned,*it_format));
+
+ year = (*it_scanned).toUInt(&ok);
+
+ if (!ok)
+ throw new MYMONEYEXCEPTION(QString("Invalid year entry: %1").arg(*it_scanned));
+
+ //
+ // 2-digit year case
+ //
+ // this algorithm will pick a year within +/- 50 years of the
+ // centurymidpoint parameter. i.e. if the midpoint is 2000,
+ // then 0-49 will become 2000-2049, and 50-99 will become 1950-1999
+ if ( year < 100 )
+ {
+ unsigned centuryend = _centurymidpoint + 50;
+ unsigned centurybegin = _centurymidpoint - 50;
+
+ if ( year < centuryend % 100 )
+ year += 100;
+ year += centurybegin - centurybegin % 100;
+ }
+
+ if ( year < 1900 )
+ throw new MYMONEYEXCEPTION(QString("Invalid year (%1)").arg(year));
+
+ break;
+ default:
+ throw new MYMONEYEXCEPTION("Invalid format character");
+ }
+
+ ++it_scanned;
+ ++it_format;
+ }
+
+ QDate result(year,month,day);
+ if ( ! result.isValid() )
+ throw new MYMONEYEXCEPTION(QString("Invalid date (yr%1 mo%2 dy%3)").arg(year).arg(month).arg(day));
+
+ return result;
+}
+
+//
+// Unit test helpers
+//
+
+convertertest::QuoteReceiver::QuoteReceiver(WebPriceQuote* q, QObject* parent, const char *name) :
+ QObject(parent,name)
+{
+ connect(q,SIGNAL(quote(const QString&,const QDate&, const double&)),
+ this,SLOT(slotGetQuote(const QString&,const QDate&, const double&)));
+ connect(q,SIGNAL(status(const QString&)),
+ this,SLOT(slotStatus(const QString&)));
+ connect(q,SIGNAL(error(const QString&)),
+ this,SLOT(slotError(const QString&)));
+}
+
+convertertest::QuoteReceiver::~QuoteReceiver()
+{
+}
+
+void convertertest::QuoteReceiver::slotGetQuote(const QString&,const QDate& d, const double& m)
+{
+// kdDebug(2) << "test::QuoteReceiver::slotGetQuote( , " << d << " , " << m.toString() << " )" << endl;
+
+ m_price = MyMoneyMoney(m);
+ m_date = d;
+}
+void convertertest::QuoteReceiver::slotStatus(const QString& msg)
+{
+// kdDebug(2) << "test::QuoteReceiver::slotStatus( " << msg << " )" << endl;
+
+ m_statuses += msg;
+}
+void convertertest::QuoteReceiver::slotError(const QString& msg)
+{
+// kdDebug(2) << "test::QuoteReceiver::slotError( " << msg << " )" << endl;
+
+ m_errors += msg;
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
+
+#include "webpricequote.moc"
diff --git a/kmymoney2/converter/webpricequote.h b/kmymoney2/converter/webpricequote.h
new file mode 100644
index 0000000..e25dfb8
--- /dev/null
+++ b/kmymoney2/converter/webpricequote.h
@@ -0,0 +1,252 @@
+/***************************************************************************
+ webpricequote.h
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Ace Jones
+ email : Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef WEBPRICEQUOTE_H
+#define WEBPRICEQUOTE_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qobject.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+#include <qmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kprocess.h>
+namespace KIO {
+ class Job;
+};
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "../mymoney/mymoneymoney.h"
+
+/**
+Helper class to attend the process which is running the script, in the case
+of a local script being used to fetch the quote.
+
+@author Thomas Baumgart <thb@net-bembel.de> & Ace Jones <acejones@users.sourceforge.net>
+*/
+class WebPriceQuoteProcess: public KProcess
+{
+ Q_OBJECT
+public:
+ WebPriceQuoteProcess(void);
+ void setSymbol(const QString& _symbol) { m_symbol = _symbol; m_string.truncate(0); }
+
+public slots:
+ void slotReceivedDataFromFilter(KProcess*, char*, int);
+ void slotProcessExited(KProcess*);
+
+signals:
+ void processExited(const QString&);
+
+private:
+ QString m_symbol;
+ QString m_string;
+};
+
+/**
+Helper class to run the Finance::Quote process. This is used only for the purpose of obtaining
+a list of valid sources. The actual price quotes are obtained thru WebPriceQuoteProcess.
+The class also contains functions to convert between the rather cryptic source names used
+by the Finance::Quote package, and more user-friendly names.
+
+@author Thomas Baumgart <thb@net-bembel.de> & Ace Jones <acejones@users.sourceforge.net>, Tony B<tonybloom@users.sourceforge.net>
+ */
+class FinanceQuoteProcess: public KProcess
+{
+ Q_OBJECT
+ public:
+ FinanceQuoteProcess(void);
+ void launch (const QString& scriptPath);
+ bool isFinished() { return(m_isDone);};
+ QStringList getSourceList();
+ const QString crypticName(const QString& niceName);
+ const QString niceName(const QString& crypticName);
+
+ public slots:
+ void slotReceivedDataFromFilter(KProcess*, char*, int);
+ void slotProcessExited(KProcess*);
+
+ private:
+ bool m_isDone;
+ QString m_string;
+ typedef QMap<QString, QString> fqNameMap;
+ fqNameMap m_fqNames;
+};
+
+/**
+ * @author Thomas Baumgart & Ace Jones
+ *
+ * This is a helper class to store information about an online source
+ * for stock prices or currency exchange rates.
+ */
+struct WebPriceQuoteSource
+{
+ WebPriceQuoteSource() {}
+ WebPriceQuoteSource(const QString& name);
+ WebPriceQuoteSource(const QString& name, const QString& url, const QString& sym, const QString& price, const QString& date, const QString& dateformat);
+ ~WebPriceQuoteSource() {}
+
+ void write(void) const;
+ void rename(const QString& name);
+ void remove(void) const;
+
+ QString m_name;
+ QString m_url;
+ QString m_sym;
+ QString m_price;
+ QString m_date;
+ QString m_dateformat;
+ bool m_skipStripping;
+};
+
+/**
+Retrieves a price quote from a web-based quote source
+
+@author Ace Jones <acejones@users.sourceforge.net>
+*/
+class WebPriceQuote: public QObject
+{
+ Q_OBJECT
+public:
+ WebPriceQuote( QObject* = 0, const char* = 0 );
+ ~WebPriceQuote();
+
+ typedef enum _quoteSystemE {
+ Native=0,
+ FinanceQuote
+ } quoteSystemE;
+
+ /**
+ * This launches a web-based quote update for the given @p _symbol.
+ * When the quote is received back from the web source, it will be
+ * emitted on the 'quote' signal.
+ *
+ * @param _symbol the trading symbol of the stock to fetch a price for
+ * @param _id an arbitrary identifier, which will be emitted in the quote
+ * signal when a price is sent back.
+ * @param _source the source of the quote (must be a valid value returned
+ * by quoteSources(). Send QString() to use the default
+ * source.
+ * @return bool Whether the quote fetch process was launched successfully
+ */
+
+ bool launch(const QString& _symbol, const QString& _id, const QString& _source=QString());
+
+ /**
+ * This returns a list of the names of the quote sources
+ * currently defined.
+ *
+ * @param _system whether to return Native or Finance::Quote source list
+ * @return QStringList of quote source names
+ */
+ static QStringList quoteSources(const _quoteSystemE _system=Native);
+
+signals:
+ void quote(const QString&, const QString&, const QDate&, const double&);
+ void failed(const QString&, const QString&);
+ void status(const QString&);
+ void error(const QString&);
+
+protected slots:
+ void slotParseQuote(const QString&);
+
+protected:
+ static QMap<QString,WebPriceQuoteSource> defaultQuoteSources(void);
+
+private:
+ bool download(const KURL& u, QString & target, QWidget* window);
+ void removeTempFile(const QString& tmpFile);
+
+private slots:
+ void slotResult( KIO::Job * job );
+
+
+private:
+ bool launchNative(const QString& _symbol, const QString& _id, const QString& _source=QString());
+ bool launchFinanceQuote(const QString& _symbol, const QString& _id, const QString& _source=QString());
+ void enter_loop(void);
+
+ static QStringList quoteSourcesNative();
+ static QStringList quoteSourcesFinanceQuote();
+
+ WebPriceQuoteProcess m_filter;
+ QString m_symbol;
+ QString m_id;
+ QDate m_date;
+ double m_price;
+ WebPriceQuoteSource m_source;
+ static QString m_financeQuoteScriptPath;
+ static QStringList m_financeQuoteSources;
+
+
+ /**
+ * Whether the download succeeded or not. Taken from KIO::NetAccess
+ */
+ bool bJobOK;
+ static QString* lastErrorMsg;
+ static int lastErrorCode;
+ QString m_tmpFile;
+};
+
+class MyMoneyDateFormat
+{
+public:
+ MyMoneyDateFormat(const QString& _format): m_format(_format) {}
+ QString convertDate(const QDate& _in) const;
+ QDate convertString(const QString& _in, bool _strict=true, unsigned _centurymidpoint = QDate::currentDate().year() ) const;
+ const QString& format(void) const { return m_format; }
+private:
+ QString m_format;
+};
+
+namespace convertertest {
+
+/**
+Simple class to handle signals/slots for unit tests
+
+@author Ace Jones <acejones@users.sourceforge.net>
+*/
+class QuoteReceiver : public QObject
+{
+Q_OBJECT
+public:
+ QuoteReceiver(WebPriceQuote* q, QObject *parent = 0, const char *name = 0);
+ ~QuoteReceiver();
+public slots:
+ void slotGetQuote(const QString&,const QDate&, const double&);
+ void slotStatus(const QString&);
+ void slotError(const QString&);
+public:
+ QStringList m_statuses;
+ QStringList m_errors;
+ MyMoneyMoney m_price;
+ QDate m_date;
+};
+
+} // end namespace convertertest
+
+
+#endif // WEBPRICEQUOTE_H
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/Makefile.am b/kmymoney2/dialogs/Makefile.am
new file mode 100644
index 0000000..ad9be80
--- /dev/null
+++ b/kmymoney2/dialogs/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LIBRARIES = libdialogs.a
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I. -I$(top_srcdir)/libkdchart -I$(top_srcdir)/kmymoney2/mymoney
+
+libdialogs_a_METASOURCES = AUTO
+
+libdialogs_a_SOURCES = kreportconfigurationfilterdlg.cpp kcurrencycalculator.cpp kcurrencyeditdlg.cpp keditequityentrydlg.cpp keditloanwizard.cpp knewloanwizard.cpp kenterscheduledlg.cpp krecentfileitem.cpp keditscheduledlg.cpp mymoneyqifprofileeditor.cpp kaccountselectdlg.cpp kupdatestockpricedlg.cpp knewequityentrydlg.cpp kstartdlg.cpp kreconciledlg.cpp knewfiledlg.cpp knewbankdlg.cpp knewaccountdlg.cpp kfindtransactiondlg.cpp kendingbalancedlg.cpp ksplittransactiondlg.cpp kimportdlg.cpp kexportdlg.cpp kcsvprogressdlg.cpp kchooseimportexportdlg.cpp kbackupdlg.cpp kequitypriceupdatedlg.cpp kmymoneypricedlg.cpp knewinvestmentwizard.cpp knewinvestmentwizard.h ksecuritylisteditor.cpp kgncimportoptionsdlg.cpp konlinequoteconfigurationdlg.cpp kgncpricesourcedlg.cpp kmymoneyfileinfodlg.cpp kselectdatabasedlg.cpp kpayeereassigndlg.cpp kcategoryreassigndlg.cpp kconfirmmanualenterdlg.cpp kaccountselectdlgdecl.ui kbackupdlgdecl.ui kchooseimportexportdlgdecl.ui kconfirmmanualenterdlgdecl.ui kcsvprogressdlgdecl.ui kcurrencycalculatordecl.ui kcurrencyeditdlgdecl.ui keditequityentrydecl.ui keditscheduledlgdecl.ui kendingbalancedlgdecl.ui kenterscheduledlgdecl.ui kequitypriceupdatedlgdecl.ui kexportdlgdecl.ui kfindtransactiondlgdecl.ui kgncimportoptionsdlgdecl.ui kimportdlgdecl.ui kmymoneypricedlgdecl.ui knewaccountdlgdecl.ui knewbankdlgdecl.ui knewequityentrydecl.ui knewfiledlgdecl.ui knewinvestmentwizarddecl.ui knewloanwizarddecl.ui konlinequoteconfigurationdecl.ui kreconciledlgdecl.ui ksecuritylisteditordecl.ui ksplitcorrectiondlg.ui ksplittransactiondlgdecl.ui kupdatestockpricedlgdecl.ui mymoneyqifprofileeditordecl.ui kgncpricesourcedlgdecl.ui kmymoneyfileinfodlgdecl.ui kselectdatabasedlgdecl.ui kpayeereassigndlgdecl.ui kcategoryreassigndlgdecl.ui transactioneditor.cpp investtransactioneditor.cpp investactivities.cpp kbalancechartdlg.cpp kplugindlg.ui kgpgkeyselectiondlg.cpp transactionmatcher.cpp kbalancewarning.cpp \
+knewbudgetdlgdecl.ui knewbudgetdlg.cpp kselecttransactionsdlgdecl.ui kselecttransactionsdlg.cpp kmergetransactionsdlg.cpp ksortoptiondlg.ui kloadtemplatedlgdecl.ui kloadtemplatedlg.cpp kmymoneysplittable.cpp
+
+EXTRA_DIST = kaccountselectdlgdecl.ui kbackupdlgdecl.ui kchooseimportexportdlgdecl.ui kconfirmmanualenterdlgdecl.ui kcsvprogressdlgdecl.ui kcurrencycalculatordecl.ui kcurrencyeditdlgdecl.ui keditequityentrydecl.ui keditscheduledlgdecl.ui kendingbalancedlgdecl.ui kenterscheduledlgdecl.ui kequitypriceupdatedlgdecl.ui kexportdlgdecl.ui kfindtransactiondlgdecl.ui kgncimportoptionsdlgdecl.ui kimportdlgdecl.ui kmymoneypricedlgdecl.ui knewaccountdlgdecl.ui knewbankdlgdecl.ui knewequityentrydecl.ui knewfiledlgdecl.ui knewinvestmentwizarddecl.ui knewloanwizarddecl.ui konlinequoteconfigurationdecl.ui kreconciledlgdecl.ui ksecuritylisteditordecl.ui ksplitcorrectiondlg.ui ksplittransactiondlgdecl.ui kupdatestockpricedlgdecl.ui mymoneyqifprofileeditordecl.ui kgncpricesourcedlgdecl.ui kmymoneyfileinfodlgdecl.ui kselectdatabasedlgdecl.ui kpayeereassigndlgdecl.ui kcategoryreassigndlgdecl.ui knewbudgetdlgdecl.ui kselecttransactionsdlgdecl.ui ksortoptiondlg.ui ksortoptiondlg.ui.h kplugindlg.ui kloadtemplatedlgdecl.ui
+
+DISTCLEANFILES= kaccountselectdlgdecl.cpp kbackupdlgdecl.cpp kchooseimportexportdlgdecl.cpp kcsvprogressdlgdecl.cpp kcurrencycalculatordecl.cpp kcurrencyeditdlgdecl.cpp keditequityentrydecl.cpp keditscheduledlgdecl.cpp kendingbalancedlgdecl.cpp kenterscheduledlgdecl.cpp kequitypriceupdatedlgdecl.cpp kexportdlgdecl.cpp kfindtransactiondlgdecl.cpp kgncimportoptionsdlgdecl.cpp kimportdlgdecl.cpp kmymoneypricedlgdecl.cpp knewaccountdlgdecl.cpp knewbankdlgdecl.cpp knewequityentrydecl.cpp knewfiledlgdecl.cpp knewinvestmentwizarddecl.cpp knewloanwizarddecl.cpp konlinequoteconfigurationdecl.cpp kreconciledlgdecl.cpp kreportconfigurationdecl.cpp ksecuritylisteditordecl.cpp ksplittransactiondlgdecl.cpp kupdatestockpricedlgdecl.cpp mymoneyqifprofileeditordecl.cpp kpayeereassigndlgdecl.cpp kcategoryreassigndlgdecl.cpp kconfirmmanualenterdlgdecl.cpp kaccountselectdlgdecl.h kbackupdlgdecl.h kchooseimportexportdlgdecl.h kcsvprogressdlgdecl.h kcurrencycalculatordecl.h kcurrencyeditdlgdecl.h keditequityentrydecl.h keditscheduledlgdecl.h kendingbalancedlgdecl.h kenterscheduledlgdecl.h kequitypriceupdatedlgdecl.h kexportdlgdecl.h kfindtransactiondlgdecl.h kgncimportoptionsdlgdecl.h kimportdlgdecl.h kmymoneypricedlgdecl.h knewaccountdlgdecl.h knewbankdlgdecl.h knewequityentrydecl.h knewfiledlgdecl.h knewinvestmentwizarddecl.h knewloanwizarddecl.h konlinequoteconfigurationdecl.h kreconciledlgdecl.h kreportconfigurationdecl.h ksecuritylisteditordecl.h ksplittransactiondlgdecl.h kupdatestockpricedlgdecl.h mymoneyqifprofileeditordecl.h kmymoneyfileinfodlgdecl.h kselectdatabasedlgdecl.h kpayeereassigndlgdecl.h kcategoryreassigndlgdecl.h knewbudgetdlgdecl.cpp knewbudgetdlgdecl.h kselecttransactionsdlgdecl.cpp kselecttransactionsdlgdecl.h kconfirmmanualenterdlgdecl.h kloadtemplatedlgdecl.cpp kloadtemplatedlgdecl.h
+
+noinst_HEADERS = keditscheduledlg.h kaccountselectdlg.h kbackupdlg.h kchooseimportexportdlg.h kcsvprogressdlg.h kcurrencyeditdlg.h keditequityentrydlg.h keditloanwizard.h kendingbalancedlg.h kenterscheduledlg.h kequitypriceupdatedlg.h kexportdlg.h kfindtransactiondlg.h kgncimportoptionsdlg.h kimportdlg.h kmymoneypricedlg.h knewaccountdlg.h knewbankdlg.h knewequityentrydlg.h knewfiledlg.h knewinvestmentwizard.h knewloanwizard.h konlinequoteconfigurationdlg.h krecentfileitem.h kreconciledlg.h kreportconfigurationfilterdlg.h ksecuritylisteditor.h ksplittransactiondlg.h kstartdlg.h kupdatestockpricedlg.h mymoneyqifprofileeditor.h kgncpricesourcedlg.h kmymoneyfileinfodlg.h kselectdatabasedlg.h kpayeereassigndlg.h kcategoryreassigndlg.h knewbudgetdlg.h kselecttransactionsdlg.h kmergetransactionsdlg.h kconfirmmanualenterdlg.h investactivities.h kbalancechartdlg.h kloadtemplatedlg.h kmymoneysplittable.h kgpgkeyselectiondlg.h transactionmatcher.h kbalancewarning.h
+
+instdir=$(includedir)/kmymoney
+inst_HEADERS = transactioneditor.h investtransactioneditor.h kcurrencycalculator.h
+
+SUBDIRS = settings
+
+messages: rc.cpp
diff --git a/kmymoney2/dialogs/investactivities.cpp b/kmymoney2/dialogs/investactivities.cpp
new file mode 100644
index 0000000..d929c38
--- /dev/null
+++ b/kmymoney2/dialogs/investactivities.cpp
@@ -0,0 +1,624 @@
+/***************************************************************************
+ investactivities.cpp
+ ----------
+ begin : Fri Dec 15 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kmymoneycompletion.h>
+#include <kmymoney/mymoneyfile.h>
+
+#include "investactivities.h"
+
+using namespace Invest;
+using namespace KMyMoneyRegister;
+
+bool Activity::isComplete(QString& reason) const
+{
+ bool rc = false;
+ KMyMoneySecurity* security = dynamic_cast<KMyMoneySecurity*>(haveWidget("security"));
+ if(!security->currentText().isEmpty()) {
+ rc = security->selector()->contains(security->currentText());
+ }
+ return rc;
+}
+
+bool Activity::haveAssetAccount(void) const
+{
+ KMyMoneyCategory* cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("asset-account"));
+
+ bool rc = true;
+ if(!isMultiSelection())
+ rc = !cat->currentText().isEmpty();
+
+ if(rc && !cat->currentText().isEmpty()) {
+ rc = cat->selector()->contains(cat->currentText());
+ }
+ return rc;
+}
+
+bool Activity::haveCategoryAndAmount(const QString& category, const QString& amount, bool optional) const
+{
+ KMyMoneyCategory* cat = dynamic_cast<KMyMoneyCategory*>(haveWidget(category));
+
+ bool rc = true;
+ if(!isMultiSelection() && !optional)
+ rc = !cat->currentText().isEmpty();
+
+ if(rc && !cat->currentText().isEmpty()) {
+ rc = cat->selector()->contains(cat->currentText()) || cat->isSplitTransaction();
+ if(rc && !amount.isEmpty()) {
+ MyMoneyMoney value = dynamic_cast<kMyMoneyEdit*>(haveWidget(amount))->value();
+ if(!isMultiSelection())
+ rc = !value.isZero();
+ }
+ }
+ return rc;
+}
+
+bool Activity::haveShares(void) const
+{
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ if(isMultiSelection() && amount->text().isEmpty())
+ return true;
+
+ return !amount->value().isZero();
+}
+
+bool Activity::havePrice(void) const
+{
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
+ if(isMultiSelection() && amount->text().isEmpty())
+ return true;
+
+ return !amount->value().isZero();
+}
+
+bool Activity::createCategorySplits(const MyMoneyTransaction& t, KMyMoneyCategory* cat, kMyMoneyEdit* amount, MyMoneyMoney factor, QValueList<MyMoneySplit>&splits, const QValueList<MyMoneySplit>& osplits ) const
+{
+ bool rc = true;
+ if(!isMultiSelection() || (isMultiSelection() && !cat->currentText().isEmpty())) {
+ if(!cat->isSplitTransaction()) {
+ splits.clear();
+ MyMoneySplit s1;
+ QString categoryId;
+ categoryId = cat->selectedItem();
+ if(!categoryId.isEmpty()) {
+ s1.setAccountId(categoryId);
+ s1.setValue(amount->value() * factor);
+ if(!s1.value().isZero()) {
+ rc = m_parent->setupPrice(t, s1);
+ }
+ splits.append(s1);
+ }
+ } else {
+ splits = osplits;
+ }
+ }
+ return rc;
+}
+
+void Activity::createAssetAccountSplit(MyMoneySplit& split, const MyMoneySplit& stockSplit) const
+{
+ KMyMoneyCategory* cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("asset-account"));
+ if(!isMultiSelection() || (isMultiSelection() && !cat->currentText().isEmpty())) {
+ QString categoryId;
+ categoryId = cat->selectedItem();
+ split.setAccountId(categoryId);
+ }
+ split.setMemo(stockSplit.memo());
+}
+
+MyMoneyMoney Activity::sumSplits(const MyMoneySplit& s0, const QValueList<MyMoneySplit>& feeSplits, const QValueList<MyMoneySplit>& interestSplits) const
+{
+ MyMoneyMoney total;
+ total = s0.value();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = feeSplits.begin(); it_s != feeSplits.end(); ++it_s) {
+ total += (*it_s).value();
+ }
+ for(it_s = interestSplits.begin(); it_s != interestSplits.end(); ++it_s) {
+ total += (*it_s).value();
+ }
+ return total;
+}
+
+void Activity::setLabelText(const QString& idx, const QString& txt) const
+{
+ QLabel* w = dynamic_cast<QLabel*>(haveWidget(idx));
+ if(w) {
+ w->setText(txt);
+ } else {
+ qDebug("Unknown QLabel named '%s'", idx.data());
+ }
+}
+
+void Activity::preloadAssetAccount(void)
+{
+ KMyMoneyCategory* cat;
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("asset-account"));
+ if(cat->isVisible()) {
+ if(cat->currentText().isEmpty()) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->accountByName(i18n("%1 (Brokerage)").arg(m_parent->account().name()));
+ if(!acc.id().isEmpty()) {
+ bool blocked = cat->signalsBlocked();
+ // block signals, so that the focus does not go crazy
+ cat->blockSignals(true);
+ cat->completion()->setSelected(acc.id());
+ cat->slotItemSelected(acc.id());
+ cat->blockSignals(blocked);
+ }
+ }
+ }
+}
+
+void Buy::showWidgets(void) const
+{
+ KMyMoneyCategory* cat;
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
+ cat->parentWidget()->show();
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ cat->parentWidget()->show();
+ kMyMoneyEdit* shareEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ shareEdit->show();
+ shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction()));
+ cat->parentWidget()->show();
+ haveWidget("asset-account")->show();
+ haveWidget("price")->show();
+ haveWidget("total")->show();
+ setLabelText("fee-label", i18n("Fees"));
+ setLabelText("interest-label", i18n("Interest"));
+ setLabelText("interest-amount-label", i18n("Amount"));
+ setLabelText("asset-label", i18n("Account"));
+ setLabelText("shares-label", i18n("Shares"));
+ setLabelText("price-label", i18n("Price/share"));
+ setLabelText("total-label", i18n("Total"));
+}
+
+bool Buy::isComplete(QString& reason) const
+{
+ bool rc = Activity::isComplete(reason);
+ rc &= haveAssetAccount();
+ rc &= haveFees(true);
+ rc &= haveInterest(true);
+ rc &= haveShares();
+ rc &= havePrice();
+
+ return rc;
+}
+
+bool Buy::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(m_interestSplits);
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ QString reason;
+ if(!isComplete(reason))
+ return false;
+
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
+
+ s0.setAction(MyMoneySplit::BuyShares);
+
+ MyMoneyMoney shares = s0.shares();
+ MyMoneyMoney price;
+ if(!s0.shares().isZero())
+ price = (s0.value() / s0.shares()).reduce();
+
+ if(!isMultiSelection() || (isMultiSelection() && !sharesEdit->text().isEmpty())) {
+ shares = sharesEdit->value().abs();
+ s0.setShares(shares);
+ s0.setValue((shares * price).reduce());
+ s0.setPrice(price);
+ }
+ if(!isMultiSelection() || (isMultiSelection() && !priceEdit->text().isEmpty())) {
+ price = priceEdit->value().abs();
+ if(priceMode() == InvestTransactionEditor::PricePerTransaction) {
+ s0.setValue(price.reduce());
+ if(!s0.shares().isZero())
+ s0.setPrice((price / s0.shares()).reduce());
+ } else {
+ s0.setValue((shares * price).reduce());
+ s0.setPrice(price);
+ }
+ }
+
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount")), MyMoneyMoney(1,1), feeSplits, m_feeSplits))
+ return false;
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount")), MyMoneyMoney(-1,1), interestSplits, m_interestSplits))
+ return false;
+
+ createAssetAccountSplit(assetAccountSplit, s0);
+
+ MyMoneyMoney total = sumSplits(s0, feeSplits, interestSplits);
+ assetAccountSplit.setValue(-total);
+
+ if(!m_parent->setupPrice(t, assetAccountSplit))
+ return false;
+
+ return true;
+}
+
+void Sell::showWidgets(void) const
+{
+ KMyMoneyCategory* cat;
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ cat->parentWidget()->show();
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
+ cat->parentWidget()->show();
+ kMyMoneyEdit* shareEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ shareEdit->show();
+ shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction()));
+ haveWidget("asset-account")->show();
+ haveWidget("price")->show();
+ haveWidget("total")->show();
+
+ setLabelText("fee-label", i18n("Fees"));
+ setLabelText("interest-label", i18n("Interest"));
+ setLabelText("interest-amount-label", i18n("Amount"));
+ setLabelText("asset-label", i18n("Account"));
+ setLabelText("shares-label", i18n("Shares"));
+ setLabelText("price-label", i18n("Price/share"));
+ setLabelText("total-label", i18n("Total"));
+}
+
+bool Sell::isComplete(QString& reason) const
+{
+ bool rc = Activity::isComplete(reason);
+ rc &= haveAssetAccount();
+ rc &= haveFees(true);
+ rc &= haveInterest(true);
+ rc &= haveShares();
+ rc &= havePrice();
+ return rc;
+}
+
+bool Sell::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ QString reason;
+ if(!isComplete(reason))
+ return false;
+
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
+
+ s0.setAction(MyMoneySplit::BuyShares);
+
+ MyMoneyMoney shares = s0.shares();
+ MyMoneyMoney price;
+ if(!s0.shares().isZero())
+ price = (s0.value() / s0.shares()).reduce();
+
+ if(!isMultiSelection() || (isMultiSelection() && !sharesEdit->text().isEmpty())) {
+ shares = -sharesEdit->value().abs();
+ s0.setShares(shares);
+ s0.setValue((shares * price).reduce());
+ s0.setPrice(price);
+ }
+ if(!isMultiSelection() || (isMultiSelection() && !priceEdit->text().isEmpty())) {
+ price = priceEdit->value().abs();
+ if(priceMode() == InvestTransactionEditor::PricePerTransaction) {
+ price = -price;
+ s0.setValue(price.reduce());
+ if(!s0.shares().isZero())
+ s0.setPrice((price / s0.shares()).reduce());
+ } else {
+ s0.setValue((shares * price).reduce());
+ s0.setPrice(price);
+ }
+ }
+
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount")), MyMoneyMoney(1,1), feeSplits, m_feeSplits))
+ return false;
+
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount")), MyMoneyMoney(-1,1), interestSplits, m_interestSplits))
+ return false;
+
+ createAssetAccountSplit(assetAccountSplit, s0);
+
+ MyMoneyMoney total = sumSplits(s0, feeSplits, interestSplits);
+ assetAccountSplit.setValue(-total);
+
+ if(!m_parent->setupPrice(t, assetAccountSplit))
+ return false;
+
+ return true;
+}
+
+void Div::showWidgets(void) const
+{
+ KMyMoneyCategory* cat;
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ cat->parentWidget()->show();
+ haveWidget("asset-account")->show();
+ haveWidget("total")->show();
+
+ setLabelText("interest-amount-label", i18n("Amount"));
+ setLabelText("interest-label", i18n("Interest"));
+ setLabelText("asset-label", i18n("Account"));
+ setLabelText("total-label", i18n("Total"));
+}
+
+bool Div::isComplete(QString& reason) const
+{
+ bool rc = haveAssetAccount();
+ rc &= haveInterest(false);
+ return rc;
+}
+
+bool Div::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(m_feeSplits);
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ QString reason;
+ if(!isComplete(reason))
+ return false;
+
+ s0.setAction(MyMoneySplit::Dividend);
+
+ // for dividends, we only use the stock split as a marker
+ MyMoneyMoney shares;
+ s0.setShares(shares);
+ s0.setValue(shares);
+ s0.setPrice(MyMoneyMoney(1,1));
+
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount")), MyMoneyMoney(-1,1), interestSplits, m_interestSplits))
+ return false;
+
+ createAssetAccountSplit(assetAccountSplit, s0);
+
+ MyMoneyMoney total = sumSplits(s0, feeSplits, interestSplits);
+ assetAccountSplit.setValue(-total);
+
+ if(!m_parent->setupPrice(t, assetAccountSplit))
+ return false;
+
+ return true;
+}
+
+void Reinvest::showWidgets(void) const
+{
+ KMyMoneyCategory* cat;
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ cat->parentWidget()->show();
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
+ cat->parentWidget()->show();
+ kMyMoneyEdit* shareEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ shareEdit->show();
+ shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction()));
+ haveWidget("price")->show();
+ haveWidget("total")->show();
+
+ setLabelText("fee-label", i18n("Fees"));
+ setLabelText("interest-label", i18n("Interest"));
+ setLabelText("shares-label", i18n("Shares"));
+ setLabelText("price-label", i18n("Price/share"));
+ setLabelText("total-label", i18n("Total"));
+}
+
+bool Reinvest::isComplete(QString& reason) const
+{
+ bool rc = Activity::isComplete(reason);
+ rc &= haveCategoryAndAmount("interest-account", QString(), false);
+ rc &= haveFees(true);
+ rc &= haveShares();
+ rc &= havePrice();
+ return rc;
+}
+
+bool Reinvest::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(assetAccountSplit);
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ QString reason;
+ if(!isComplete(reason))
+ return false;
+
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
+
+ s0.setAction(MyMoneySplit::ReinvestDividend);
+
+ MyMoneyMoney shares = s0.shares();
+ MyMoneyMoney price;
+ if(!s0.shares().isZero())
+ price = (s0.value() / s0.shares()).reduce();
+
+ if(!isMultiSelection() || (isMultiSelection() && !sharesEdit->text().isEmpty())) {
+ shares = sharesEdit->value().abs();
+ s0.setShares(shares);
+ s0.setValue((shares * price).reduce());
+ s0.setPrice(price);
+ }
+ if(!isMultiSelection() || (isMultiSelection() && !priceEdit->text().isEmpty())) {
+ price = priceEdit->value().abs();
+ if(priceMode() == InvestTransactionEditor::PricePerTransaction) {
+ s0.setValue(price.reduce());
+ if(!s0.shares().isZero())
+ s0.setPrice((price / s0.shares()).reduce());
+ } else {
+ s0.setValue((shares * price).reduce());
+ s0.setPrice(price);
+ }
+ }
+
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount")), MyMoneyMoney(1,1), feeSplits, m_feeSplits))
+ return false;
+
+ if(!createCategorySplits(t, dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account")), dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount")), MyMoneyMoney(-1,1), interestSplits, m_interestSplits))
+ return false;
+
+ if(interestSplits.count() != 1) {
+ qDebug("more or less than one interest split in Reinvest::createTransaction. Not created.");
+ return false;
+ }
+
+ MyMoneySplit& s1 = interestSplits[0];
+
+ MyMoneyMoney total = sumSplits(s0, feeSplits, QValueList<MyMoneySplit>());
+ s1.setValue(-total);
+
+ if(!m_parent->setupPrice(t, s1))
+ return false;
+
+ return true;
+}
+
+void Add::showWidgets(void) const
+{
+ kMyMoneyEdit* shareEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ shareEdit->show();
+ shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction()));
+
+ setLabelText("shares-label", i18n("Shares"));
+}
+
+bool Add::isComplete(QString& reason) const
+{
+ bool rc = Activity::isComplete(reason);
+ rc &= haveShares();
+ return rc;
+}
+
+bool Add::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(t);
+ Q_UNUSED(assetAccountSplit);
+ Q_UNUSED(m_feeSplits);
+ Q_UNUSED(m_interestSplits);
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ QString reason;
+ if(!isComplete(reason))
+ return false;
+
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+
+ s0.setAction(MyMoneySplit::AddShares);
+ s0.setShares(sharesEdit->value().abs());
+ s0.setValue(MyMoneyMoney(0, 1));
+ s0.setPrice(MyMoneyMoney(0, 1));
+
+ feeSplits.clear();
+ interestSplits.clear();
+
+ return true;
+}
+
+void Remove::showWidgets(void) const
+{
+ kMyMoneyEdit* shareEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ shareEdit->show();
+ shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction()));
+ setLabelText("shares-label", i18n("Shares"));
+}
+
+bool Remove::isComplete(QString& reason) const
+{
+ bool rc = Activity::isComplete(reason);
+ rc &= haveShares();
+ return rc;
+}
+
+bool Remove::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(t);
+ Q_UNUSED(assetAccountSplit);
+ Q_UNUSED(m_feeSplits);
+ Q_UNUSED(m_interestSplits);
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ QString reason;
+ if(!isComplete(reason))
+ return false;
+
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+
+ s0.setAction(MyMoneySplit::AddShares);
+ s0.setShares(-(sharesEdit->value().abs()));
+ s0.setValue(MyMoneyMoney(0, 1));
+ s0.setPrice(MyMoneyMoney(0, 1));
+
+ feeSplits.clear();
+ interestSplits.clear();
+
+ return true;
+}
+
+void Split::showWidgets(void) const
+{
+ // TODO do we need a special split ratio widget?
+ // TODO maybe yes, currently the precision is the one of the fraction and might differ from it
+ kMyMoneyEdit* shareEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ shareEdit->show();
+ shareEdit->setPrecision(-1);
+ setLabelText("shares-label", i18n("Ratio 1/"));
+}
+
+bool Split::isComplete(QString& reason) const
+{
+ bool rc = Activity::isComplete(reason);
+ rc &= haveShares();
+ return rc;
+}
+
+bool Split::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency)
+{
+ Q_UNUSED(t);
+ Q_UNUSED(assetAccountSplit);
+ Q_UNUSED(m_feeSplits);
+ Q_UNUSED(m_interestSplits);
+ Q_UNUSED(security);
+ Q_UNUSED(currency);
+
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+
+ s0.setAction(MyMoneySplit::SplitShares);
+ s0.setShares(sharesEdit->value().abs());
+ s0.setValue(MyMoneyMoney(0, 1));
+ s0.setPrice(MyMoneyMoney(0, 1));
+
+ feeSplits.clear();
+ interestSplits.clear();
+
+ return true;
+}
+
+
diff --git a/kmymoney2/dialogs/investactivities.h b/kmymoney2/dialogs/investactivities.h
new file mode 100644
index 0000000..91b474d
--- /dev/null
+++ b/kmymoney2/dialogs/investactivities.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ investactivities.h
+ ----------
+ begin : Fri Dec 15 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef INVESTACTIVITIES_H
+#define INVESTACTIVITIES_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/register.h>
+#include <kmymoney/investtransactioneditor.h>
+
+namespace Invest {
+
+class Activity
+{
+public:
+ virtual MyMoneySplit::investTransactionTypeE type(void) const = 0;
+ virtual void showWidgets(void) const = 0;
+ virtual bool isComplete(QString& reason) const = 0;
+
+ /**
+ * Create a transaction @p t based on the split @p s0 and the data contained
+ * in the widgets. In multiselection mode, @p assetAccountSplit, @p feeSplits, @p
+ * interestSplits, @p security and @p currency are taken from the original
+ * transaction and should be used as well.
+ *
+ * @return @p true if creation was successful, @p false otherwise
+ */
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) = 0;
+
+ virtual void preloadAssetAccount(void);
+ virtual ~Activity() {}
+
+protected:
+ Activity(InvestTransactionEditor* editor) { m_parent = editor; }
+ QWidget* haveWidget(const QString& name) const { return m_parent->haveWidget(name); }
+ bool haveAssetAccount(void) const;
+ bool haveFees(bool optional = false) const { return haveCategoryAndAmount("fee-account", "fee-amount", optional); }
+ bool haveInterest(bool optional = false) const { return haveCategoryAndAmount("interest-account", "interest-amount", optional); }
+ bool haveShares(void) const;
+ bool havePrice(void) const;
+ bool isMultiSelection(void) const { return m_parent->isMultiSelection(); }
+ bool createCategorySplits(const MyMoneyTransaction& t, KMyMoneyCategory* cat, kMyMoneyEdit* amount, MyMoneyMoney factor, QValueList<MyMoneySplit>&splits, const QValueList<MyMoneySplit>& osplits ) const;
+ void createAssetAccountSplit(MyMoneySplit& split, const MyMoneySplit& stockSplit) const;
+ MyMoneyMoney sumSplits(const MyMoneySplit& s0, const QValueList<MyMoneySplit>& feeSplits, const QValueList<MyMoneySplit>& interestSplits) const;
+ bool haveCategoryAndAmount(const QString& category, const QString& amount, bool optional) const;
+ void setLabelText(const QString& idx, const QString& txt) const;
+ InvestTransactionEditor::priceModeE priceMode(void) const { return m_parent->priceMode(); }
+
+protected:
+ InvestTransactionEditor* m_parent;
+ QMap<QString, MyMoneyMoney> m_priceInfo;
+};
+
+class Buy : public Activity
+{
+public:
+ Buy(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Buy() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::BuyShares; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+class Sell : public Activity
+{
+public:
+ Sell(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Sell() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::SellShares; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+class Div : public Activity
+{
+public:
+ Div(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Div() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::Dividend; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+class Reinvest : public Activity
+{
+public:
+ Reinvest(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Reinvest() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::ReinvestDividend; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+class Add : public Activity
+{
+public:
+ Add(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Add() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::AddShares; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+class Remove : public Activity
+{
+public:
+ Remove(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Remove() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::RemoveShares; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+class Split : public Activity
+{
+public:
+ Split(InvestTransactionEditor* editor) : Activity(editor) {}
+ virtual ~Split() {}
+ virtual MyMoneySplit::investTransactionTypeE type(void) const { return MyMoneySplit::SplitShares; }
+ virtual void showWidgets(void) const;
+ virtual bool isComplete(QString& reason) const;
+ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& m_feeSplits, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency);
+};
+
+} // namespace Invest
+
+
+
+#endif // INVESTACTIVITIES_H
+
diff --git a/kmymoney2/dialogs/investtransactioneditor.cpp b/kmymoney2/dialogs/investtransactioneditor.cpp
new file mode 100644
index 0000000..5a62436
--- /dev/null
+++ b/kmymoney2/dialogs/investtransactioneditor.cpp
@@ -0,0 +1,1094 @@
+/***************************************************************************
+ investtransactioneditor.cpp
+ ----------
+ begin : Fri Dec 15 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <typeinfo>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <ktextedit.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+#include <kstdguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/investtransactioneditor.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneyaccountcompletion.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/transactionform.h>
+
+#include "../dialogs/ksplittransactiondlg.h"
+#include "../dialogs/kcurrencycalculator.h"
+
+#include "../kmymoneyglobalsettings.h"
+
+#include "investactivities.h"
+
+using namespace KMyMoneyRegister;
+using namespace KMyMoneyTransactionForm;
+using namespace Invest;
+
+class InvestTransactionEditor::Private {
+ friend class Invest::Activity;
+
+public:
+ Private(InvestTransactionEditor* parent) :
+ m_parent(parent),
+ m_activity(0)
+ {
+ m_phonyAccount = MyMoneyAccount("Phony-ID", MyMoneyAccount());
+ }
+
+ ~Private() {
+ delete m_activity;
+ }
+
+ QWidget* haveWidget(const QString& name) { return m_parent->haveWidget(name); }
+
+ InvestTransactionEditor* m_parent;
+ Activity* m_activity;
+ MyMoneyAccount m_phonyAccount;
+ MyMoneySplit m_phonySplit;
+};
+
+
+InvestTransactionEditor::InvestTransactionEditor() :
+ d(new Private(this))
+{
+}
+
+InvestTransactionEditor::~InvestTransactionEditor()
+{
+ delete d;
+}
+
+InvestTransactionEditor::InvestTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::InvestTransaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) :
+ TransactionEditor(regForm, item, list, lastPostDate),
+ d(new Private(this))
+{
+ // dissect the transaction into its type, splits, currency, security etc.
+ dissectTransaction(m_transaction, m_split,
+ m_assetAccountSplit,
+ m_feeSplits,
+ m_interestSplits,
+ m_security,
+ m_currency,
+ m_transactionType);
+
+ // determine initial activity object
+ activityFactory(m_transactionType);
+}
+
+void InvestTransactionEditor::activityFactory(MyMoneySplit::investTransactionTypeE type)
+{
+ if(!d->m_activity || type != d->m_activity->type()) {
+ delete d->m_activity;
+ switch(type) {
+ default:
+ case MyMoneySplit::BuyShares:
+ d->m_activity = new Buy(this);
+ break;
+ case MyMoneySplit::SellShares:
+ d->m_activity = new Sell(this);
+ break;
+ case MyMoneySplit::Dividend:
+ case MyMoneySplit::Yield:
+ d->m_activity = new Div(this);
+ break;
+ case MyMoneySplit::ReinvestDividend:
+ d->m_activity = new Reinvest(this);
+ break;
+ case MyMoneySplit::AddShares:
+ d->m_activity = new Add(this);
+ break;
+ case MyMoneySplit::RemoveShares:
+ d->m_activity = new Remove(this);
+ break;
+ case MyMoneySplit::SplitShares:
+ d->m_activity = new Split(this);
+ break;
+ }
+ }
+}
+
+void InvestTransactionEditor::dissectTransaction(const MyMoneyTransaction& transaction, const MyMoneySplit& split, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency, MyMoneySplit::investTransactionTypeE& transactionType)
+{
+ // collect the splits. split references the stock account and should already
+ // be set up. assetAccountSplit references the corresponding asset account (maybe
+ // empty), feeSplits is the list of all expenses and interestSplits
+ // the list of all incomes
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ if((*it_s).id() == split.id()) {
+ security = file->security(acc.currencyId());
+ } else if(acc.accountGroup() == MyMoneyAccount::Expense) {
+ feeSplits.append(*it_s);
+ // feeAmount += (*it_s).value();
+ } else if(acc.accountGroup() == MyMoneyAccount::Income) {
+ interestSplits.append(*it_s);
+ // interestAmount += (*it_s).value();
+ } else {
+ assetAccountSplit = *it_s;
+ }
+ }
+
+ // determine transaction type
+ if(split.action() == MyMoneySplit::ActionAddShares) {
+ transactionType = (!split.shares().isNegative()) ? MyMoneySplit::AddShares : MyMoneySplit::RemoveShares;
+ } else if(split.action() == MyMoneySplit::ActionBuyShares) {
+ transactionType = (!split.value().isNegative()) ? MyMoneySplit::BuyShares : MyMoneySplit::SellShares;
+ } else if(split.action() == MyMoneySplit::ActionDividend) {
+ transactionType = MyMoneySplit::Dividend;
+ } else if(split.action() == MyMoneySplit::ActionReinvestDividend) {
+ transactionType = MyMoneySplit::ReinvestDividend;
+ } else if(split.action() == MyMoneySplit::ActionYield) {
+ transactionType = MyMoneySplit::Yield;
+ } else if(split.action() == MyMoneySplit::ActionSplitShares) {
+ transactionType = MyMoneySplit::SplitShares;
+ } else
+ transactionType = MyMoneySplit::BuyShares;
+
+ currency.setTradingSymbol("???");
+ try {
+ currency = file->security(transaction.commodity());
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void InvestTransactionEditor::createEditWidgets(void)
+{
+ KMyMoneyActivityCombo* activity = new KMyMoneyActivityCombo();
+ m_editWidgets["activity"] = activity;
+ connect(activity, SIGNAL(activitySelected(MyMoneySplit::investTransactionTypeE)), this, SLOT(slotUpdateActivity(MyMoneySplit::investTransactionTypeE)));
+ connect(activity, SIGNAL(activitySelected(MyMoneySplit::investTransactionTypeE)), this, SLOT(slotUpdateButtonState()));
+
+ m_editWidgets["postdate"] = new kMyMoneyDateInput;
+ connect(m_editWidgets["postdate"], SIGNAL(dateChanged(const QDate&)), this, SLOT(slotUpdateButtonState()));
+
+ KMyMoneySecurity* security = new KMyMoneySecurity;
+ security->setHint(i18n("Security"));
+ m_editWidgets["security"] = security;
+ connect(security, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateSecurity(const QString&)));
+ connect(security, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(security, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateSecurity(const QString&, QString&)));
+ connect(security, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+
+ KMyMoneyCategory* asset = new KMyMoneyCategory(0, 0, false);
+ asset->setHint(i18n("Asset account"));
+ m_editWidgets["asset-account"] = asset;
+ connect(asset, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(asset, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+
+ KMyMoneyCategory* fees = new KMyMoneyCategory(0, 0, true);
+ fees->setHint(i18n("Fees"));
+ m_editWidgets["fee-account"] = fees;
+ connect(fees, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateFeeCategory(const QString&)));
+ connect(fees, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(fees, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateFeeVisibility(const QString&)));
+ connect(fees, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateFeeCategory(const QString&, QString&)));
+ connect(fees, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+ connect(fees->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditFeeSplits()));
+
+ KMyMoneyCategory* interest = new KMyMoneyCategory(0, 0, true);
+ interest->setHint(i18n("Interest"));
+ m_editWidgets["interest-account"] = interest;
+ connect(interest, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateInterestCategory(const QString&)));
+ connect(interest, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(interest, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateInterestVisibility(const QString&)));
+ connect(interest, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateInterestCategory(const QString&, QString&)));
+ connect(interest, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+ connect(interest->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditInterestSplits()));
+
+ KTextEdit* memo = new KTextEdit;
+ memo->setTabChangesFocus(true);
+ m_editWidgets["memo"] = memo;
+
+ kMyMoneyEdit* value = new kMyMoneyEdit;
+ value->setHint(i18n("Shares"));
+ value->setResetButtonVisible(false);
+ m_editWidgets["shares"] = value;
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateTotalAmount()));
+
+ value = new kMyMoneyEdit;
+ value->setHint(i18n("Price"));
+ value->setResetButtonVisible(false);
+ value->setPrecision(KMyMoneyGlobalSettings::pricePrecision());
+ m_editWidgets["price"] = value;
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateTotalAmount()));
+
+ value = new kMyMoneyEdit;
+ // TODO once we have the selected transactions as array of Transaction
+ // we can allow multiple splits for fee and interest
+ value->setResetButtonVisible(false);
+ m_editWidgets["fee-amount"] = value;
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateTotalAmount()));
+
+ value = new kMyMoneyEdit;
+ // TODO once we have the selected transactions as array of Transaction
+ // we can allow multiple splits for fee and interest
+ value->setResetButtonVisible(false);
+ m_editWidgets["interest-amount"] = value;
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateTotalAmount()));
+
+ KMyMoneyReconcileCombo* reconcile = new KMyMoneyReconcileCombo;
+ m_editWidgets["status"] = reconcile;
+ connect(reconcile, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateButtonState()));
+
+ KMyMoneyRegister::QWidgetContainer::iterator it_w;
+ for(it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) {
+ (*it_w)->installEventFilter(this);
+ }
+
+ QLabel* label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::AlignRight | Qt::DontClip);
+ m_editWidgets["total"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["total-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["asset-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["fee-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["fee-amount-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["interest-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["interest-amount-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["price-label"] = label;
+
+ label = new QLabel("", 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["shares-label"] = label;
+
+ // if we don't have more than 1 selected transaction, we don't need
+ // the "don't change" item in some of the combo widgets
+ if(m_transactions.count() < 2) {
+ reconcile->removeDontCare();
+ }
+}
+
+int InvestTransactionEditor::slotEditFeeSplits(void)
+{
+ return editSplits("fee-account", "fee-amount", m_feeSplits, false, SLOT(slotEditFeeSplits()));
+}
+
+int InvestTransactionEditor::slotEditInterestSplits(void)
+{
+ return editSplits("interest-account", "interest-amount", m_interestSplits, true, SLOT(slotEditInterestSplits()));
+}
+
+int InvestTransactionEditor::editSplits(const QString& categoryWidgetName, const QString& amountWidgetName, QValueList<MyMoneySplit>& splits, bool isIncome, const char* slotEditSplits)
+{
+ int rc = QDialog::Rejected;
+
+ if(!m_openEditSplits) {
+ // only get in here in a single instance
+ m_openEditSplits = true;
+
+ // force focus change to update all data
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets[categoryWidgetName]);
+ QWidget* w = category->splitButton();
+ if(w)
+ w->setFocus();
+
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(haveWidget(amountWidgetName));
+
+ MyMoneyTransaction transaction;
+ transaction.setCommodity(m_currency.id());
+ if(splits.count() == 0 && category->selectedItem()) {
+ MyMoneySplit s;
+ s.setAccountId(category->selectedItem());
+ s.setShares(amount->value());
+ s.setValue(s.shares());
+ splits << s;
+ }
+ // use the transactions commodity as the currency indicator for the splits
+ // this is used to allow some useful setting for the fractions in the amount fields
+ try {
+ d->m_phonyAccount.setCurrencyId(m_transaction.commodity());
+ d->m_phonyAccount.fraction(MyMoneyFile::instance()->security(m_transaction.commodity()));
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to setup precision");
+ delete e;
+ }
+
+ if(createPseudoTransaction(transaction, splits)) {
+ MyMoneyMoney value;
+
+ KSplitTransactionDlg* dlg = new KSplitTransactionDlg(transaction,
+ d->m_phonySplit,
+ d->m_phonyAccount,
+ false,
+ isIncome,
+ 0,
+ m_priceInfo,
+ m_regForm);
+ // connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), this, SIGNAL(newCategory(MyMoneyAccount&)));
+
+ if((rc = dlg->exec()) == QDialog::Accepted) {
+ transaction = dlg->transaction();
+ // collect splits out of the transaction
+ splits.clear();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ MyMoneyMoney fees;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ if((*it_s).accountId() == d->m_phonyAccount.id())
+ continue;
+ splits << *it_s;
+ fees += (*it_s).shares();
+ }
+ if(isIncome)
+ fees = -fees;
+
+ QString categoryId;
+ setupCategoryWidget(category, splits, categoryId, slotEditSplits);
+ amount->setValue(fees);
+ slotUpdateTotalAmount();
+ }
+
+ delete dlg;
+ }
+
+ // focus jumps into the memo field
+ if((w = haveWidget("memo")) != 0) {
+ w->setFocus();
+ }
+
+ m_openEditSplits = false;
+ }
+ return rc;
+}
+
+bool InvestTransactionEditor::createPseudoTransaction(MyMoneyTransaction& t, const QValueList<MyMoneySplit>& splits)
+{
+ t.removeSplits();
+
+ MyMoneySplit split;
+ split.setAccountId(d->m_phonyAccount.id());
+ split.setValue(-subtotal(splits));
+ split.setShares(split.value());
+ t.addSplit(split);
+ d->m_phonySplit = split;
+
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ split = *it_s;
+ split.clearId();
+ t.addSplit(split);
+ }
+ return true;
+}
+
+void InvestTransactionEditor::slotCreateSecurity(const QString& name, QString& id)
+{
+ MyMoneyAccount acc;
+ QRegExp exp("([^:]+)");
+ if(exp.search(name) != -1) {
+ acc.setName(exp.cap(1));
+
+ emit createSecurity(acc, m_account);
+
+ // return id
+ id = acc.id();
+
+ if(!id.isEmpty()) {
+ slotUpdateSecurity(id);
+ }
+ }
+}
+
+void InvestTransactionEditor::slotCreateFeeCategory(const QString& name, QString& id)
+{
+ MyMoneyAccount acc;
+ acc.setName(name);
+
+ emit createCategory(acc, MyMoneyFile::instance()->expense());
+
+ // return id
+ id = acc.id();
+}
+
+void InvestTransactionEditor::slotUpdateFeeCategory(const QString& id)
+{
+ haveWidget("fee-amount")->setDisabled(id.isEmpty());
+}
+
+void InvestTransactionEditor::slotUpdateFeeVisibility(const QString& txt)
+{
+ haveWidget("fee-amount")->setHidden(txt.isEmpty());
+ QWidget* w = haveWidget("fee-amount-label");
+ if(w)
+ w->setShown(haveWidget("fee-amount")->isVisible());
+}
+
+void InvestTransactionEditor::slotUpdateInterestCategory(const QString& id)
+{
+ haveWidget("interest-amount")->setDisabled(id.isEmpty());
+}
+
+void InvestTransactionEditor::slotUpdateInterestVisibility(const QString& txt)
+{
+ KMyMoneyCategory* interest = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ QWidget* w = haveWidget("interest-amount-label");
+
+ if(dynamic_cast<Reinvest*>(d->m_activity)) {
+ interest->splitButton()->hide();
+ haveWidget("interest-amount")->setHidden(true);
+ // for the reinvest case, we don't ever hide the label do avoid a shine through
+ // of the underlying transaction data.
+ w = 0;
+ } else {
+ haveWidget("interest-amount")->setHidden(txt.isEmpty());
+ // FIXME once we can handle split interest, we need to uncomment the next line
+ // interest->splitButton()->show();
+ }
+
+ if(w)
+ w->setShown(haveWidget("interest-amount")->isVisible());
+}
+
+void InvestTransactionEditor::slotCreateInterestCategory(const QString& name, QString& id)
+{
+ MyMoneyAccount acc;
+ acc.setName(name);
+
+ emit createCategory(acc, MyMoneyFile::instance()->income());
+
+ // return id
+ id = acc.id();
+}
+
+void InvestTransactionEditor::slotReloadEditWidgets(void)
+{
+ KMyMoneyCategory* interest = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ KMyMoneyCategory* fees = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
+ KMyMoneySecurity* security = dynamic_cast<KMyMoneySecurity*>(haveWidget("security"));
+
+ AccountSet aSet;
+ QString id;
+
+ // interest-account
+ aSet.clear();
+ aSet.addAccountGroup(MyMoneyAccount::Income);
+ aSet.load(interest->selector());
+ setupCategoryWidget(interest, m_interestSplits, id, SLOT(slotEditInterestSplits()));
+
+ // fee-account
+ aSet.clear();
+ aSet.addAccountGroup(MyMoneyAccount::Expense);
+ aSet.load(fees->selector());
+ setupCategoryWidget(fees, m_feeSplits, id, SLOT(slotEditFeeSplits()));
+
+ // security
+ aSet.clear();
+ aSet.load(security->selector(), i18n("Security"), m_account.accountList(), true);
+}
+
+void InvestTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action /* action */)
+{
+ QString id;
+
+ kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(haveWidget("postdate"));
+ KMyMoneyReconcileCombo* reconcile = dynamic_cast<KMyMoneyReconcileCombo*>(haveWidget("status"));
+ KMyMoneySecurity* security = dynamic_cast<KMyMoneySecurity*>(haveWidget("security"));
+ KMyMoneyActivityCombo* activity = dynamic_cast<KMyMoneyActivityCombo*>(haveWidget("activity"));
+ KMyMoneyCategory* asset = dynamic_cast<KMyMoneyCategory*>(haveWidget("asset-account"));
+ KTextEdit* memo = dynamic_cast<KTextEdit*>(m_editWidgets["memo"]);
+ kMyMoneyEdit* value;
+ KMyMoneyCategory* interest = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ KMyMoneyCategory* fees = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
+
+ // check if the current transaction has a reference to an equity account
+ bool haveEquityAccount = false;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = m_transaction.splits().begin(); !haveEquityAccount && it_s != m_transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.accountType() == MyMoneyAccount::Equity)
+ haveEquityAccount = true;
+ }
+
+ // asset-account
+ AccountSet aSet;
+ aSet.clear();
+ aSet.addAccountType(MyMoneyAccount::Checkings);
+ aSet.addAccountType(MyMoneyAccount::Savings);
+ aSet.addAccountType(MyMoneyAccount::Cash);
+ aSet.addAccountType(MyMoneyAccount::Asset);
+ aSet.addAccountType(MyMoneyAccount::Currency);
+ aSet.addAccountType(MyMoneyAccount::CreditCard);
+ if(KMyMoneyGlobalSettings::expertMode() || haveEquityAccount)
+ aSet.addAccountGroup(MyMoneyAccount::Equity);
+ aSet.load(asset->selector());
+
+ // security
+ security->setSuppressObjectCreation(false); // allow object creation on the fly
+ aSet.clear();
+ aSet.load(security->selector(), i18n("Security"), m_account.accountList(), true);
+
+ if(!isMultiSelection()) {
+ // date
+ if(m_transaction.postDate().isValid())
+ postDate->setDate(m_transaction.postDate());
+ else if(m_lastPostDate.isValid())
+ postDate->setDate(m_lastPostDate);
+ else
+ postDate->setDate(QDate::currentDate());
+
+ // security (but only if it's not the investment account)
+ if(m_split.accountId() != m_account.id()) {
+ security->completion()->setSelected(m_split.accountId());
+ security->slotItemSelected(m_split.accountId());
+ }
+
+ // activity
+ activity->setActivity(d->m_activity->type());
+ slotUpdateActivity(activity->activity());
+
+ asset->completion()->setSelected(m_assetAccountSplit.accountId());
+ asset->slotItemSelected(m_assetAccountSplit.accountId());
+
+ // interest-account
+ aSet.clear();
+ aSet.addAccountGroup(MyMoneyAccount::Income);
+ aSet.load(interest->selector());
+ setupCategoryWidget(interest, m_interestSplits, id, SLOT(slotEditInterestSplits()));
+ slotUpdateInterestVisibility(interest->currentText());
+
+ // fee-account
+ aSet.clear();
+ aSet.addAccountGroup(MyMoneyAccount::Expense);
+ aSet.load(fees->selector());
+ setupCategoryWidget(fees, m_feeSplits, id, SLOT(slotEditFeeSplits()));
+ slotUpdateFeeVisibility(fees->currentText());
+
+ // memo
+ memo->setText(m_split.memo());
+
+ // shares
+ // don't set the value if the number of shares is zero so that
+ // we can see the hint
+ value = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ if(typeid(*(d->m_activity)) != typeid(Invest::Split(this)))
+ value->setPrecision(MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
+ else
+ value->setPrecision(-1);
+
+ if(!m_split.shares().isZero())
+ value->setValue(m_split.shares().abs());
+
+ // price
+ updatePriceMode(m_split);
+
+ // fee amount
+ value = dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount"));
+ value->setValue(subtotal(m_feeSplits));
+
+ // interest amount
+ value = dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount"));
+ value->setValue(-subtotal(m_interestSplits));
+
+ // total
+ slotUpdateTotalAmount();
+
+ // status
+ if(m_split.reconcileFlag() == MyMoneySplit::Unknown)
+ m_split.setReconcileFlag(MyMoneySplit::NotReconciled);
+ reconcile->setState(m_split.reconcileFlag());
+
+ } else {
+ postDate->loadDate(QDate());
+ reconcile->setState(MyMoneySplit::Unknown);
+ memo->setText(QString());
+
+ // We don't allow to change the activity
+ activity->setActivity(d->m_activity->type());
+ slotUpdateActivity(activity->activity());
+ activity->setDisabled(true);
+
+ // scan the list of selected transactions and check that they have
+ // the same activity.
+ KMyMoneyRegister::SelectedTransactions::iterator it_t = m_transactions.begin();
+ const QString& action = m_item->split().action();
+ bool isNegative = m_item->split().shares().isNegative();
+ bool allSameActivity = true;
+ for(it_t = m_transactions.begin(); allSameActivity && (it_t != m_transactions.end()); ++it_t) {
+ allSameActivity = (action == (*it_t).split().action() && (*it_t).split().shares().isNegative() == isNegative);
+ }
+
+ QStringList fields;
+ fields << "shares" << "price" << "fee-amount" << "interest-amount";
+ QStringList::const_iterator it_f;
+ for(it_f = fields.begin(); it_f != fields.end(); ++it_f) {
+ value = dynamic_cast<kMyMoneyEdit*>(haveWidget((*it_f)));
+ value->setText("");
+ value->setAllowEmpty();
+ }
+
+ // if we have transactions with different activities, disable some more widgets
+ if(!allSameActivity) {
+ fields << "asset-account" << "fee-account" << "interest-account";
+ QStringList::const_iterator it_f;
+ for(it_f = fields.begin(); it_f != fields.end(); ++it_f) {
+ haveWidget(*it_f)->setDisabled(true);
+ }
+ }
+ }
+}
+
+QWidget* InvestTransactionEditor::firstWidget(void) const
+{
+ return 0; // let the creator use the first widget in the tab order
+}
+
+bool InvestTransactionEditor::isComplete(QString& reason) const
+{
+ reason = QString();
+ // reason.clear(); // for Qt4
+ return d->m_activity->isComplete(reason);
+}
+
+MyMoneyMoney InvestTransactionEditor::subtotal(const QValueList<MyMoneySplit>& splits) const
+{
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ MyMoneyMoney sum;
+
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ sum += (*it_s).value();
+ }
+
+ return sum;
+}
+
+void InvestTransactionEditor::slotUpdateSecurity(const QString& stockId)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount stock = file->account(stockId);
+ m_security = file->security(stock.currencyId());
+ m_currency = file->security(m_security.tradingCurrency());
+ bool currencyKnown = !m_currency.id().isEmpty();
+ if(!currencyKnown) {
+ m_currency.setTradingSymbol("???");
+ } else {
+ if(typeid(*(d->m_activity)) != typeid(Invest::Split(this))) {
+ dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"))->setPrecision(MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
+ } else {
+ dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"))->setPrecision(-1);
+ }
+ }
+
+ updatePriceMode();
+
+ d->m_activity->preloadAssetAccount();
+
+ haveWidget("shares")->setEnabled(currencyKnown);
+ haveWidget("price")->setEnabled(currencyKnown);
+ haveWidget("fee-amount")->setEnabled(currencyKnown);
+ haveWidget("interest-amount")->setEnabled(currencyKnown);
+
+ slotUpdateTotalAmount();
+}
+
+void InvestTransactionEditor::totalAmount(MyMoneyMoney& amount) const
+{
+ KMyMoneyActivityCombo* activityCombo = dynamic_cast<KMyMoneyActivityCombo*>(haveWidget("activity"));
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
+ kMyMoneyEdit* feesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount"));
+ kMyMoneyEdit* interestEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount"));
+
+ if(priceMode() == InvestTransactionEditor::PricePerTransaction)
+ amount = priceEdit->value().abs();
+ else
+ amount = sharesEdit->value().abs() * priceEdit->value().abs();
+
+ if(feesEdit->isVisible()) {
+ MyMoneyMoney fee = feesEdit->value();
+ MyMoneyMoney factor(-1,1);
+ switch(activityCombo->activity()) {
+ case MyMoneySplit::BuyShares:
+ case MyMoneySplit::ReinvestDividend:
+ factor = MyMoneyMoney(1,1);
+ break;
+ default:
+ break;
+ }
+ amount += (fee * factor);
+ }
+
+ if(interestEdit->isVisible()) {
+ MyMoneyMoney interest = interestEdit->value();
+ MyMoneyMoney factor(1,1);
+ switch(activityCombo->activity()) {
+ case MyMoneySplit::BuyShares:
+ factor = MyMoneyMoney(-1,1);
+ break;
+ default:
+ break;
+ }
+ amount += (interest * factor);
+ }
+}
+
+void InvestTransactionEditor::slotUpdateTotalAmount(void)
+{
+ QLabel* total = dynamic_cast<QLabel*>(haveWidget("total"));
+
+ if(total && total->isVisible()) {
+ MyMoneyMoney amount;
+ totalAmount(amount);
+ total->setText(amount.formatMoney(m_currency.tradingSymbol(), MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())));
+ }
+}
+
+void InvestTransactionEditor::slotUpdateActivity(MyMoneySplit::investTransactionTypeE activity)
+{
+ // create new activity object if required
+ activityFactory(activity);
+
+ KMyMoneyCategory* cat;
+
+ // hide all dynamic widgets (make sure to use the parentWidget for the
+ // category widgets)
+ haveWidget("interest-account")->parentWidget()->hide();
+ haveWidget("fee-account")->parentWidget()->hide();
+
+ QStringList dynwidgets;
+ dynwidgets << "total-label" << "asset-label" << "fee-label" << "fee-amount-label" << "interest-label" << "interest-amount-label" << "price-label" << "shares-label";
+
+ // hiding labels works by clearing them. hide() does not do the job
+ // as the underlying text in the QTable object will shine through
+ QStringList::const_iterator it_s;
+ for(it_s = dynwidgets.begin(); it_s != dynwidgets.end(); ++it_s) {
+ QLabel* w = dynamic_cast<QLabel*>(haveWidget(*it_s));
+ if(w)
+ w->setText(" ");
+ }
+
+ // real widgets can be hidden
+ dynwidgets.clear();
+ dynwidgets << "asset-account" << "interest-amount" << "fee-amount" << "shares" << "price" << "total";
+
+ for(it_s = dynwidgets.begin(); it_s != dynwidgets.end(); ++it_s) {
+ QWidget* w = haveWidget(*it_s);
+ if(w)
+ w->hide();
+ }
+
+ d->m_activity->showWidgets();
+
+ d->m_activity->preloadAssetAccount();
+
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
+ if(cat->parentWidget()->isVisible())
+ slotUpdateInterestVisibility(cat->currentText());
+
+ cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
+ if(cat->parentWidget()->isVisible())
+ slotUpdateFeeVisibility(cat->currentText());
+}
+
+InvestTransactionEditor::priceModeE InvestTransactionEditor::priceMode(void) const
+{
+ priceModeE mode = static_cast<priceModeE>(0);
+ KMyMoneySecurity* sec = dynamic_cast<KMyMoneySecurity*>(m_editWidgets["security"]);
+ QString accId;
+ if(!sec->currentText().isEmpty()) {
+ accId = sec->selectedItem();
+ if(accId.isEmpty())
+ accId = m_account.id();
+ }
+ while(!accId.isEmpty() && mode == 0) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(accId);
+ if(acc.value("priceMode").isEmpty())
+ accId = acc.parentAccountId();
+ else
+ mode = static_cast<priceModeE>(acc.value("priceMode").toInt());
+ }
+
+ // if it's still <default> then use that default
+ if(mode == 0)
+ mode = PricePerShare;
+ return mode;
+}
+
+bool InvestTransactionEditor::setupPrice(const MyMoneyTransaction& t, MyMoneySplit& split)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount acc = file->account(split.accountId());
+ MyMoneySecurity toCurrency(file->security(acc.currencyId()));
+ int fract = acc.fraction();
+
+ if(acc.currencyId() != t.commodity()) {
+ QMap<QString, MyMoneyMoney>::Iterator it_p;
+ QString key = t.commodity() + "-" + acc.currencyId();
+ it_p = m_priceInfo.find(key);
+
+ // if it's not found, then collect it from the user first
+ MyMoneyMoney price;
+ if(it_p == m_priceInfo.end()) {
+ MyMoneySecurity fromCurrency = file->security(t.commodity());
+ MyMoneyMoney fromValue, toValue;
+
+ fromValue = split.value();
+ MyMoneyPrice priceInfo = MyMoneyFile::instance()->price(fromCurrency.id(), toCurrency.id());
+ toValue = split.value() * priceInfo.rate(toCurrency.id());
+
+ KCurrencyCalculator calc(fromCurrency,
+ toCurrency,
+ fromValue,
+ toValue,
+ t.postDate(),
+ fract,
+ m_regForm, "currencyCalculator");
+
+ if(calc.exec() == QDialog::Rejected) {
+ return false;
+ }
+ price = calc.price();
+ m_priceInfo[key] = price;
+ } else {
+ price = (*it_p);
+ }
+
+ // update shares if the transaction commodity is the currency
+ // of the current selected account
+ split.setShares((split.value() * price).convert(fract));
+ } else {
+ split.setShares(split.value().convert(fract));
+ }
+
+ return true;
+}
+
+bool InvestTransactionEditor::createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool /* skipPriceDialog */)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ // we start with the previous values, make sure we can add them later on
+ t = torig;
+ MyMoneySplit s0 = sorig;
+ s0.clearId();
+
+ KMyMoneySecurity* sec = dynamic_cast<KMyMoneySecurity*>(m_editWidgets["security"]);
+ if(!isMultiSelection() || (isMultiSelection() && !sec->currentText().isEmpty())) {
+ QString securityId = sec->selectedItem();
+ if(!securityId.isEmpty()) {
+ s0.setAccountId(securityId);
+ MyMoneyAccount stockAccount = file->account(securityId);
+ QString currencyId = stockAccount.currencyId();
+ MyMoneySecurity security = file->security(currencyId);
+
+ t.setCommodity(security.tradingCurrency());
+ } else {
+ s0.setAccountId(m_account.id());
+ t.setCommodity(m_account.currencyId());
+ }
+ }
+
+ // extract price info from original transaction
+ m_priceInfo.clear();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ if(!torig.id().isEmpty()) {
+ for(it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) {
+ if((*it_s).id() != sorig.id()) {
+ MyMoneyAccount cat = file->account((*it_s).accountId());
+ if(cat.currencyId() != m_account.currencyId()) {
+ if(!(*it_s).shares().isZero() && !(*it_s).value().isZero()) {
+ m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce();
+ }
+ }
+ }
+ }
+ }
+
+ t.removeSplits();
+
+ kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"]);
+ if(postDate->date().isValid()) {
+ t.setPostDate(postDate->date());
+ }
+
+ // memo and number field are special: if we have multiple transactions selected
+ // and the edit field is empty, we treat it as "not modified".
+ // FIXME a better approach would be to have a 'dirty' flag with the widgets
+ // which identifies if the originally loaded value has been modified
+ // by the user
+ KTextEdit* memo = dynamic_cast<KTextEdit*>(m_editWidgets["memo"]);
+ if(memo) {
+ if(!isMultiSelection() || (isMultiSelection() && !memo->text().isEmpty() ) )
+ s0.setMemo(memo->text());
+ }
+
+ MyMoneySplit assetAccountSplit;
+ QValueList<MyMoneySplit> feeSplits;
+ QValueList<MyMoneySplit> interestSplits;
+ MyMoneySecurity security, currency;
+ MyMoneySplit::investTransactionTypeE transactionType;
+
+ // extract the splits from the original transaction
+ dissectTransaction(torig, sorig,
+ assetAccountSplit,
+ feeSplits,
+ interestSplits,
+ security,
+ currency,
+ transactionType);
+
+ // check if the trading currency is the same if the security has changed
+ // in case it differs, check that we have a price (request from user)
+ // and convert all splits
+ // TODO
+
+ // do the conversions here
+ // TODO
+
+ // keep the current activity object and create a new one
+ // that can be destroyed later on
+ Activity* activity = d->m_activity;
+ d->m_activity = 0; // make sure we create a new one
+ activityFactory(activity->type());
+
+ // if the activity is not set in the combo widget, we keep
+ // the one which is used in the original transaction
+ KMyMoneyActivityCombo* activityCombo = dynamic_cast<KMyMoneyActivityCombo*>(haveWidget("activity"));
+ if(activityCombo->activity() == MyMoneySplit::UnknownTransactionType) {
+ activityFactory(transactionType);
+ }
+
+ // if we mark the split reconciled here, we'll use today's date if no reconciliation date is given
+ KMyMoneyReconcileCombo* status = dynamic_cast<KMyMoneyReconcileCombo*>(m_editWidgets["status"]);
+ if(status->state() != MyMoneySplit::Unknown)
+ s0.setReconcileFlag(status->state());
+
+ if(s0.reconcileFlag() == MyMoneySplit::Reconciled && !s0.reconcileDate().isValid())
+ s0.setReconcileDate(QDate::currentDate());
+
+ // call the creation logic for the current selected activity
+ bool rc = d->m_activity->createTransaction(t, s0, assetAccountSplit, feeSplits, m_feeSplits, interestSplits, m_interestSplits, security, currency);
+
+ // now switch back to the original activity
+ delete d->m_activity;
+ d->m_activity = activity;
+
+ // add the splits to the transaction
+ if(rc) {
+ if(!assetAccountSplit.accountId().isEmpty()) {
+ assetAccountSplit.clearId();
+ t.addSplit(assetAccountSplit);
+ }
+
+ t.addSplit(s0);
+
+ QValueList<MyMoneySplit>::iterator it_s;
+ for(it_s = feeSplits.begin(); it_s != feeSplits.end(); ++it_s) {
+ (*it_s).clearId();
+ t.addSplit(*it_s);
+ }
+
+ for(it_s = interestSplits.begin(); it_s != interestSplits.end(); ++it_s) {
+ (*it_s).clearId();
+ t.addSplit(*it_s);
+ }
+ }
+
+ // adjust the value to the smallestAccountFraction found
+ // for the commodity of the transaction.
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ MyMoneySplit s = (*it_s);
+ s.setValue((*it_s).value().convert(currency.smallestAccountFraction()));
+ t.modifySplit(s);
+ }
+
+ return rc;
+}
+
+void InvestTransactionEditor::updatePriceMode(const MyMoneySplit& split)
+{
+ QLabel* label = dynamic_cast<QLabel*>(haveWidget("price-label"));
+ if(label) {
+ kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
+ kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
+ MyMoneyMoney price;
+ if(!split.id().isEmpty())
+ price = split.price().reduce();
+ else
+ price = priceEdit->value().abs();
+
+ if(priceMode() == PricePerTransaction && label->text() != i18n("Price")) {
+ label->setText(i18n("Price"));
+ if(!sharesEdit->value().isZero())
+ priceEdit->setValue(sharesEdit->value().abs() * price);
+
+ } else if(priceMode() == PricePerShare && label->text() == i18n("Price")) {
+ label->setText(i18n("Price/Share"));
+ if(!sharesEdit->value().isZero())
+ priceEdit->setValue(price / sharesEdit->value().abs());
+
+ } else if(priceMode() == PricePerTransaction) {
+ priceEdit->setValue(sharesEdit->value().abs() * price);
+
+ } else
+ priceEdit->setValue(price);
+ }
+}
+
+void InvestTransactionEditor::setupFinalWidgets(void)
+{
+ addFinalWidget(haveWidget("memo"));
+}
+
+#include "investtransactioneditor.moc"
+
diff --git a/kmymoney2/dialogs/investtransactioneditor.h b/kmymoney2/dialogs/investtransactioneditor.h
new file mode 100644
index 0000000..4d56697
--- /dev/null
+++ b/kmymoney2/dialogs/investtransactioneditor.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+ investtransactioneditor.h
+ ----------
+ begin : Fri Dec 15 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef INVESTMENTTRANSACTIONEDITOR_H
+#define INVESTMENTTRANSACTIONEDITOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transactioneditor.h>
+
+class InvestTransactionEditor : public TransactionEditor
+{
+ friend class InvestTransactionEditorPrivate;
+
+ Q_OBJECT
+public:
+ typedef enum {
+ PricePerShare = 1,
+ PricePerTransaction
+ } priceModeE;
+
+ InvestTransactionEditor();
+ InvestTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::InvestTransaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate);
+ virtual ~InvestTransactionEditor();
+
+ /**
+ * This method returns information about the completeness of the data
+ * entered. This can be used to control the availability of the
+ * 'Enter transaction' action.
+ *
+ * @retval true if entering the transaction into the engine
+ * @retval false if not enough information is present to enter the
+ * transaction into the engine
+ *
+ * @param reason will be filled with a string about the reason why the
+ * completeness is not reached. Empty if the return value
+ * is @c true.
+ *
+ * @sa transactionDataSufficient()
+ */
+ virtual bool isComplete(QString& reason) const;
+
+ virtual QWidget* firstWidget(void) const;
+
+ virtual bool fixTransactionCommodity(const MyMoneyAccount& /* account */) { return true; }
+
+ void totalAmount(MyMoneyMoney& amount) const;
+
+ static void dissectTransaction(const MyMoneyTransaction& transaction, const MyMoneySplit& split, MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& feeSplits, QValueList<MyMoneySplit>& interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency, MyMoneySplit::investTransactionTypeE& transactionType);
+
+ bool setupPrice(const MyMoneyTransaction& t, MyMoneySplit& split);
+
+ /**
+ * This method creates a transaction based on the contents of the current widgets,
+ * the splits in m_split in single selection mode or an existing transaction/split
+ * and the contents of the widgets in multi selection mode.
+ *
+ * The split referencing the current account is returned as the first split in the
+ * transaction's split list.
+ *
+ * @param t reference to created transaction
+ * @param torig the original transaction
+ * @param sorig the original split
+ *
+ * @param skipPriceDialog if @p true the user will not be requested for price information
+ * (defaults to @p false)
+ *
+ * @return @p false if aborted by user, @p true otherwise
+ *
+ * @note Usually not used directly. If unsure, use enterTransactions() instead.
+ */
+ bool createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog = false);
+
+ priceModeE priceMode(void) const;
+
+ const MyMoneySecurity& security(void) const { return m_security; }
+
+protected slots:
+ void slotCreateSecurity(const QString& name, QString& id);
+ void slotCreateFeeCategory(const QString& name, QString& id);
+ void slotCreateInterestCategory(const QString& name, QString& id);
+
+ int slotEditInterestSplits(void);
+ int slotEditFeeSplits(void);
+ void slotReloadEditWidgets(void);
+
+ void slotUpdateActivity(MyMoneySplit::investTransactionTypeE);
+ void slotUpdateSecurity(const QString& stockId);
+ void slotUpdateInterestCategory(const QString& id);
+ void slotUpdateInterestVisibility(const QString&);
+ void slotUpdateFeeCategory(const QString& id);
+ void slotUpdateFeeVisibility(const QString&);
+ void slotUpdateTotalAmount(void);
+
+protected:
+ /**
+ * This method creates all necessary widgets for this transaction editor.
+ * All signals will be connected to the relevant slots.
+ */
+ void createEditWidgets(void);
+
+ /**
+ * This method (re-)loads the widgets with the transaction information
+ * contained in @a m_transaction and @a m_split.
+ *
+ * @param action preset the edit wigdets for @a action if no transaction
+ * is present
+ */
+ void loadEditWidgets(KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone);
+
+ void activityFactory(MyMoneySplit::investTransactionTypeE type);
+
+ MyMoneyMoney subtotal(const QValueList<MyMoneySplit>& splits) const;
+
+ /**
+ * This method creates a transaction to be used for the split fee/interest editor.
+ * It has a reference to a phony account and the splits contained in @a splits .
+ */
+ bool createPseudoTransaction(MyMoneyTransaction& t, const QValueList<MyMoneySplit>& splits);
+
+ /**
+ * Convenience method used by slotEditInterestSplits() and slotEditFeeSplits().
+ *
+ * @param categoryWidgetName name of the category widget
+ * @param amountWidgetName name of the amount widget
+ * @param splits the splits that make up the transaction to be edited
+ * @param isIncome @c false for fees, @c true for interest
+ * @param slotEditSplits name of the slot to be connected to the focusIn signal of the
+ * category widget named @p categoryWidgetName in case of multiple splits
+ * in @p splits .
+ */
+ int editSplits(const QString& categoryWidgetName, const QString& amountWidgetName, QValueList<MyMoneySplit>& splits, bool isIncome, const char* slotEditSplits);
+
+ void updatePriceMode(const MyMoneySplit& split = MyMoneySplit());
+
+ void setupFinalWidgets(void);
+
+private:
+ MyMoneySplit m_assetAccountSplit;
+ QValueList<MyMoneySplit> m_interestSplits;
+ QValueList<MyMoneySplit> m_feeSplits;
+ MyMoneySecurity m_security;
+ MyMoneySecurity m_currency;
+ MyMoneySplit::investTransactionTypeE m_transactionType;
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kaccountselectdlg.cpp b/kmymoney2/dialogs/kaccountselectdlg.cpp
new file mode 100644
index 0000000..0b172f0
--- /dev/null
+++ b/kmymoney2/dialogs/kaccountselectdlg.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+ kaccountselectdlg.cpp - description
+ -------------------
+ begin : Mon Feb 10 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kactivelabel.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kaccountselectdlg.h"
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneycategory.h>
+#include "../widgets/kmymoneyaccountselector.h"
+
+#include <../kmymoney2.h>
+
+KAccountSelectDlg::KAccountSelectDlg(const KMyMoneyUtils::categoryTypeE accountType, const QString& purpose, QWidget *parent, const char *name )
+ : KAccountSelectDlgDecl(parent, name),
+ m_purpose(purpose),
+ m_accountType(accountType),
+ m_aborted(false)
+{
+ // Hide the abort button. It needs to be shown on request by the caller
+ // using showAbortButton()
+ m_kButtonAbort->hide();
+
+ slotReloadWidget();
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem skipButtonItem( i18n( "&Skip" ),
+ QIconSet(il->loadIcon("redo", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Skip this transaction"),
+ i18n("Use this to skip importing this transaction and proceed with the next one."));
+ m_qbuttonCancel->setGuiItem(skipButtonItem);
+
+ KGuiItem createButtenItem( i18n( "&Create..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new account/category"),
+ i18n("Use this to add a new account/category to the file"));
+ m_createButton->setGuiItem(createButtenItem);
+ m_qbuttonOk->setGuiItem(KStdGuiItem::ok());
+
+ KGuiItem abortButtenItem( i18n("&Abort" ),
+ QIconSet(il->loadIcon("stop", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Abort the import operation and dismiss all changes"),
+ i18n("Use this to abort the import. Your financial data will be in the state before you started the QIF import."));
+ m_kButtonAbort->setGuiItem(abortButtenItem);
+
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadWidget()));
+
+ connect(m_createButton, SIGNAL(clicked()), this, SLOT(slotCreateAccount()));
+ connect(m_qbuttonOk, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_qbuttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_kButtonAbort, SIGNAL(clicked()), this, SLOT(abort()));
+}
+
+KAccountSelectDlg::~KAccountSelectDlg()
+{
+}
+
+void KAccountSelectDlg::slotReloadWidget(void)
+{
+ AccountSet set;
+ if(m_accountType & KMyMoneyUtils::asset)
+ set.addAccountGroup(MyMoneyAccount::Asset);
+ if(m_accountType & KMyMoneyUtils::liability)
+ set.addAccountGroup(MyMoneyAccount::Liability);
+ if(m_accountType & KMyMoneyUtils::income)
+ set.addAccountGroup(MyMoneyAccount::Income);
+ if(m_accountType & KMyMoneyUtils::expense)
+ set.addAccountGroup(MyMoneyAccount::Expense);
+ if(m_accountType & KMyMoneyUtils::equity)
+ set.addAccountGroup(MyMoneyAccount::Equity);
+
+ set.load(m_accountSelector->selector());
+}
+
+void KAccountSelectDlg::setDescription(const QString& msg)
+{
+ m_descLabel->setText(msg);
+}
+
+void KAccountSelectDlg::setHeader(const QString& msg)
+{
+ m_headerLabel->setText(msg);
+}
+
+void KAccountSelectDlg::setAccount(const MyMoneyAccount& account, const QString& id)
+{
+ m_account = account;
+ m_accountSelector->setSelectedItem(id);
+}
+
+void KAccountSelectDlg::slotCreateInstitution(void)
+{
+ kmymoney2->slotInstitutionNew();
+}
+
+void KAccountSelectDlg::slotCreateAccount(void)
+{
+ if(!(m_accountType & (KMyMoneyUtils::expense | KMyMoneyUtils::income))) {
+ kmymoney2->slotAccountNew(m_account);
+ if(!m_account.id().isEmpty()) {
+ slotReloadWidget();
+ m_accountSelector->setSelectedItem(m_account.id());
+ accept();
+ }
+ } else {
+ if(m_account.accountType() == MyMoneyAccount::Expense)
+ kmymoney2->createCategory(m_account, MyMoneyFile::instance()->expense());
+ else
+ kmymoney2->createCategory(m_account, MyMoneyFile::instance()->income());
+ if(!m_account.id().isEmpty()) {
+ slotReloadWidget();
+ m_accountSelector->setSelectedItem(m_account.id());
+ accept();
+ }
+ }
+}
+
+void KAccountSelectDlg::abort(void)
+{
+ m_aborted = true;
+ reject();
+}
+
+void KAccountSelectDlg::setMode(const int mode)
+{
+ m_mode = mode ? 1 : 0;
+}
+
+void KAccountSelectDlg::showAbortButton(const bool visible)
+{
+ m_kButtonAbort->setShown(visible);
+}
+
+int KAccountSelectDlg::exec(void)
+{
+ int rc = Rejected;
+
+ if(m_mode == 1) {
+ slotCreateAccount();
+ rc = result();
+ }
+ if(rc != Accepted) {
+ m_createButton->setFocus();
+ rc = KAccountSelectDlgDecl::exec();
+ }
+ return rc;
+}
+
+const QString& KAccountSelectDlg::selectedAccount(void) const
+{
+ return m_accountSelector->selectedItem();
+}
+
+#include "kaccountselectdlg.moc"
diff --git a/kmymoney2/dialogs/kaccountselectdlg.h b/kmymoney2/dialogs/kaccountselectdlg.h
new file mode 100644
index 0000000..271cd0f
--- /dev/null
+++ b/kmymoney2/dialogs/kaccountselectdlg.h
@@ -0,0 +1,155 @@
+/***************************************************************************
+ kaccountselectdlg.h - description
+ -------------------
+ begin : Mon Feb 10 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KACCOUNTSELECTDLG_H
+#define KACCOUNTSELECTDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneycombo.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyutils.h>
+#include "../dialogs/kaccountselectdlgdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KAccountSelectDlg : public KAccountSelectDlgDecl
+{
+ Q_OBJECT
+public:
+ KAccountSelectDlg(const KMyMoneyUtils::categoryTypeE type, const QString& purpose = "General", QWidget *parent=0, const char *name=0);
+ ~KAccountSelectDlg();
+
+ /**
+ * This method is used to setup the descriptive text in the account
+ * selection dialog box. The @p msg should contain a descriptive
+ * text about the purpose of the dialog and it's options.
+ *
+ * @param msg const reference to QString object containing the text.
+ */
+ void setDescription(const QString& msg);
+
+ /**
+ * This method is used to setup the buddy text of the account
+ * selection box. the @p msg should contain a short text
+ * which is placed above the selection box with the account
+ * names.
+ *
+ * @param msg const reference to QString object containing the text.
+ */
+ void setHeader(const QString& msg);
+
+ /**
+ * This method is used to pass information to the account selection
+ * dialog which will be used as initial selection in the account
+ * selection combo box and during account creation.
+ *
+ * @param account MyMoneyAccount filled with the relevant and available information
+ * @param id account id to be used.
+ */
+ void setAccount(const MyMoneyAccount& account, const QString& id);
+
+ /**
+ * This method returns the name of the selected account in the combo box.
+ *
+ * @return QString containing the id of the selected account
+ */
+ const QString& selectedAccount(void) const;
+
+ /**
+ * This method is used to set the mode of the dialog. Two modes
+ * are supplied: a) select or create and b) create only.
+ * If @p mode is 0, select or create is selected, otherwise create only
+ * is selected.
+ *
+ * @param mode selected mode
+ */
+ void setMode(const int mode);
+
+ /**
+ * This method allows to control the visibilty of the abort button
+ * in this dialog according to the the parameter @p visible.
+ *
+ * @param visible @p true shows the abort button, @p false hides it.
+ */
+ void showAbortButton(const bool visible);
+
+ /**
+ * This method is used to determine if the user pressed the 'Skip' or
+ * the 'Abort' button. The return value is valid only, if the exec()
+ * function of the dialog returns false.
+ *
+ * @retval false Dialog was left using the 'Skip' button
+ * @retval true Dialog was left using the 'Abort' button
+ */
+ bool aborted(void) const { return m_aborted; };
+
+public slots:
+ /**
+ * Reimplemented from QDialog
+ */
+ int exec();
+
+protected slots:
+ /**
+ * This slot is used to fire up the new account wizard and preset it
+ * with the values found in m_account. If an account was created using
+ * the wizard, this will be the selected account.
+ */
+ void slotCreateAccount(void);
+
+ /**
+ * This slot is used to fire up the new institution dialog
+ */
+ void slotCreateInstitution(void);
+
+ /**
+ * This slot is used to react on the abort button
+ */
+ void abort(void);
+
+ /**
+ * This is the slot which will be called if the engine data is changed.
+ */
+ void slotReloadWidget(void);
+
+private:
+ QString m_purpose;
+ MyMoneyAccount m_account;
+ int m_mode; // 0 - select or create, 1 - create only
+ KMyMoneyUtils::categoryTypeE m_accountType;
+ bool m_aborted;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kaccountselectdlgdecl.ui b/kmymoney2/dialogs/kaccountselectdlgdecl.ui
new file mode 100644
index 0000000..1908339
--- /dev/null
+++ b/kmymoney2/dialogs/kaccountselectdlgdecl.ui
@@ -0,0 +1,215 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAccountSelectDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KAccountSelectDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>651</width>
+ <height>434</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Account selection</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>m_qifEntry</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ <property name="undoDepth">
+ <number>0</number>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>m_createButton</cstring>
+ </property>
+ <property name="text">
+ <string>Create</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_accountSelector</cstring>
+ </property>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>110</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KActiveLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_descLabel</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_headerLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Account to import to</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_kButtonAbort</cstring>
+ </property>
+ <property name="text">
+ <string>Abort</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>160</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Skip</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kbackupdlg.cpp b/kmymoney2/dialogs/kbackupdlg.cpp
new file mode 100644
index 0000000..d98aeaf
--- /dev/null
+++ b/kmymoney2/dialogs/kbackupdlg.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+ kbackupdialog.cpp - description
+ -------------------
+ begin : Mon Jun 4 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#if QT_VERSION > 300
+#include <kstandarddirs.h>
+#else
+#include <kstddirs.h>
+#endif
+
+#include <kconfig.h>
+#include <kdirselectdialog.h>
+#include <kglobalsettings.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kbackupdlg.h"
+
+KBackupDlg::KBackupDlg( QWidget* parent, const char* name/*, bool modal*/)
+ : kbackupdlgdecl( parent, name , true)
+{
+ readConfig();
+
+ // add icons to buttons
+ KIconLoader *il = KGlobal::iconLoader();
+ btnOK->setGuiItem(KStdGuiItem::ok());
+ btnCancel->setGuiItem(KStdGuiItem::cancel());
+
+ KGuiItem chooseButtenItem( i18n("C&hoose..."),
+ QIconSet(il->loadIcon("folder", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Select mount point"),
+ i18n("Use this to browse to the mount point."));
+ chooseButton->setGuiItem(chooseButtenItem);
+
+ connect(chooseButton, SIGNAL(clicked()), this, SLOT(chooseButtonClicked()));
+ connect(btnOK,SIGNAL(clicked()),this,SLOT(accept()));
+ connect(btnCancel,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+KBackupDlg::~KBackupDlg()
+{
+ writeConfig();
+}
+
+void KBackupDlg::chooseButtonClicked()
+{
+ KURL newDir = KDirSelectDialog::selectDirectory(KGlobalSettings::documentPath());
+ if (newDir.hasPath())
+ txtMountPoint->setText(newDir.path());
+}
+
+void KBackupDlg::readConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ mountCheckBox->setChecked(config->readBoolEntry("KBackupDlg_mountDevice", false));
+ txtMountPoint->setText(config->readEntry("KBackupDlg_BackupMountPoint", "/mnt/floppy"));
+}
+
+void KBackupDlg::writeConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("KBackupDlg_mountDevice", mountCheckBox->isChecked());
+ config->writeEntry("KBackupDlg_BackupMountPoint", txtMountPoint->text());
+ config->sync();
+}
+
+#include "kbackupdlg.moc"
diff --git a/kmymoney2/dialogs/kbackupdlg.h b/kmymoney2/dialogs/kbackupdlg.h
new file mode 100644
index 0000000..b275606
--- /dev/null
+++ b/kmymoney2/dialogs/kbackupdlg.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ kbackupdialog.h - description
+ -------------------
+ begin : Mon Jun 4 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBACKUPDIALOG_H
+#define KBACKUPDIALOG_H
+
+#include <qwidget.h>
+#include "../dialogs/kbackupdlgdecl.h"
+
+/**
+ *@author Michael Edwardes
+ */
+
+class KBackupDlg : public kbackupdlgdecl {
+ Q_OBJECT
+private:
+ void readConfig(void);
+ void writeConfig(void);
+
+protected slots:
+ void chooseButtonClicked();
+
+public:
+ KBackupDlg( QWidget* parent, const char* name/*, bool modal*/);
+ ~KBackupDlg();
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kbackupdlgdecl.ui b/kmymoney2/dialogs/kbackupdlgdecl.ui
new file mode 100644
index 0000000..ff9795f
--- /dev/null
+++ b/kmymoney2/dialogs/kbackupdlgdecl.ui
@@ -0,0 +1,210 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kbackupdlgdecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kbackupdlgdecl</cstring>
+ </property>
+ <property name="caption">
+ <string>Backup</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Use this dialog to backup your data.
+
+Please make sure you have a disk inserted and that the drive is ready. Then choose the mount point from either the Choose button or by entering the path in the available box.
+
+Click OK to perform the backup. If your system does not use an automounter, make sure you mark the checkbox below to "mount this directory before backing up."</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Device options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout42</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lblMountPoint</cstring>
+ </property>
+ <property name="text">
+ <string>Mount Point:</string>
+ <comment>This is the mount point</comment>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>txtMountPoint</cstring>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>chooseButton</cstring>
+ </property>
+ <property name="text">
+ <string>Choose...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>mountCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Mount this directory before backing up.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer17</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout44</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>455</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnOK</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kbalancechartdlg.cpp b/kmymoney2/dialogs/kbalancechartdlg.cpp
new file mode 100644
index 0000000..05eccf3
--- /dev/null
+++ b/kmymoney2/dialogs/kbalancechartdlg.cpp
@@ -0,0 +1,227 @@
+/***************************************************************************
+ kbalancechartdlg - description
+ -------------------
+ begin : Mon Nov 26 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qframe.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kbalancechartdlg.h"
+
+#include <kmymoney/mymoneyreport.h>
+#include "../reports/kreportchartview.h"
+#include "../reports/pivottable.h"
+
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+
+// in KOffice version < 1.5 KDCHART_PROPSET_NORMAL_DATA was a static const
+// but in 1.5 this has been changed into a #define'd value. So we have to
+// make sure, we use the right one.
+#ifndef KDCHART_PROPSET_NORMAL_DATA
+#define KMM_KDCHART_PROPSET_NORMAL_DATA KDChartParams::KDCHART_PROPSET_NORMAL_DATA
+#else
+#define KMM_KDCHART_PROPSET_NORMAL_DATA KDCHART_PROPSET_NORMAL_DATA
+#endif
+
+KBalanceChartDlg::KBalanceChartDlg(const MyMoneyAccount& account, QWidget* parent, const char* name) :
+ KDialog(parent, name)
+{
+#ifdef HAVE_KDCHART
+ setCaption(i18n("Balance of %1").arg(account.name()));
+ setSizeGripEnabled( TRUE );
+ setModal( TRUE );
+
+ QVBoxLayout* KBalanceChartDlgLayout = new QVBoxLayout( this, 11, 6, "KBalanceChartDlgLayout");
+
+ MyMoneyReport reportCfg = MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::userDefined, // overridden by the setDateFilter() call below
+ MyMoneyReport::eDetailTotal,
+ i18n("%1 Balance History").arg(account.name()),
+ i18n("Generated Report")
+ );
+ reportCfg.setChartByDefault(true);
+ reportCfg.setChartGridLines(false);
+ reportCfg.setChartDataLabels(false);
+ reportCfg.setChartType(MyMoneyReport::eChartLine);
+ reportCfg.setIncludingSchedules( true );
+ if(account.accountType() == MyMoneyAccount::Investment) {
+ QStringList::const_iterator it_a;
+ for(it_a = account.accountList().begin(); it_a != account.accountList().end(); ++it_a)
+ reportCfg.addAccount(*it_a);
+ } else
+ reportCfg.addAccount(account.id());
+ reportCfg.setColumnsAreDays( true );
+ reportCfg.setConvertCurrency( false );
+ reportCfg.setDateFilter(QDate::currentDate().addDays(-90),QDate::currentDate().addDays(+90));
+
+ reports::PivotTable table(reportCfg);
+
+ reports::KReportChartView* chartWidget = new reports::KReportChartView(this, 0);
+
+ table.drawChart(*chartWidget);
+
+ chartWidget->params()->setLineMarker(false);
+ chartWidget->params()->setLegendPosition(KDChartParams::NoLegend);
+ chartWidget->params()->setLineWidth(2);
+ chartWidget->params()->setDataColor(0, KGlobalSettings::textColor());
+
+ // draw future values in a different line style
+ KDChartPropertySet propSetFutureValue("future value", KMM_KDCHART_PROPSET_NORMAL_DATA);
+ propSetFutureValue.setLineStyle(KDChartPropertySet::OwnID, Qt::DotLine);
+ int m_idPropFutureValue = chartWidget->params()->registerProperties(propSetFutureValue);
+
+ KDChartPropertySet propSetLastValue("last value", m_idPropFutureValue);
+ propSetLastValue.setExtraLinesAlign(KDChartPropertySet::OwnID, Qt::AlignLeft | Qt::AlignBottom);
+ propSetLastValue.setExtraLinesWidth(KDChartPropertySet::OwnID, -4);
+ propSetLastValue.setExtraLinesColor(KDChartPropertySet::OwnID, KMyMoneyGlobalSettings::listGridColor());
+
+ int m_idPropLastValue = chartWidget->params()->registerProperties(propSetLastValue);
+
+ KDChartPropertySet propSetMinBalance("min balance", m_idPropFutureValue);
+ propSetMinBalance.setLineStyle(KDChartPropertySet::OwnID, Qt::NoPen);
+ propSetMinBalance.setExtraLinesAlign(KDChartPropertySet::OwnID, Qt::AlignLeft | Qt::AlignRight);
+ int m_idPropMinBalance = chartWidget->params()->registerProperties(propSetMinBalance);
+
+ KDChartPropertySet propSetMaxCredit("max credit", m_idPropMinBalance);
+ propSetMaxCredit.setExtraLinesColor(KDChartPropertySet::OwnID, KMyMoneyGlobalSettings::listNegativeValueColor());
+ propSetMaxCredit.setExtraLinesStyle(KDChartPropertySet::OwnID, Qt::DotLine);
+ int m_idPropMaxCredit = chartWidget->params()->registerProperties(propSetMaxCredit);
+
+ KBalanceChartDlgLayout->addWidget(chartWidget, 10);
+
+
+ // add another row for markers if required or remove it if not necessary
+ // see http://www.klaralvdalens-datakonsult.se/kdchart/ProgrammersManual/KDChart.pdf
+ // Chapter 6, "Adding separate Lines/Markers".
+
+ bool needRow = false;
+ bool haveMinBalance = false;
+ bool haveMaxCredit = false;
+ MyMoneyMoney minBalance, maxCredit;
+ MyMoneyMoney factor(1,1);
+ if(account.accountGroup() == MyMoneyAccount::Asset)
+ factor = -factor;
+
+ if(account.value("maxCreditEarly").length() > 0) {
+ needRow = true;
+ haveMaxCredit = true;
+ maxCredit = MyMoneyMoney(account.value("maxCreditEarly")) * factor;
+ }
+ if(account.value("maxCreditAbsolute").length() > 0) {
+ needRow = true;
+ haveMaxCredit = true;
+ maxCredit = MyMoneyMoney(account.value("maxCreditAbsolute")) * factor;
+ }
+
+ if(account.value("minBalanceEarly").length() > 0) {
+ needRow = true;
+ haveMinBalance = true;
+ minBalance = MyMoneyMoney(account.value("minBalanceEarly"));
+ }
+ if(account.value("minBalanceAbsolute").length() > 0) {
+ needRow = true;
+ haveMinBalance = true;
+ minBalance = MyMoneyMoney(account.value("minBalanceAbsolute"));
+ }
+
+ KDChartTableDataBase* data = chartWidget->data();
+ if(!needRow && data->usedRows() == 2) {
+ data->expand( data->usedRows()-1, data->usedCols() );
+ } else if(needRow && data->usedRows() == 1) {
+ data->expand( data->usedRows()+1, data->usedCols() );
+ }
+
+ if(needRow) {
+ if(haveMinBalance) {
+ data->setCell(1, 0, minBalance.toDouble());
+ chartWidget->setProperty(1, 0, m_idPropMinBalance);
+ }
+ if(haveMaxCredit) {
+ data->setCell(1, 1, maxCredit.toDouble());
+ chartWidget->setProperty(1, 1, m_idPropMaxCredit);
+ }
+ }
+
+ for(int iCell = 90; iCell < 180; ++iCell) {
+ chartWidget->setProperty(0, iCell, m_idPropFutureValue);
+ }
+ chartWidget->setProperty(0, 90, m_idPropLastValue);
+
+
+
+ QFrame* line1 = new QFrame( this, "line1" );
+ line1->setFrameShape( QFrame::HLine );
+ line1->setFrameShadow( QFrame::Sunken );
+ line1->setFrameShape( QFrame::HLine );
+
+ KBalanceChartDlgLayout->addWidget(line1);
+ QHBoxLayout* Layout1 = new QHBoxLayout( KBalanceChartDlgLayout, 6, "Layout1");
+#if 0
+ KPushButton* buttonHelp = new KPushButton( this, "buttonHelp" );
+ buttonHelp->setAutoDefault( TRUE );
+ buttonHelp->setText(i18n("&Help"));
+ Layout1->addWidget( buttonHelp );
+#endif
+
+ QSpacerItem* Horizontal_Spacing2 = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ Layout1->addItem( Horizontal_Spacing2 );
+
+#if 0
+ KPushButton* buttonOk = new KPushButton( this, "buttonOk" );
+ buttonOk->setAutoDefault( TRUE );
+ buttonOk->setDefault( TRUE );
+ buttonOk->setText(i18n("&OK"));
+ Layout1->addWidget( buttonOk );
+#endif
+ KPushButton* buttonClose = new KPushButton( this, "buttonClose" );
+ buttonClose->setEnabled( TRUE );
+ buttonClose->setAutoDefault( TRUE );
+ buttonClose->setGuiItem(KStdGuiItem::Close);
+ Layout1->addWidget( buttonClose );
+
+ // connect( buttonOk, SIGNAL( clicked() ), this, SLOT( accept() ) );
+ connect( buttonClose, SIGNAL( clicked() ), this, SLOT( accept() ) );
+
+ resize( QSize(700, 500).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+#endif
+}
+
+
+KBalanceChartDlg::~KBalanceChartDlg()
+{
+}
+
+#include "kbalancechartdlg.moc"
+
diff --git a/kmymoney2/dialogs/kbalancechartdlg.h b/kmymoney2/dialogs/kbalancechartdlg.h
new file mode 100644
index 0000000..8fe2502
--- /dev/null
+++ b/kmymoney2/dialogs/kbalancechartdlg.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ kbalancechartdlg - description
+ -------------------
+ begin : Mon Nov 26 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBALANCECHARTDLG_H
+#define KBALANCECHARTDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdialog.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class MyMoneyAccount;
+
+/**
+ * @author Thomas Baumgart <ipwizard@users.sourceforge.net>
+ */
+class KBalanceChartDlg : public KDialog
+{
+ Q_OBJECT
+ public:
+ KBalanceChartDlg(const MyMoneyAccount& account, QWidget* parent = 0, const char* name = 0);
+ ~KBalanceChartDlg();
+
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kbalancewarning.cpp b/kmymoney2/dialogs/kbalancewarning.cpp
new file mode 100644
index 0000000..16f3dc0
--- /dev/null
+++ b/kmymoney2/dialogs/kbalancewarning.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+ kbalancewarning.cpp
+ -------------------
+ begin : Mon Feb 9 2009
+ copyright : (C) 2009 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyaccount.h"
+#include "kbalancewarning.h"
+
+class KBalanceWarning::Private
+{
+public:
+ QString dontShowAgain() const { return "BalanceWarning"; }
+ QMap<QString, bool> m_deselectedAccounts;
+};
+
+KBalanceWarning::KBalanceWarning(QObject* parent, const char* name) :
+ QObject(parent, name),
+ d(new Private)
+{
+ KMessageBox::enableMessage(d->dontShowAgain());
+}
+
+KBalanceWarning::~KBalanceWarning()
+{
+ delete d;
+}
+
+void KBalanceWarning::slotShowMessage(QWidget* parent, const MyMoneyAccount& account, const QString& msg)
+{
+ if(d->m_deselectedAccounts.find(account.id()) == d->m_deselectedAccounts.end()) {
+ KMessageBox::information(parent, msg, QString::null, d->dontShowAgain());
+ if(!KMessageBox::shouldBeShownContinue(d->dontShowAgain())) {
+ d->m_deselectedAccounts[account.id()] = true;
+ KMessageBox::enableMessage(d->dontShowAgain());
+ }
+ }
+}
+
+
+#include "kbalancewarning.moc"
diff --git a/kmymoney2/dialogs/kbalancewarning.h b/kmymoney2/dialogs/kbalancewarning.h
new file mode 100644
index 0000000..2e3c4d4
--- /dev/null
+++ b/kmymoney2/dialogs/kbalancewarning.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ kbalancewarning.h
+ -------------------
+ begin : Mon Feb 9 2009
+ copyright : (C) 2009 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBALANCEWARNING_H
+#define KBALANCEWARNING_H
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+class QString;
+class QWidget;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class MyMoneyAccount;
+
+class KBalanceWarning : public QObject
+{
+ Q_OBJECT
+public:
+ KBalanceWarning(QObject* parent, const char* name = 0);
+ virtual ~KBalanceWarning();
+
+public slots:
+ void slotShowMessage(QWidget* parent, const MyMoneyAccount& account, const QString& msg);
+
+private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kcategoryreassigndlg.cpp b/kmymoney2/dialogs/kcategoryreassigndlg.cpp
new file mode 100644
index 0000000..f457134
--- /dev/null
+++ b/kmymoney2/dialogs/kcategoryreassigndlg.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+ kcategoryreassigndlg.cpp
+ -------------------
+ copyright : (C) 2007 by Thomas Baumgart
+ author : Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdialog.h>
+#include <klocale.h>
+#include <kstdguiitem.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kcategoryreassigndlg.h"
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kguiutils.h>
+
+KCategoryReassignDlg::KCategoryReassignDlg( QWidget* parent, const char* name) :
+ KCategoryReassignDlgDecl( parent, name)
+{
+ buttonOk->setGuiItem(KStdGuiItem::ok());
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+ kMandatoryFieldGroup* mandatory = new kMandatoryFieldGroup(this);
+ mandatory->add(m_category);
+ mandatory->setOkButton(buttonOk);
+}
+
+KCategoryReassignDlg::~KCategoryReassignDlg()
+{
+}
+
+QString KCategoryReassignDlg::show(const MyMoneyAccount& category)
+{
+ if (category.id().isEmpty())
+ return QString(); // no payee available? nothing can be selected...
+
+ AccountSet set;
+ set.addAccountGroup(MyMoneyAccount::Income);
+ set.addAccountGroup(MyMoneyAccount::Expense);
+ set.load(m_category->selector());
+
+ // remove the category we are about to delete
+ m_category->selector()->removeItem(category.id());
+
+ // make sure the available categories have the same currency
+ QStringList list;
+ QStringList::const_iterator it_a;
+ m_category->selector()->itemList(list);
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.currencyId() != category.currencyId())
+ m_category->selector()->removeItem(*it_a);
+ }
+
+ // reload the list
+ m_category->selector()->itemList(list);
+
+ // if there is no category for reassignment left, we bail out
+ if(list.isEmpty()) {
+ KMessageBox::sorry(this, QString("<qt>")+i18n("At least one transaction/schedule still references the category <b>%1</b>. However, at least one category with the same currency must exist so that the transactions/schedules can be reassigned.").arg(category.name())+QString("</qt>"));
+ return QString();
+ }
+
+ // execute dialog and if aborted, return empty string
+ if (this->exec() == QDialog::Rejected)
+ return QString();
+
+ // otherwise return index of selected payee
+ return m_category->selectedItem();
+}
+
+
+void KCategoryReassignDlg::accept(void)
+{
+ // force update of payeeCombo
+ buttonOk->setFocus();
+
+ if(m_category->selectedItem().isEmpty()) {
+ KMessageBox::information(this, i18n("This dialog does not allow to create new categories. Please pick a category from the list."), i18n("Category creation"));
+ } else {
+ KCategoryReassignDlgDecl::accept();
+ }
+}
+
+#include "kcategoryreassigndlg.moc"
diff --git a/kmymoney2/dialogs/kcategoryreassigndlg.h b/kmymoney2/dialogs/kcategoryreassigndlg.h
new file mode 100644
index 0000000..ce756ee
--- /dev/null
+++ b/kmymoney2/dialogs/kcategoryreassigndlg.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ kcategoryreassigndlg.cpp
+ -------------------
+ copyright : (C) 2007 by Thomas Baumgart
+ author : Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCATEGORYREASSIGNDLG_H
+#define KCATEGORYREASSIGNDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qvaluelist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include "kmymoney2/dialogs/kcategoryreassigndlgdecl.h"
+
+/**
+ * Implementation of the dialog that lets the user select a payee in order
+ * to re-assign transactions (for instance, if payees are deleted).
+ */
+class KCategoryReassignDlg : public KCategoryReassignDlgDecl
+{
+ Q_OBJECT
+public:
+ /** Default constructor */
+ KCategoryReassignDlg( QWidget* parent = 0, const char* name = 0);
+
+ /** Destructor */
+ ~KCategoryReassignDlg();
+
+ /**
+ * This function sets up the dialog, lets the user select a category and returns
+ * the id of the selected category in the list of all known income and expense accounts.
+ *
+ * @param category reference to MyMoneyAccount object of the category to be deleted
+ *
+ * @return Returns the id of the selected category in the list or QString() if
+ * the dialog was aborted. QString() is also returned if the @a category
+ * does not have an id.
+ */
+ QString show(const MyMoneyAccount& category);
+
+protected:
+ void accept(void);
+
+};
+
+#endif // KCATEGORYREASSIGNDLG_H
diff --git a/kmymoney2/dialogs/kcategoryreassigndlgdecl.ui b/kmymoney2/dialogs/kcategoryreassigndlgdecl.ui
new file mode 100644
index 0000000..5b9a954
--- /dev/null
+++ b/kmymoney2/dialogs/kcategoryreassigndlgdecl.ui
@@ -0,0 +1,175 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KCategoryReassignDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KCategoryeReassignDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>392</width>
+ <height>308</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Reassign categories</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>The transactions, schedules and budgets associated with the selected category need to be re-assigned to a different category before the selected category can be deleted. Please select a category from the list below.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignJustify|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Available categories:</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory">
+ <property name="name">
+ <cstring>m_category</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>305</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KCategoryeReassignDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KCategoryeReassignDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kchooseimportexportdlg.cpp b/kmymoney2/dialogs/kchooseimportexportdlg.cpp
new file mode 100644
index 0000000..0c390a8
--- /dev/null
+++ b/kmymoney2/dialogs/kchooseimportexportdlg.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ kchooseimportexportdlg.cpp - description
+ -------------------
+ begin : Thu Jul 12 2001
+ copyright : (C) 2000-2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include <kglobal.h>
+#include <klocale.h>
+#if QT_VERSION > 300
+#include <kstandarddirs.h>
+#else
+#include <kstddirs.h>
+#endif
+
+#include <qpixmap.h>
+
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qpushbutton.h>
+
+#include <kglobal.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+#include "kchooseimportexportdlg.h"
+
+KChooseImportExportDlg::KChooseImportExportDlg(int type, QWidget *parent, const char *name )
+ : KChooseImportExportDlgDecl(parent,name, true)
+{
+ QString filename;
+
+ if (type==0) { // import
+ topLabel->setText(i18n("Please choose the type of import you wish to perform. A simple explanation\n"
+ "of the import type is available at the bottom of the screen and is updated when\n"
+ "you select an item from the choice box."
+ "\n\nOnce you have chosen an import type please press the OK button." ));
+ promptLabel->setText(i18n("Choose import type:"));
+ setCaption(i18n("Choose Import Type Dialog"));
+ } else { // export
+ topLabel->setText(i18n("Please choose the type of export you wish to perform. A simple explanation\n"
+ "of the export type is available at the bottom of the screen and is updated when\n"
+ "you select an item from the choice box."
+ "\n\nOnce you have chosen an export type please press the OK button." ));
+ promptLabel->setText(i18n("Choose export type:"));
+ setCaption(i18n("Choose Export Type Dialog"));
+ }
+
+ readConfig();
+ slotTypeActivated(m_lastType);
+ typeCombo->setCurrentItem(((m_lastType=="QIF") ? 0 : 1));
+
+ connect(typeCombo, SIGNAL(activated(const QString&)), this, SLOT(slotTypeActivated(const QString&)));
+ connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+KChooseImportExportDlg::~KChooseImportExportDlg()
+{
+ writeConfig();
+}
+
+void KChooseImportExportDlg::slotTypeActivated(const QString& text)
+{
+ if (text=="QIF") {
+ descriptionLabel->setText(i18n("QIF files are created by the popular accounting program Quicken.\n"
+ "Another dialog will appear, if you choose this type, asking for further\n"
+ "information relevant to the Quicken format."));
+ } else {
+ descriptionLabel->setText(i18n("The CSV type uses a comma delimeted text file that can be used by\n"
+ "most popular spreadsheet programs available for Linux and other operating\n"
+ "systems."));
+ }
+}
+
+QString KChooseImportExportDlg::importExportType(void)
+{
+ return typeCombo->currentText();
+}
+
+void KChooseImportExportDlg::readConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ m_lastType = config->readEntry("KChooseImportExportDlg_LastType");
+}
+
+void KChooseImportExportDlg::writeConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("KChooseImportExportDlg_LastType", typeCombo->currentText());
+ config->sync();
+}
+
+#include "kchooseimportexportdlg.moc"
diff --git a/kmymoney2/dialogs/kchooseimportexportdlg.h b/kmymoney2/dialogs/kchooseimportexportdlg.h
new file mode 100644
index 0000000..ac562f3
--- /dev/null
+++ b/kmymoney2/dialogs/kchooseimportexportdlg.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ kchooseimportexportdlg.h - description
+ -------------------
+ begin : Thu Jul 12 2001
+ copyright : (C) 2000-2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCHOOSEIMPORTEXPORTDLG_H
+#define KCHOOSEIMPORTEXPORTDLG_H
+
+#include <qwidget.h>
+#include "../dialogs/kchooseimportexportdlgdecl.h"
+
+/**
+ *@author Michael Edwardes
+ */
+
+class KChooseImportExportDlg : public KChooseImportExportDlgDecl {
+ Q_OBJECT
+private:
+ void readConfig(void);
+ void writeConfig(void);
+ QString m_lastType;
+
+protected slots:
+ void slotTypeActivated(const QString& text);
+
+public:
+ KChooseImportExportDlg(int type, QWidget *parent=0, const char *name=0);
+ ~KChooseImportExportDlg();
+ QString importExportType(void);
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kchooseimportexportdlgdecl.ui b/kmymoney2/dialogs/kchooseimportexportdlgdecl.ui
new file mode 100644
index 0000000..3d12a14
--- /dev/null
+++ b/kmymoney2/dialogs/kchooseimportexportdlgdecl.ui
@@ -0,0 +1,235 @@
+<!DOCTYPE UI><UI>
+<class>KChooseImportExportDlgDecl</class>
+<widget>
+ <class>QDialog</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>kChooseImportDlgDecl</cstring>
+ </property>
+ <property stdset="1">
+ <name>caption</name>
+ <string>Choose Import Type Dialog</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>topLabel</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Please choose the type of import you wish to perform. A simple explanation
+of the import type is available at the bottom of the screen and is updated when
+you select an item from the choice box.
+
+Once you have chosen an import type please press the OK button.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>Line</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Line1</cstring>
+ </property>
+ <property stdset="1">
+ <name>frameShadow</name>
+ <enum>Raised</enum>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout3</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer1</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>promptLabel</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Choose import type:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QComboBox</class>
+ <item>
+ <property>
+ <name>text</name>
+ <string>QIF</string>
+ </property>
+ </item>
+ <item>
+ <property>
+ <name>text</name>
+ <string>CSV</string>
+ </property>
+ </item>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>typeCombo</cstring>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>descriptionLabel</cstring>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ </sizepolicy>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>410</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Some descripton</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer2</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>okButton</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>OK</string>
+ </property>
+ <property stdset="1">
+ <name>default</name>
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>cancelButton</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+</UI>
diff --git a/kmymoney2/dialogs/kconfirmmanualenterdlg.cpp b/kmymoney2/dialogs/kconfirmmanualenterdlg.cpp
new file mode 100644
index 0000000..3c20a48
--- /dev/null
+++ b/kmymoney2/dialogs/kconfirmmanualenterdlg.cpp
@@ -0,0 +1,202 @@
+/***************************************************************************
+ kconfirmmanualenterdlg.cpp
+ -------------------
+ begin : Mon Apr 9 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qradiobutton.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <ktextedit.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyutils.h>
+#include "kconfirmmanualenterdlg.h"
+
+KConfirmManualEnterDlg::KConfirmManualEnterDlg(const MyMoneySchedule& schedule, QWidget* parent, const char* name) :
+ KConfirmManualEnterDlgDecl(parent, name)
+{
+ buttonOk->setGuiItem(KStdGuiItem::ok());
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+ m_onceRadio->setChecked(true);
+ m_onceRadio->setFocus();
+
+ if(schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT) {
+ m_setRadio->setEnabled(false);
+ m_discardRadio->setEnabled(false);
+ }
+
+}
+
+void KConfirmManualEnterDlg::loadTransactions(const MyMoneyTransaction& to, const MyMoneyTransaction& tn)
+{
+ QString messageDetail("<qt>");
+ MyMoneyFile* file = MyMoneyFile::instance();
+ int noItemsChanged=0;
+
+#if 0
+ // if no schedule is present, we cannot enter it
+ if(m_schedule.id().isEmpty())
+ return false;
+
+ if (m_fromAccountId == m_toAccountId)
+ {
+ KMessageBox::error(this, i18n("Account and transfer account are the same. Please change one."));
+ m_from->setFocus();
+ return false;
+ }
+
+ if (!checkDateInPeriod(m_date->date()))
+ return false;
+#endif
+
+ try
+ {
+ QString po, pn;
+ if(to.splits()[0].payeeId())
+ po = file->payee(to.splits()[0].payeeId()).name();
+ if(tn.splits()[0].payeeId())
+ pn = file->payee(tn.splits()[0].payeeId()).name();
+
+ if (po != pn) {
+ noItemsChanged++;
+ messageDetail += i18n("Payee changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>").arg(po).arg(pn);
+ }
+#if 0
+ if ( (m_schedule.type() == MyMoneySchedule::TYPE_TRANSFER ||
+ m_schedule.type() == MyMoneySchedule::TYPE_BILL) &&
+ m_from->currentText() != m_schedule.account().name())
+ {
+ noItemsChanged++;
+ messageDetail += i18n("Account changed. Old: \"%1\", New: \"%2\"")
+ .arg(m_schedule.account().name()).arg(m_from->currentText()) + QString("\n");
+ }
+
+ if ( m_schedule.type() == MyMoneySchedule::TYPE_DEPOSIT &&
+ m_to->currentText() != m_schedule.account().name())
+ {
+ noItemsChanged++;
+ messageDetail += i18n("Account changed. Old: \"%1\", New: \"%2\"")
+ .arg(m_schedule.account().name()).arg(m_to->currentText()) + QString("\n");
+ }
+#endif
+
+ if(to.splits()[0].accountId() != tn.splits()[0].accountId()) {
+ noItemsChanged++;
+ messageDetail += i18n("Account changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>")
+ .arg(file->account(to.splits()[0].accountId()).name())
+ .arg(file->account(tn.splits()[0].accountId()).name());
+ }
+
+ if(file->isTransfer(to) && file->isTransfer(tn)) {
+ if(to.splits()[1].accountId() != tn.splits()[1].accountId()) {
+ noItemsChanged++;
+ messageDetail += i18n("Transfer account changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>")
+ .arg(file->account(to.splits()[1].accountId()).name())
+ .arg(file->account(tn.splits()[1].accountId()).name());
+ }
+ } else {
+ QString co, cn;
+ switch(to.splitCount()) {
+ default:
+ co = i18n("Split transaction (category replacement)", "Split transaction");
+ break;
+ case 2:
+ co = file->accountToCategory(to.splits()[1].accountId());
+ case 1:
+ break;
+ }
+
+ switch(tn.splitCount()) {
+ default:
+ cn = i18n("Split transaction (category replacement)", "Split transaction");
+ break;
+ case 2:
+ cn = file->accountToCategory(tn.splits()[1].accountId());
+ case 1:
+ break;
+ }
+ if (co != cn)
+ {
+ noItemsChanged++;
+ messageDetail += i18n("Category changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>").arg(co).arg(cn);
+ }
+ }
+
+ QString mo, mn;
+ mo = to.splits()[0].memo();
+ mn = tn.splits()[0].memo();
+ if(mo.isEmpty())
+ mo = QString("<i>")+i18n("empty")+QString("</i>");
+ if(mn.isEmpty())
+ mn = QString("<i>")+i18n("empty")+QString("</i>");
+ if (mo != mn)
+ {
+ noItemsChanged++;
+ messageDetail += i18n("Memo changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>").arg(mo).arg(mn);
+ }
+
+ const MyMoneySecurity& sec = MyMoneyFile::instance()->security(to.commodity());
+ MyMoneyMoney ao, an;
+ ao = to.splits()[0].value();
+ an = tn.splits()[0].value();
+ if (ao != an) {
+ noItemsChanged++;
+ messageDetail += i18n("Amount changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>")
+ .arg(ao.formatMoney(sec.smallestAccountFraction())).arg(an.formatMoney(sec.smallestAccountFraction()));
+ }
+
+ MyMoneySplit::reconcileFlagE fo, fn;
+ fo = to.splits()[0].reconcileFlag();
+ fn = tn.splits()[0].reconcileFlag();
+ if(fo != fn) {
+ noItemsChanged++;
+ messageDetail += i18n("Reconciliation flag changed.<br>&nbsp;&nbsp;&nbsp;Old: <b>%1</b>, New: <b>%2</b><p>")
+ .arg(KMyMoneyUtils::reconcileStateToString(fo, true))
+ .arg(KMyMoneyUtils::reconcileStateToString(fn, true));
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ KMessageBox::error(this, i18n("Fatal error in determining data: ") + e->what());
+ delete e;
+ }
+
+ messageDetail += "</qt>";
+ m_details->setText(messageDetail);
+ return;
+}
+
+KConfirmManualEnterDlg::Action KConfirmManualEnterDlg::action(void) const
+{
+ if(m_discardRadio->isChecked())
+ return UseOriginal;
+ if(m_setRadio->isChecked())
+ return ModifyAlways;
+ return ModifyOnce;
+}
+
+#include "kconfirmmanualenterdlg.moc"
diff --git a/kmymoney2/dialogs/kconfirmmanualenterdlg.h b/kmymoney2/dialogs/kconfirmmanualenterdlg.h
new file mode 100644
index 0000000..43ff65a
--- /dev/null
+++ b/kmymoney2/dialogs/kconfirmmanualenterdlg.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ kconfirmmanualenterdlg.h
+ -------------------
+ begin : Mon Apr 9 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCONFIRMMANUALENTERDLG_H
+#define KCONFIRMMANUALENTERDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytransaction.h>
+#include "../dialogs/kconfirmmanualenterdlgdecl.h"
+
+class KConfirmManualEnterDlg : public KConfirmManualEnterDlgDecl
+{
+ Q_OBJECT
+public:
+ KConfirmManualEnterDlg(const MyMoneySchedule& schedule, QWidget* parent = 0, const char* name = 0);
+
+ typedef enum {
+ UseOriginal = 0,
+ ModifyOnce,
+ ModifyAlways
+ } Action;
+
+ /**
+ * setup the dialog for the difference between the original transaction
+ * @a to and the transaction to be entered @a tn.
+ */
+ void loadTransactions(const MyMoneyTransaction& to, const MyMoneyTransaction& tn);
+
+ /**
+ * Returns information about what to do with the transaction
+ */
+ Action action(void) const;
+};
+
+#endif // KCONFIRMMANUALENTERDLG_H
diff --git a/kmymoney2/dialogs/kconfirmmanualenterdlgdecl.ui b/kmymoney2/dialogs/kconfirmmanualenterdlgdecl.ui
new file mode 100644
index 0000000..f88f0ce
--- /dev/null
+++ b/kmymoney2/dialogs/kconfirmmanualenterdlgdecl.ui
@@ -0,0 +1,160 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KConfirmManualEnterDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KConfirmManualEnterDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>578</width>
+ <height>384</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Confirm Manual Enter</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_message</cstring>
+ </property>
+ <property name="text">
+ <string>The following changes have been made to the transaction data:</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ </widget>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>m_details</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ </font>
+ </property>
+ <property name="title">
+ <string>Please choose what you wish to do with the above changes</string>
+ </property>
+ <property name="selectedId" stdset="0">
+ <number>1</number>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_discardRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Discard the changes and enter the original transaction into the register.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_onceRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Enter these new values this one time, for this occurence only.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_setRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Set all further occurences in this schedule to be these values.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>180</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KConfirmManualEnterDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KConfirmManualEnterDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kcsvprogressdlg.cpp b/kmymoney2/dialogs/kcsvprogressdlg.cpp
new file mode 100644
index 0000000..d8f85ed
--- /dev/null
+++ b/kmymoney2/dialogs/kcsvprogressdlg.cpp
@@ -0,0 +1,252 @@
+/***************************************************************************
+ kcsvprogressdlg.cpp - description
+ -------------------
+ begin : Sun Jul 29 2001
+ copyright : (C) 2000-2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include <kglobal.h>
+#include <klocale.h>
+#if QT_VERSION > 300
+#include <kstandarddirs.h>
+#else
+#include <kstddirs.h>
+#endif
+
+#include <qpixmap.h>
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qprogressbar.h>
+#include <qlineedit.h>
+#include <qgroupbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kcsvprogressdlg.h"
+#include "../widgets/kmymoneydateinput.h"
+#include "../kmymoneyutils.h"
+
+/** Simple constructor */
+KCsvProgressDlg::KCsvProgressDlg(int type, MyMoneyAccount *account, QWidget *parent, const char *name )
+ : KCsvProgressDlgDecl(parent,name, true)
+{
+ m_nType = type;
+ if (m_nType==0)
+ {
+ m_kmymoneydateEnd->setEnabled(false);
+ m_kmymoneydateStart->setEnabled(false);
+ m_qbuttonRun->setText(i18n("&Import"));
+ }
+ else
+ m_qbuttonRun->setText(i18n("&Export"));
+
+ m_mymoneyaccount = account;
+
+ m_qbuttonOk->setText(i18n("C&lose"));
+
+ readConfig();
+
+ connect(m_qbuttonBrowse, SIGNAL(clicked()), this, SLOT(slotBrowseClicked()));
+ connect(m_qbuttonRun, SIGNAL(clicked()), this, SLOT(slotRunClicked()));
+ connect(m_qlineeditFile, SIGNAL(textChanged(const QString&)), this,
+ SLOT(slotFileTextChanged(const QString&)));
+ connect(m_qbuttonOk, SIGNAL(clicked()), this, SLOT(accept()));
+}
+
+/** Simple destructor */
+KCsvProgressDlg::~KCsvProgressDlg()
+{
+ writeConfig();
+}
+
+/** Perform the export process */
+void KCsvProgressDlg::performExport(void)
+{
+/*
+ // Do some validation on the inputs.
+ if (m_qlineeditFile->text().isEmpty()) {
+ KMessageBox::information(this, i18n("Please enter the path to the CSV file"), i18n("Export CSV"));
+ m_qlineeditFile->setFocus();
+ return;
+ }
+
+ QString strFile = m_qlineeditFile->text();
+ if(KMyMoneyUtils::appendCorrectFileExt(strFile, QString("csv")))
+ m_qlineeditFile->setText(strFile);
+
+ if (m_kmymoneydateEnd->getQDate() < m_kmymoneydateStart->getQDate()) {
+ KMessageBox::information(this, i18n("Please enter a start date lower than the end date."));
+ return;
+ }
+
+ QFile qfile(m_qlineeditFile->text());
+ if (!qfile.open(IO_WriteOnly)) {
+ KMessageBox::error(this, i18n("Unable to open export file for writing."));
+ return;
+ }
+ qfile.close();
+
+ m_qlabelAccount->setText(m_mymoneyaccount->name());
+ m_qlabelTransaction->setText(QString("0") + i18n(" of ") + QString::number(m_mymoneyaccount->transactionCount()));
+ m_qprogressbar->setTotalSteps(m_mymoneyaccount->transactionCount());
+
+ // Make sure we have an account to operate on
+ if (m_mymoneyaccount) {
+ // Connect to the provided signals in MyMoneyAccount
+ // These signals will be emitted at appropriate times.
+ connect(m_mymoneyaccount, SIGNAL(signalProgressCount(int)), m_qprogressbar, SLOT(setTotalSteps(int)));
+ connect(m_mymoneyaccount, SIGNAL(signalProgress(int)), this, SLOT(slotSetProgress(int)));
+
+ int nTransCount = 0;
+
+ // Do the actual write
+ if (!m_mymoneyaccount->writeCSVFile(m_qlineeditFile->text(), m_kmymoneydateStart->getQDate(),
+ m_kmymoneydateEnd->getQDate(), nTransCount)) {
+ KMessageBox::error(this, i18n("Error occurred whilst exporting to csv file."), i18n("Export CSV"));
+ }
+ else {
+ QString qstringPrompt = i18n("Export finished successfully.\n\n");
+ qstringPrompt += i18n("Number of transactions exported ");
+ qstringPrompt += QString::number(nTransCount);
+ qstringPrompt += ".";
+ KMessageBox::information(this, qstringPrompt, i18n("Export CSV"));
+ }
+ }
+*/
+}
+
+/** perform the import process */
+void KCsvProgressDlg::performImport(void)
+{
+/*
+ // Do some validation on the inputs.
+ if (m_qlineeditFile->text().isEmpty()) {
+ KMessageBox::information(this, i18n("Please enter the path to the CSV file"), i18n("Import CSV"));
+ m_qlineeditFile->setFocus();
+ return;
+ }
+
+ QFile qfile(m_qlineeditFile->text());
+ if (!qfile.open(IO_ReadOnly)) {
+ KMessageBox::error(this, i18n("Unable to open import file for reading."));
+ return;
+ }
+ qfile.close();
+
+ m_qlabelAccount->setText(m_mymoneyaccount->name());
+
+ // Make sure we have an account to operate on
+ if (m_mymoneyaccount) {
+ // Connect to the provided signals in MyMoneyAccount
+ // These signals will be emitted at appropriate times.
+ connect(m_mymoneyaccount, SIGNAL(signalProgressCount(int)), m_qprogressbar, SLOT(setTotalSteps(int)));
+ connect(m_mymoneyaccount, SIGNAL(signalProgress(int)), this, SLOT(slotSetProgress(int)));
+
+ int nTransCount = 0;
+
+ // Do the actual write
+ if (!m_mymoneyaccount->readCSVFile(m_qlineeditFile->text(), nTransCount)) {
+ KMessageBox::error(this, i18n("Error occurred whilst importing csv file."), i18n("Import CSV"));
+ }
+ else {
+ QString qstringPrompt = i18n("Import finished successfully.\n\n");
+ qstringPrompt += i18n("Number of transactions imported ");
+ qstringPrompt += QString::number(nTransCount);
+ qstringPrompt += ".";
+ KMessageBox::information(this, qstringPrompt, i18n("Import CSV"));
+ }
+ }
+*/
+}
+
+/** Called when the user clicks on the Browser button */
+void KCsvProgressDlg::slotBrowseClicked()
+{
+ QString newName = KFileDialog::getSaveFileName(QString::null,"*.CSV");
+ if (!newName.isEmpty())
+ {
+ m_qlineeditFile->setText(newName);
+ m_qbuttonRun->setEnabled(true);
+ }
+ else
+ m_qbuttonRun->setEnabled(false);
+}
+
+/** Called when user clicks on the Run button */
+void KCsvProgressDlg::slotRunClicked()
+{
+ m_qgroupbox->setEnabled(true);
+ if (m_nType==0)
+ performImport();
+ else
+ performExport();
+}
+
+/** Make sure the text input is ok */
+void KCsvProgressDlg::slotFileTextChanged(const QString& text)
+{
+ if (!text.isEmpty()) {
+ m_qlineeditFile->setText(text);
+ m_qbuttonRun->setEnabled(true);
+ } else
+ m_qbuttonRun->setEnabled(false);
+}
+
+void KCsvProgressDlg::readConfig(void)
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("Last Use Settings");
+ m_kmymoneydateStart->setDate(kconfig->readDateTimeEntry("KCsvProgressDlg_StartDate").date());
+ m_kmymoneydateEnd->setDate(kconfig->readDateTimeEntry("KCsvProgressDlg_EndDate").date());
+ m_qlineeditFile->setText(kconfig->readEntry("KCsvProgressDlg_LastFile", ""));
+ if (m_qlineeditFile->text().length()>=1)
+ m_qbuttonRun->setEnabled(true);
+ else
+ m_qbuttonRun->setEnabled(false);
+}
+
+void KCsvProgressDlg::writeConfig(void)
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("Last Use Settings");
+ kconfig->writeEntry("KCsvProgressDlg_LastFile", m_qlineeditFile->text());
+ kconfig->writeEntry("KCsvProgressDlg_StartDate", QDateTime(m_kmymoneydateStart->date()));
+ kconfig->writeEntry("KCsvProgressDlg_EndDate", QDateTime(m_kmymoneydateEnd->date()));
+ kconfig->sync();
+}
+
+/** Update the progress bar, and update the transaction count indicator. */
+void KCsvProgressDlg::slotSetProgress(int progress)
+{
+ m_qprogressbar->setProgress(progress);
+ QString qstring = QString::number(progress);
+ qstring += i18n(" of ");
+ qstring += QString::number(m_qprogressbar->totalSteps());
+ m_qlabelTransaction->setText(qstring);
+}
+
+#include "kcsvprogressdlg.moc"
diff --git a/kmymoney2/dialogs/kcsvprogressdlg.h b/kmymoney2/dialogs/kcsvprogressdlg.h
new file mode 100644
index 0000000..339d210
--- /dev/null
+++ b/kmymoney2/dialogs/kcsvprogressdlg.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ kcsvprogressdlg.h - description
+ -------------------
+ begin : Sun Jul 29 2001
+ copyright : (C) 2000-2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KCSVPROGRESSDLG_H
+#define KCSVPROGRESSDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../mymoney/mymoneyaccount.h"
+#include "../dialogs/kcsvprogressdlgdecl.h"
+
+/**
+ * This class is used to show the progress of an import or export of type
+ * csv. It could eventually become a base class for other import/export
+ * types which would reimplement performImport/performExport.
+ *
+ * @author Michael Edwardes 2000-2001
+ * $Id: kcsvprogressdlg.h,v 1.5 2005/03/23 20:42:31 ipwizard Exp $
+ *
+ * @short A class to show the progress of a CSV import or export.
+**/
+class KCsvProgressDlg : public KCsvProgressDlgDecl {
+ Q_OBJECT
+private:
+ MyMoneyAccount *m_mymoneyaccount;
+ int m_nType;
+
+protected:
+ void performExport(void);
+ void performImport(void);
+ void readConfig(void);
+ void writeConfig(void);
+
+protected slots:
+ void slotBrowseClicked();
+ void slotRunClicked();
+ void slotFileTextChanged(const QString& text);
+ void slotSetProgress(int progress);
+
+public:
+ KCsvProgressDlg(int type, MyMoneyAccount *account, QWidget *parent=0, const char *name=0);
+ ~KCsvProgressDlg();
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kcsvprogressdlgdecl.ui b/kmymoney2/dialogs/kcsvprogressdlgdecl.ui
new file mode 100644
index 0000000..4b1afd5
--- /dev/null
+++ b/kmymoney2/dialogs/kcsvprogressdlgdecl.ui
@@ -0,0 +1,535 @@
+<!DOCTYPE UI><UI>
+<class>KCsvProgressDlgDecl</class>
+<widget>
+ <class>QDialog</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>kcsvprogressdlgdecl</cstring>
+ </property>
+ <property stdset="1">
+ <name>caption</name>
+ <string>CSV Dialog</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>CSV Dialog. Choose a file and then click on Run. You can view your progress at
+the bottom of the screen.
+
+You can cancel the process at any time by clicking on the Cancel button.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>Line</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Line2</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout20</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout19</cstring>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Choose the csv file:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout18</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLineEdit</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qlineeditFile</cstring>
+ </property>
+ </widget>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qbuttonBrowse</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Browse</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QGroupBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qgroupboxDates</cstring>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>Between These Dates</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout8</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>lblStartDate</cstring>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ </sizepolicy>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Start on:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>kMyMoneyDateInput</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_kmymoneydateStart</cstring>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout7_2</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>lblEndDate</cstring>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ </sizepolicy>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>End on:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>kMyMoneyDateInput</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_kmymoneydateEnd</cstring>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer3</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qbuttonRun</cstring>
+ </property>
+ <property stdset="1">
+ <name>enabled</name>
+ <bool>false</bool>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Run</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QGroupBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qgroupbox</cstring>
+ </property>
+ <property stdset="1">
+ <name>enabled</name>
+ <bool>false</bool>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>Progress Info</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Processing Account:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qlabelAccount</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Unknown</string>
+ </property>
+ <property stdset="1">
+ <name>alignment</name>
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property>
+ <name>hAlign</name>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Processing Transaction:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qlabelTransaction</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>0 of 0</string>
+ </property>
+ <property stdset="1">
+ <name>alignment</name>
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property>
+ <name>hAlign</name>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QProgressBar</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qprogressbar</cstring>
+ </property>
+ <property stdset="1">
+ <name>enabled</name>
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout3</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer1</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>m_qbuttonOk</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Close</string>
+ </property>
+ <property stdset="1">
+ <name>default</name>
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyDateInput</class>
+ <header location="global">../widgets/kmymoneydateinput.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>1</hordata>
+ <verdata>1</verdata>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image>
+ <name>image0</name>
+ <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data>
+ </image>
+</images>
+</UI>
diff --git a/kmymoney2/dialogs/kcurrencycalculator.cpp b/kmymoney2/dialogs/kcurrencycalculator.cpp
new file mode 100644
index 0000000..6e674dc
--- /dev/null
+++ b/kmymoney2/dialogs/kcurrencycalculator.cpp
@@ -0,0 +1,315 @@
+/***************************************************************************
+ kcurrencycalculator.cpp - description
+ -------------------
+ begin : Thu Apr 8 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qwidgetstack.h>
+#include <qgroupbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kcombobox.h>
+#include <kstdguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kcurrencycalculator.h"
+
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneycurrencyselector.h>
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "../kmymoneyutils.h"
+
+bool KCurrencyCalculator::setupSplitPrice(MyMoneyMoney& shares, const MyMoneyTransaction& t, const MyMoneySplit& s, const QMap<QString, MyMoneyMoney>& priceInfo, QWidget* parentWidget)
+{
+ bool rc = true;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if(!s.value().isZero()) {
+ MyMoneyAccount cat = file->account(s.accountId());
+ MyMoneySecurity toCurrency;
+ toCurrency = file->security(cat.currencyId());
+ // determine the fraction required for this category/account
+ int fract = cat.fraction(toCurrency);
+
+ if(cat.currencyId() != t.commodity()) {
+
+ MyMoneySecurity fromCurrency;
+ MyMoneyMoney fromValue, toValue;
+ fromCurrency = file->security(t.commodity());
+ // display only positive values to the user
+ fromValue = s.value().abs();
+
+ // if we had a price info in the beginning, we use it here
+ if(priceInfo.find(cat.currencyId()) != priceInfo.end()) {
+ toValue = (fromValue * priceInfo[cat.currencyId()]).convert(fract);
+ }
+
+ // if the shares are still 0, we need to change that
+ if(toValue.isZero()) {
+ MyMoneyPrice price = file->price(fromCurrency.id(), toCurrency.id());
+ // if the price is valid calculate the shares. If it is invalid
+ // assume a conversion rate of 1.0
+ if(price.isValid()) {
+ toValue = (price.rate(toCurrency.id()) * fromValue).convert(fract);
+ } else {
+ toValue = fromValue;
+ }
+ }
+
+ // now present all that to the user
+ KCurrencyCalculator calc(fromCurrency,
+ toCurrency,
+ fromValue,
+ toValue,
+ t.postDate(),
+ fract,
+ parentWidget, "currencyCalculator");
+
+ if(calc.exec() == QDialog::Rejected) {
+ rc = false;
+ } else
+ shares = (s.value() * calc.price()).convert(fract);
+
+ } else {
+ shares = s.value().convert(fract);
+ }
+ } else
+ shares = s.value();
+
+ return rc;
+}
+
+KCurrencyCalculator::KCurrencyCalculator(const MyMoneySecurity& from, const MyMoneySecurity& to, const MyMoneyMoney& value, const MyMoneyMoney& shares, const QDate& date, const signed64 resultFraction, QWidget *parent, const char *name ) :
+ KCurrencyCalculatorDecl(parent, name),
+ m_fromCurrency(from),
+ m_toCurrency(to),
+ m_result(shares.abs()),
+ m_value(value.abs()),
+ m_resultFraction(resultFraction)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ m_dateFrame->hide();
+ if(date.isValid())
+ m_dateEdit->setDate(date);
+ else
+ m_dateEdit->setDate(QDate::currentDate());
+
+ m_fromCurrencyText->setText(m_fromCurrency.isCurrency() ? m_fromCurrency.id() : m_fromCurrency.tradingSymbol());
+ m_toCurrencyText->setText(m_toCurrency.isCurrency() ? m_toCurrency.id() : m_toCurrency.tradingSymbol());
+
+ m_fromAmount->setText(m_value.formatMoney("", MyMoneyMoney::denomToPrec(m_fromCurrency.smallestAccountFraction())));
+
+ m_dateText->setText(KGlobal::locale()->formatDate(date, true));
+
+ m_fromType->setText(KMyMoneyUtils::securityTypeToString(m_fromCurrency.securityType()));
+ m_toType->setText(KMyMoneyUtils::securityTypeToString(m_toCurrency.securityType()));
+
+ // load button icons
+ m_cancelButton->setGuiItem(KStdGuiItem::cancel());
+ m_okButton->setGuiItem(KStdGuiItem::ok());
+
+ m_updateButton->setChecked(KMyMoneyGlobalSettings::priceHistoryUpdate());
+
+ // setup initial result
+ if(m_result == MyMoneyMoney() && !m_value.isZero()) {
+ MyMoneyPrice pr = file->price(m_fromCurrency.id(), m_toCurrency.id(), date);
+ if(pr.isValid()) {
+ m_result = m_value * pr.rate(m_fromCurrency.id());
+ }
+ }
+
+ // fill in initial values
+ m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
+ m_toAmount->setPrecision(MyMoneyMoney::denomToPrec(m_resultFraction));
+
+ m_conversionRate->setPrecision(KMyMoneyGlobalSettings::pricePrecision());
+
+ connect(m_amountButton, SIGNAL(clicked()), this, SLOT(slotSetToAmount()));
+ connect(m_rateButton, SIGNAL(clicked()), this, SLOT(slotSetExchangeRate()));
+
+ connect(m_toAmount, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateResult(const QString&)));
+ connect(m_conversionRate, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateRate(const QString&)));
+ connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_okButton, SIGNAL(clicked()), this, SLOT(accept()));
+
+ // use this as the default
+ m_amountButton->animateClick();
+ slotUpdateResult(m_toAmount->text());
+
+ // If the from security is not a currency, we only allow entering a price
+ if(!m_fromCurrency.isCurrency()) {
+ m_rateButton->animateClick();
+ m_amountButton->hide();
+ m_toAmount->hide();
+ }
+ m_okButton->setFocus();
+}
+
+KCurrencyCalculator::~KCurrencyCalculator()
+{
+}
+
+void KCurrencyCalculator::setupPriceEditor(void)
+{
+ m_dateFrame->show();
+ m_amountDateFrame->hide();
+ m_updateButton->setChecked(true);
+ m_updateButton->hide();
+}
+
+void KCurrencyCalculator::slotSetToAmount(void)
+{
+ m_rateButton->setChecked(false);
+ m_toAmount->setEnabled(true);
+ m_conversionRate->setEnabled(false);
+}
+
+void KCurrencyCalculator::slotSetExchangeRate(void)
+{
+ m_amountButton->setChecked(false);
+ m_toAmount->setEnabled(false);
+ m_conversionRate->setEnabled(true);
+}
+
+void KCurrencyCalculator::slotUpdateResult(const QString& /*txt*/)
+{
+ MyMoneyMoney result = m_toAmount->value();
+ MyMoneyMoney price(0, 1);
+
+ if(result.isNegative()) {
+ m_toAmount->setValue(-result);
+ slotUpdateResult(QString());
+ return;
+ }
+
+ if(!result.isZero()) {
+ price = result / m_value;
+
+ m_conversionRate->loadText(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
+ m_result = (m_value * price).convert(m_resultFraction);
+ m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
+ }
+ updateExample(price);
+}
+
+void KCurrencyCalculator::slotUpdateRate(const QString& /*txt*/)
+{
+ MyMoneyMoney price = m_conversionRate->value();
+
+ if(price.isNegative()) {
+ m_conversionRate->setValue(-price);
+ slotUpdateRate(QString());
+ return;
+ }
+
+ if(!price.isZero()) {
+ m_conversionRate->loadText(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
+ m_result = (m_value * price).convert(m_resultFraction);
+ m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
+ }
+ updateExample(price);
+}
+
+void KCurrencyCalculator::updateExample(const MyMoneyMoney& price)
+{
+ QString msg;
+ if(price.isZero()) {
+ msg = QString("1 %1 = ? %2").arg(m_fromCurrency.tradingSymbol())
+ .arg(m_toCurrency.tradingSymbol());
+ if(m_fromCurrency.isCurrency()) {
+ msg += QString("\n");
+ msg += QString("1 %1 = ? %2").arg(m_toCurrency.tradingSymbol())
+ .arg(m_fromCurrency.tradingSymbol());
+ }
+ } else {
+ msg = QString("1 %1 = %2 %3").arg(m_fromCurrency.tradingSymbol())
+ .arg(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()))
+ .arg(m_toCurrency.tradingSymbol());
+ if(m_fromCurrency.isCurrency()) {
+ msg += QString("\n");
+ msg += QString("1 %1 = %2 %3").arg(m_toCurrency.tradingSymbol())
+ .arg((MyMoneyMoney(1,1)/price).formatMoney("", KMyMoneyGlobalSettings::pricePrecision()))
+ .arg(m_fromCurrency.tradingSymbol());
+ }
+ }
+ m_conversionExample->setText(msg);
+ m_okButton->setEnabled(!price.isZero());
+}
+
+void KCurrencyCalculator::accept(void)
+{
+ if(m_conversionRate->isEnabled())
+ slotUpdateRate(QString());
+ else
+ slotUpdateResult(QString());
+
+ if(m_updateButton->isChecked()) {
+ MyMoneyPrice pr = MyMoneyFile::instance()->price(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date());
+ if(!pr.isValid()
+ || pr.date() != m_dateEdit->date()
+ || (pr.date() == m_dateEdit->date() && pr.rate(m_fromCurrency.id()) != price())) {
+ pr = MyMoneyPrice(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date(), price(), i18n("User"));
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->addPrice(pr);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ qDebug("Cannot add price");
+ delete e;
+ }
+ }
+ }
+
+ // remember setting for next round
+ KMyMoneyGlobalSettings::setPriceHistoryUpdate(m_updateButton->isChecked());
+
+ KCurrencyCalculatorDecl::accept();
+}
+
+const MyMoneyMoney KCurrencyCalculator::price(void) const
+{
+ // This should fix https://bugs.kde.org/show_bug.cgi?id=205254 but
+ // I am not sure about any side effects when dealing with multi-
+ // currency transactions.
+ //
+ // The following line is the original version of this code
+ // which causes some rounding issues (see the above bug entry)
+ // return m_result / m_value;
+ return m_conversionRate->value();
+}
+
+
+#include "kcurrencycalculator.moc"
diff --git a/kmymoney2/dialogs/kcurrencycalculator.h b/kmymoney2/dialogs/kcurrencycalculator.h
new file mode 100644
index 0000000..d9934da
--- /dev/null
+++ b/kmymoney2/dialogs/kcurrencycalculator.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ kcurrencycalculator.h - description
+ -------------------
+ begin : Thu Apr 8 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCURRENCYCALCULATOR_H
+#define KCURRENCYCALCULATOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/kcurrencycalculatordecl.h"
+#include <kmymoney/mymoneyfile.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KCurrencyCalculator : public KCurrencyCalculatorDecl
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @param from the @p from currency
+ * @param to the @p to currency
+ * @param value the value to be converted
+ * @param shares the number of foreign currency units
+ * @param date the date when the conversion took place
+ * @param resultFraction the smallest fraction of the result (default 100)
+ * @param parent see QWidget constructor
+ * @param name see QWidget constructor
+ *
+ * @note @p value must not be 0!
+ */
+ KCurrencyCalculator(const MyMoneySecurity& from, const MyMoneySecurity& to, const MyMoneyMoney& value, const MyMoneyMoney& shares, const QDate& date, const signed64 resultFraction = 100, QWidget *parent=0, const char *name=0);
+ ~KCurrencyCalculator();
+
+ const MyMoneyMoney price(void) const;
+
+ void setupPriceEditor(void);
+
+ static bool setupSplitPrice(MyMoneyMoney& shares, const MyMoneyTransaction& t, const MyMoneySplit& s, const QMap<QString, MyMoneyMoney>& priceInfo, QWidget* parentWidget);
+
+protected:
+ void updateExample(const MyMoneyMoney& price);
+
+protected slots:
+ void slotSetToAmount(void);
+ void slotSetExchangeRate(void);
+ void slotUpdateResult(const QString& txt);
+ void slotUpdateRate(const QString& txt);
+ virtual void accept(void);
+
+private:
+ MyMoneySecurity m_fromCurrency;
+ MyMoneySecurity m_toCurrency;
+ MyMoneyMoney m_result;
+ MyMoneyMoney m_value;
+ signed64 m_resultFraction;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kcurrencycalculatordecl.ui b/kmymoney2/dialogs/kcurrencycalculatordecl.ui
new file mode 100644
index 0000000..688a282
--- /dev/null
+++ b/kmymoney2/dialogs/kcurrencycalculatordecl.ui
@@ -0,0 +1,414 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KCurrencyCalculatorDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KCurrencyCalculatorDecl</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>387</width>
+ <height>368</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Exchange Rate/Price Editor</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_amountDateFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Amount</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_fromAmount</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_dateText</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>145</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2_2</cstring>
+ </property>
+ <property name="title">
+ <string>Convert from</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_fromType</cstring>
+ </property>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_fromCurrencyText</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Convert to</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_toType</cstring>
+ </property>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_toCurrencyText</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_conversionRate</cstring>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0" rowspan="3" colspan="1">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_amountButton</cstring>
+ </property>
+ <property name="text">
+ <string>To amount</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_rateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Exchange rate / Price</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_dateFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_dateEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_conversionExample</cstring>
+ </property>
+ <property name="text">
+ <string>xx
+xx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_toAmount</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_updateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Update price history</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_okButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>m_amountButton</tabstop>
+ <tabstop>m_rateButton</tabstop>
+ <tabstop>m_updateButton</tabstop>
+ <tabstop>m_okButton</tabstop>
+ <tabstop>m_cancelButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kcurrencyeditdlg.cpp b/kmymoney2/dialogs/kcurrencyeditdlg.cpp
new file mode 100644
index 0000000..55bac30
--- /dev/null
+++ b/kmymoney2/dialogs/kcurrencyeditdlg.cpp
@@ -0,0 +1,291 @@
+/***************************************************************************
+ kcurrencyeditdlg.cpp - description
+ -------------------
+ begin : Wed Mar 24 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <locale.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qheader.h>
+#include <qtimer.h>
+
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qlabel.h>
+#include <qgroupbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <klistview.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kinputdialog.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kcurrencyeditdlg.h"
+
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneylistviewitem.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kmymoneylineedit.h>
+
+#include "../widgets/kmymoneypriceview.h"
+
+KCurrencyEditDlg::KCurrencyEditDlg(QWidget *parent, const char *name ) :
+ KCurrencyEditDlgDecl(parent,name)
+{
+ m_currencyList->addColumn(i18n("Currency"));
+ m_currencyList->header()->hide();
+
+ // FIXME: the online source table currently has no functionality
+ m_onlineSourceTable->hide();
+
+ connect(m_currencyList, SIGNAL(rightButtonPressed(QListViewItem* , const QPoint&, int)),
+ this, SLOT(slotListClicked(QListViewItem*, const QPoint&, int)));
+ connect(m_currencyList, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotSelectCurrency(QListViewItem*)));
+
+
+ connect(m_currencyList, SIGNAL(itemRenamed(QListViewItem*,int,const QString&)), this, SIGNAL(renameCurrency(QListViewItem*,int,const QString&)));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadCurrencies()));
+
+ slotLoadCurrencies();
+
+ connect(m_baseCurrencyButton, SIGNAL(clicked()), this, SLOT(slotSelectBaseCurrency()));
+ connect(buttonClose, SIGNAL(clicked()), this, SLOT(slotClose()));
+
+ // FIXME: currently, no online help available
+ buttonHelp->hide();
+
+ // FIXME this is currently unused so we hide it also
+ m_description->hide();
+
+ resize(width()-1, height()-1);
+ QTimer::singleShot(10, this, SLOT(timerDone()));
+}
+
+void KCurrencyEditDlg::timerDone(void)
+{
+ if(!m_currency.id().isEmpty()) {
+ QListViewItemIterator it(m_currencyList);
+ QListViewItem* q;
+ while((q = it.current()) != 0) {
+ KMyMoneyListViewItem* p = static_cast<KMyMoneyListViewItem *>(q);
+ if(p->id() == m_currency.id()) {
+ m_currencyList->ensureItemVisible(q);
+ break;
+ }
+ ++it;
+ }
+ }
+ // the resize operation does the trick to adjust
+ // all widgets in the view to the size they should
+ // have and show up correctly. Don't ask me, why
+ // this is, but it cured the problem (ipwizard).
+ resize(width()+1, height()+1);
+}
+
+KCurrencyEditDlg::~KCurrencyEditDlg()
+{
+}
+
+void KCurrencyEditDlg::resizeEvent(QResizeEvent* /* e*/)
+{
+ int w = m_currencyList->visibleWidth();
+
+ m_currencyList->setColumnWidth(0, w);
+}
+
+void KCurrencyEditDlg::slotLoadCurrencies(void)
+{
+ QValueList<MyMoneySecurity> list = MyMoneyFile::instance()->currencyList();
+ QValueList<MyMoneySecurity>::ConstIterator it;
+ QListViewItem *first = 0;
+
+ QString localCurrency(localeconv()->int_curr_symbol);
+ localCurrency.truncate(3);
+
+ QString baseCurrency = MyMoneyFile::instance()->baseCurrency().id();
+ // construct a transparent 16x16 pixmap
+ QPixmap empty(16, 16);
+ empty.setMask(QBitmap(16, 16, true));
+
+ m_currencyList->clear();
+ for(it = list.begin(); it != list.end(); ++it) {
+ KMyMoneyListViewItem* p = new KMyMoneyListViewItem(m_currencyList, (*it).name(), QString(), (*it).id());
+ p->setRenameEnabled(0, true);
+
+ if((*it).id() == baseCurrency) {
+ p->setPixmap(0, QPixmap( locate("icon","hicolor/16x16/apps/kmymoney2.png")));
+ if(m_currency.id().isEmpty())
+ first = p;
+ } else {
+ p->setPixmap(0, empty);
+ }
+
+ // if we had a previously selected
+ if(!m_currency.id().isEmpty()) {
+ if(m_currency.id() == p->id())
+ first = p;
+ } else if ((*it).id() == localCurrency && !first)
+ first = p;
+ }
+
+ if(first == 0)
+ first = m_currencyList->firstChild();
+ if(first != 0) {
+ m_currencyList->setSelected(first, true);
+ m_currencyList->ensureItemVisible(first);
+ }
+
+ slotSelectCurrency(first);
+}
+
+void KCurrencyEditDlg::updateCurrency(void)
+{
+ if(!m_currency.id().isEmpty()) {
+ if(m_symbolEdit->text() != m_currency.tradingSymbol()) {
+ m_currency.setTradingSymbol(m_symbolEdit->text());
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifyCurrency(m_currency);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ qWarning("Updateing the currency failed!");
+ delete e;
+ }
+ }
+ }
+}
+
+void KCurrencyEditDlg::slotSelectCurrency(const QString& id)
+{
+ QListViewItemIterator it(m_currencyList);
+
+ while(it.current()) {
+ KMyMoneyListViewItem* p = static_cast<KMyMoneyListViewItem*>(it.current());
+ if(p->id() == id) {
+ slotSelectCurrency(p);
+ m_currencyList->setSelected(p, true);
+ m_currencyList->ensureItemVisible(p);
+ break;
+ }
+ ++it;
+ }
+}
+
+void KCurrencyEditDlg::slotSelectCurrency(QListViewItem *item)
+{
+ QMap<QDate, MyMoneyMoney> history;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ updateCurrency();
+
+ m_detailGroup->setEnabled(item != 0);
+ m_onlineSourceTable->clear();
+ m_idLabel->setText(QString());
+ m_symbolEdit->setText(QString());
+
+ if(item) {
+ try {
+ KMyMoneyListViewItem* p = static_cast<KMyMoneyListViewItem *>(item);
+ m_currency = file->security(p->id());
+ m_idLabel->setText(m_currency.id());
+ m_symbolEdit->setText(m_currency.tradingSymbol());
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ m_currency = MyMoneySecurity();
+ m_onlineSourceTable->clear();
+ m_idLabel->setText(QString());
+ m_symbolEdit->setText(QString());
+ }
+ m_baseCurrencyButton->setDisabled(m_currency.id() == file->baseCurrency().id());
+ emit selectObject(m_currency);
+ }
+}
+
+void KCurrencyEditDlg::slotClose(void)
+{
+ updateCurrency();
+ accept();
+}
+
+void KCurrencyEditDlg::slotStartRename(void)
+{
+ QListViewItemIterator it_l(m_currencyList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ if((it_v = it_l.current()) != 0) {
+ it_v->startRename(0);
+ }
+}
+
+void KCurrencyEditDlg::slotListClicked(QListViewItem* item, const QPoint&, int)
+{
+ slotSelectCurrency(item);
+ emit openContextMenu(m_currency);
+}
+
+void KCurrencyEditDlg::slotRenameCurrency(QListViewItem* item, int /* col */, const QString& txt)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ KMyMoneyListViewItem* p = static_cast<KMyMoneyListViewItem *>(item);
+
+ try {
+ if(txt != m_currency.name()) {
+ qDebug("Renaming");
+ MyMoneySecurity currency = file->currency(p->id());
+ currency.setName(txt);
+ MyMoneyFileTransaction ft;
+ try {
+ file->modifyCurrency(currency);
+ m_currency = currency;
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ qDebug("Renaming currency failed");
+ delete e;
+ }
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ updateCurrency();
+ }
+}
+
+void KCurrencyEditDlg::slotSelectBaseCurrency(void)
+{
+ if(!m_currency.id().isEmpty()) {
+ QListViewItem* p = m_currencyList->selectedItem();
+ emit selectBaseCurrency(m_currency);
+ // in case the dataChanged() signal was not sent out (nested FileTransaction)
+ // we update the list manually
+ if(p == m_currencyList->selectedItem())
+ slotLoadCurrencies();
+ }
+}
+
+#include "kcurrencyeditdlg.moc"
diff --git a/kmymoney2/dialogs/kcurrencyeditdlg.h b/kmymoney2/dialogs/kcurrencyeditdlg.h
new file mode 100644
index 0000000..f1a4871
--- /dev/null
+++ b/kmymoney2/dialogs/kcurrencyeditdlg.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ kcurrencyeditdlg.h - description
+ -------------------
+ begin : Wed Mar 24 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCURRENCYEDITDLG_H
+#define KCURRENCYEDITDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KPopupMenu;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/kcurrencyeditdlgdecl.h"
+#include "../mymoney/mymoneysecurity.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KCurrencyEditDlg : public KCurrencyEditDlgDecl
+{
+ Q_OBJECT
+public:
+ KCurrencyEditDlg(QWidget *parent=0, const char *name=0);
+ ~KCurrencyEditDlg();
+
+public slots:
+ void slotSelectCurrency(const QString& id);
+
+protected:
+ /// the resize event
+ virtual void resizeEvent(QResizeEvent*);
+ void updateCurrency(void);
+
+protected slots:
+ void slotSelectCurrency(QListViewItem *);
+
+ void slotClose(void);
+ void slotStartRename(void);
+ void slotListClicked(QListViewItem* item, const QPoint&, int);
+ void slotRenameCurrency(QListViewItem* item, int col, const QString& txt);
+ void slotLoadCurrencies(void);
+
+private slots:
+ void timerDone(void);
+ void slotSelectBaseCurrency(void);
+
+signals:
+ void selectObject(const MyMoneySecurity& currency);
+ void openContextMenu(const MyMoneySecurity& currency);
+ void renameCurrency(QListViewItem* item, int, const QString& txt);
+ void selectBaseCurrency(const MyMoneySecurity& currency);
+
+private:
+ MyMoneySecurity m_currency;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kcurrencyeditdlgdecl.ui b/kmymoney2/dialogs/kcurrencyeditdlgdecl.ui
new file mode 100644
index 0000000..4a0a740
--- /dev/null
+++ b/kmymoney2/dialogs/kcurrencyeditdlgdecl.ui
@@ -0,0 +1,304 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KCurrencyEditDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KCurrencyEditDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>666</width>
+ <height>516</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Currencies</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>m_currencyList</cstring>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_baseCurrencyFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_baseCurrencyButton</cstring>
+ </property>
+ <property name="text">
+ <string>Select as base currency</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_detailGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Details</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Symbol</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_idLabel</cstring>
+ </property>
+ <property name="text">
+ <string>real ID</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_symbolEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>ID</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_description</cstring>
+ </property>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Online Source</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_onlineSourceTable</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonClose</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>If this button is not activated, select the base currency first.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Press this button to close the dialog. If the button is not activated, select your base currency.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyLineEdit</class>
+ <header location="local">../widgets/kmymoneylineedit.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1114">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042149444154789c8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d096e8b11261871837bc8e282ac7ac82187e049a317e32d37110992bf42123c694eea414c0e0bf1b0ec6c402139485a54e8810c54c10e741146fa110bd643f74c12bd642e4d75f77cf5d5ef7dafdfc2ce7087d9eff32fdfdff74e5114104011e489d6e952cce5cfbe5998692dec0c77b87aedd3fddd9f2b3efce02291082209aa3504685022e4ffd7a000a82a765c515615ce95acae659c3f7765c100ec6e575cf8f822e991025f3b6a6f890c484f181ccfc1583428f5d4e2fe84da039aa04121b40eb32483a0ec6e5bce9f8385d36fa7fb9b1b17c8f31cbfe7a95c45be94520c72b2141a1caa160d1666e24ea94aa11ee7685054159d2ada34d41387c40dc63b8844f0b5c73a4bb19cb3f9de001f2aac1fa23aa209168c004224902e29d22ff1e38abbdb275055c4800610233867311a1491847a62c98f66ac6f14d8e99072f22daa15b68a8108424d6422e24c88e3966fbce4c9d786945b27f0be0103ed13c16004d59a2c4d58df28a87548e9aee2274ab95d60c7193c9a0281fc959ae2a4450364a9e2572c7a2b43438374ef2dd2154012d050514dbec7396578a3130d9d6850066f0ad9d186f2d78cdbbb799b0a202f2c48d3aebbb418310240b112637588574bf54b8efaa4fd9b691dacbf5b305813542bae63a9eee4c4694d967b5494eca8c7ef0933bdc5d90e6a2caa0e3f013b7adce9fa5b03d637561113a30106a71d18c5fd9677058338ad01e91c0b8b743b880182ce19cd9c0e5e2b583fbdda565d3d04cfedad180942133af201b2bc3588e111c680068f489780ce69b192b279768088524f2b3458ea694d3de99a4323bc976ed34eb86b98c51993f6be10f77240c99685cd731991f1582df15aa15a213d583f5313a7806988fb8a0640e336359d9e9933568bf44062214ba19e2a7652a13d8b068ff596b807182189234e9da9f1ceb78c81b28c3ac6fe21e306c58e41d5118952acd6a0c2f56b9e6a5c72f346cdcd6b19a3bf8010010d714f89533b674c90c7189b598eab12a45fb5c75b8253672b863fbcccf5af93b6904119fe9851bf5153ac3a746ae7b9d5698c1dc58f313e70e4707ce9d84bafa2f79fc23fb8c7c1438ef04031a2642fee21060ec69ee47020796ecaa12313ccd333d1b67935047acf2be3bb11aa010dbe656cc755dbe3b772084a7ebc6d5711253b593dfcc0cc8fcd3cafda455512c7f200ec56cbfac0f1d7d34b7fdf0f98fd88a92a7e9cb0e70cc933c0b38a2c823ea0bd76c70c016adb67f47bc2a117a6d40abeea33fa23c2fb867edfb413e4a34fded94ffb3991c46dc7754cd3634ad2af490b857f5a5137126a97e02a8120a485235b6a28ef80bd077ee2b9f2d54fed04595dcbd8ddb6c4bd87334c10cadb2064e856177e7864e669fbe1df154a0142839f7ad2e5b6880bff1da66eece78e315d959f609da670f98befe6c3f45fb42672c9acff7f660000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/keditequityentrydecl.ui b/kmymoney2/dialogs/keditequityentrydecl.ui
new file mode 100644
index 0000000..4acf703
--- /dev/null
+++ b/kmymoney2/dialogs/keditequityentrydecl.ui
@@ -0,0 +1,306 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KEditEquityEntryDecl</class>
+<author>Kevin Tambascio </author>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KEditEquityEntryDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>482</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Edit Equity</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>edtEquityName</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Stock</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mutual Fund</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Bond</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>cmbInvestmentType</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Smallest fraction:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="1">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>1 /</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>edtFraction</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblType</cstring>
+ </property>
+ <property name="text">
+ <string>Investment Type:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lblEquityName</cstring>
+ </property>
+ <property name="text">
+ <string>Equity Name:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>edtMarketSymbol</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblSymbol</cstring>
+ </property>
+ <property name="text">
+ <string>Market Symbol:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Price History</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneyPriceView">
+ <property name="name">
+ <cstring>kpvPriceHistory</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnAddEntry</cstring>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnEditEntry</cstring>
+ </property>
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnRemoveEntry</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>238</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnOK</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyEdit</class>
+ <header location="local">../widgets/kmymoneyedit.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>1</hordata>
+ <verdata>1</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>KMyMoneyPriceView</class>
+ <header location="local">../widgets/kmymoneypriceview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image1</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="256">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c749444154789cad55db1184200c4c180bb005eab1cd6b8112b40d4bf1bee2486ef3006fbf1c93ece605f07eece4e1a4ed42ff2b35f6e2961132e46309941952ed8f628a761a21f56217cb20b04a45fe276d97f8ffb422431ad96e62a4ee057a83131bcc38431a6d057f8eb5cb36438afcb5cded719614011e9088308374c61aa9adb0e0651b5552b4b29efaacb099312ad5da5b2d50a93124463b2adf516fbb8cbd1354a9b1b667c8a787674144f9f982bcb93635ba8cb3fd1b2616f251013403fee763fabce8bff0aa6c989d7e67440000000049454e44ae426082</data>
+ </image>
+ <image name="image1">
+ <data format="PNG" length="826">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154789cb59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a0901e2257b0000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/keditequityentrydlg.cpp b/kmymoney2/dialogs/keditequityentrydlg.cpp
new file mode 100644
index 0000000..854ce9a
--- /dev/null
+++ b/kmymoney2/dialogs/keditequityentrydlg.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+ keditequityentrydlg.cpp - description
+ -------------------
+ begin : Sat Mar 6 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qtimer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "keditequityentrydlg.h"
+#include "kupdatestockpricedlg.h"
+#include "../widgets/kmymoneypriceview.h"
+
+KEditEquityEntryDlg::KEditEquityEntryDlg(const MyMoneySecurity& selectedSecurity, QWidget *parent, const char *name)
+ : KEditEquityEntryDecl(parent, name, true)
+{
+ m_selectedSecurity = selectedSecurity;
+
+ connect(btnOK, SIGNAL(clicked()), this, SLOT(slotOKClicked()));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(edtEquityName, SIGNAL(textChanged(const QString &)), this, SLOT(slotDataChanged()));
+ connect(edtMarketSymbol, SIGNAL(textChanged(const QString &)), this, SLOT(slotDataChanged()));
+ connect(edtFraction, SIGNAL(textChanged(const QString&)), this, SLOT(slotDataChanged()));
+ connect(btnAddEntry, SIGNAL(clicked()), kpvPriceHistory, SLOT(slotAddPrice()));
+ connect(btnEditEntry, SIGNAL(clicked()), kpvPriceHistory, SLOT(slotEditPrice()));
+ connect(btnRemoveEntry, SIGNAL(clicked()), kpvPriceHistory, SLOT(slotDeletePrice()));
+ connect(kpvPriceHistory, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotSelectionChanged(QListViewItem*)));
+
+ //fill in the fields with what we know.
+ edtEquityName->setText(m_selectedSecurity.name());
+ edtMarketSymbol->setText(m_selectedSecurity.tradingSymbol());
+ edtFraction->setPrecision(0);
+ edtFraction->setCalculatorButtonVisible(false);
+ edtFraction->loadText(QString::number(m_selectedSecurity.smallestAccountFraction()));
+ cmbInvestmentType->setCurrentItem((int)m_selectedSecurity.securityType());
+ // FIXME PRICE
+ // kpvPriceHistory->setHistory(m_selectedSecurity.priceHistory());
+
+ // add icons to buttons
+ KIconLoader *il = KGlobal::iconLoader();
+ btnOK->setGuiItem(KStdGuiItem::ok());
+ btnCancel->setGuiItem(KStdGuiItem::cancel());
+ btnRemoveEntry->setGuiItem(KStdGuiItem::remove());
+ btnAddEntry->setGuiItem(KStdGuiItem::add());
+
+ KGuiItem editButtenItem( i18n( "&Edit" ),
+ QIconSet(il->loadIcon("edit", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Modify the selected entry"),
+ i18n("Change the price information of the selected entry."));
+ btnEditEntry->setGuiItem(editButtenItem);
+
+ slotSelectionChanged(0); // make sure buttons are disabled in the beginning
+ slotDataChanged();
+ m_changes = false;
+
+ // force a resize to optimize the layout of all widgets
+ resize(width()-1, height()-1);
+ QTimer::singleShot(10, this, SLOT(slotTimerDone()));
+}
+
+KEditEquityEntryDlg::~KEditEquityEntryDlg()
+{
+}
+
+void KEditEquityEntryDlg::slotTimerDone(void)
+{
+ // the resize operation does the trick to adjust
+ // all widgets in the view to the size they should
+ // have and show up correctly. Don't ask me, why
+ // this is, but it cured the problem (ipwizard).
+ resize(width()+1, height()+1);
+}
+
+/** No descriptions */
+void KEditEquityEntryDlg::slotOKClicked()
+{
+ if(m_changes /* || kpvPriceHistory->dirty() */)
+ {
+ m_selectedSecurity.setName(edtEquityName->text());
+ m_selectedSecurity.setTradingSymbol(edtMarketSymbol->text());
+ m_selectedSecurity.setSmallestAccountFraction(edtFraction->value().abs());
+ // FIXME PRICE
+ // m_selectedSecurity.setPriceHistory(kpvPriceHistory->history());
+ }
+
+ accept();
+}
+
+void KEditEquityEntryDlg::slotSelectionChanged(QListViewItem* item)
+{
+ btnEditEntry->setEnabled(item != 0);
+ btnRemoveEntry->setEnabled(item != 0);
+}
+
+void KEditEquityEntryDlg::slotDataChanged(void)
+{
+ bool okEnabled = true;
+
+ if(!edtFraction->value().isPositive()
+ || edtMarketSymbol->text().isEmpty()
+ || edtEquityName->text().isEmpty())
+ okEnabled = false;
+
+ btnOK->setEnabled(okEnabled);
+
+ m_changes = true;
+}
+
+#include "keditequityentrydlg.moc"
diff --git a/kmymoney2/dialogs/keditequityentrydlg.h b/kmymoney2/dialogs/keditequityentrydlg.h
new file mode 100644
index 0000000..0fdf40e
--- /dev/null
+++ b/kmymoney2/dialogs/keditequityentrydlg.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ keditequityentrydlg.h - description
+ -------------------
+ begin : Sat Mar 6 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KEDITEQUITYENTRYDLG_H
+#define KEDITEQUITYENTRYDLG_H
+
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qdialog.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <klistview.h>
+#include <klocale.h>
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/keditequityentrydecl.h"
+#include "../mymoney/mymoneysecurity.h"
+
+/**
+ * @author Kevin Tambascio
+ */
+
+class KEditEquityEntryDlg : public KEditEquityEntryDecl
+{
+ Q_OBJECT
+public:
+ KEditEquityEntryDlg(const MyMoneySecurity& selectedSecurity, QWidget *parent = NULL, const char *name = NULL);
+ ~KEditEquityEntryDlg();
+
+ void updatedEquity(MyMoneySecurity& security) { security = m_selectedSecurity; }
+
+protected slots:
+ void slotOKClicked();
+ void slotDataChanged(void);
+ void slotSelectionChanged(QListViewItem* item);
+
+private slots:
+ void slotTimerDone(void);
+
+private:
+ MyMoneySecurity m_selectedSecurity;
+ bool m_changes;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/keditloanwizard.cpp b/kmymoney2/dialogs/keditloanwizard.cpp
new file mode 100644
index 0000000..6054cec
--- /dev/null
+++ b/kmymoney2/dialogs/keditloanwizard.cpp
@@ -0,0 +1,514 @@
+/***************************************************************************
+ keditloanwizard.cpp - description
+ -------------------
+ begin : Wed Nov 12 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <../dialogs/knewloanwizard.h>
+#include "keditloanwizard.h"
+#include "../widgets/kmymoneylineedit.h"
+#include "../widgets/kmymoneyedit.h"
+#include "../widgets/kmymoneycombo.h"
+#include "../widgets/kmymoneyaccountselector.h"
+#include "../widgets/kmymoneydateinput.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../kmymoneyutils.h"
+
+KEditLoanWizard::KEditLoanWizard(const MyMoneyAccount& account, QWidget *parent, const char *name ) :
+ KNewLoanWizard(parent, name)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ setCaption(i18n("Edit loan wizard"));
+ m_effectiveDateLabel->setText(QString("\n") + i18n(
+ "Please enter the date from which on the following changes will be effective. "
+ "The date entered must be later than the opening date of this account (%1), but must "
+ "not be in the future. The default will be today.").arg(KGlobal::locale()->formatDate(account.openingDate(), true)));
+ m_account = account;
+ try {
+ QString id = m_account.value("schedule");
+ m_schedule = file->schedule(id);
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ m_lastSelection = -1;
+ m_editInterestRateButton->animateClick();
+
+ loadWidgets(m_account);
+
+ if(m_account.openingDate() > QDate::currentDate()) {
+ m_effectiveDateNoteLabel->setText(QString("\n") + i18n(
+ "Note: you will not be able to modify this account today, because the opening date \"%1\" is in the future. "
+ "Please revisit this dialog when the time has come."
+ ).arg(KGlobal::locale()->formatDate(m_account.openingDate(), true)));
+ } else {
+ m_effectiveDateNoteLabel->hide();
+ }
+ // turn off all pages that are contained here for derived classes
+ setAppropriate(m_newIntroPage, false);
+ setAppropriate(m_newGeneralInfoPage, false);
+ setAppropriate(m_lendBorrowPage, false);
+ setAppropriate(m_namePage, false);
+ setAppropriate(m_newCalculateLoanPage, false);
+ setAppropriate(m_newPaymentsPage, false);
+ removePage(m_assetAccountPage);
+ m_assetAccountPage = 0;
+
+ // turn on all pages that are contained here for derived classes
+ setAppropriate(m_editIntroPage, true);
+ setAppropriate(m_editSelectionPage, true);
+
+ // setup connections
+ connect(m_effectiveChangeDateEdit, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotCheckPageFinished()));
+ connect(m_newPaymentEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished()));
+ connect(m_newInterestRateEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished()));
+
+ // make sure, we show the correct start page
+ showPage(m_editIntroPage);
+}
+
+KEditLoanWizard::~KEditLoanWizard()
+{
+}
+
+void KEditLoanWizard::loadWidgets(const MyMoneyAccount& /* account */)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString paymentAccountId, interestAccountId;
+
+ m_nameEdit->loadText(m_account.name());
+ m_loanAmountEdit->loadText(m_account.loanAmount().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
+ m_finalPaymentEdit->loadText(m_account.finalPayment().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
+ m_firstDueDateEdit->setDate(m_account.openingDate());
+
+ if(m_account.fixedInterestRate()) {
+ m_fixedInterestButton->animateClick();
+ } else {
+ m_variableInterestButton->animateClick();
+ }
+
+ MyMoneyMoney ir;
+ if(m_schedule.startDate() > QDate::currentDate()) {
+ ir = m_account.interestRate(m_schedule.startDate());
+ } else {
+ ir = m_account.interestRate(QDate::currentDate());
+ }
+ m_interestRateEdit->loadText(ir.formatMoney("", 3));
+ m_newInterestRateEdit->loadText(ir.formatMoney("", 3));
+ m_newInterestRateEdit->setPrecision(3);
+ m_interestRateLabel->setText(QString(" ") + ir.formatMoney("", 3) + QString("%"));
+
+ m_paymentFrequencyUnitEdit->setCurrentItem(i18n(m_schedule.occurenceToString()));
+ updateTermWidgets(m_account.term());
+
+ // the base payment (amortization and interest) is determined
+ // by adding all splits that are not automatically calculated.
+ // If the loan is a liability, we reverse the sign at the end
+ MyMoneyMoney basePayment;
+ MyMoneyMoney addPayment;
+
+ m_transaction = m_schedule.transaction();
+
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = m_schedule.transaction().splits().begin();
+ it_s != m_schedule.transaction().splits().end();
+ ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ // if it's the split that references the source/dest
+ // of the money, we check if we borrow or loan money
+ if(paymentAccountId.isEmpty()
+ && acc.isAssetLiability() && !acc.isLoan()
+ && (*it_s).value() != MyMoneyMoney::autoCalc) {
+ if((*it_s).value().isNegative()) {
+ m_lendButton->setChecked(false);
+ m_borrowButton->setChecked(true);
+ } else {
+ m_lendButton->setChecked(true);
+ m_borrowButton->setChecked(false);
+ }
+ // we keep the amount of the full payment and subtract the
+ // base payment later to get information about the additional payment
+ addPayment = (*it_s).value();
+ paymentAccountId = (*it_s).accountId();
+ MyMoneyPayee payee;
+ if(!(*it_s).payeeId().isEmpty()) {
+ try {
+ payee = file->payee((*it_s).payeeId());
+ m_payeeEdit->setSelectedItem(payee.id());
+ } catch(MyMoneyException *e) {
+ delete e;
+ qWarning("Payee for schedule has been deleted");
+ }
+ }
+
+ // remove this split with one that will be replaced
+ // later and has a phony id
+ m_transaction.removeSplit(*it_s);
+ m_split.clearId();
+ m_transaction.addSplit(m_split);
+ }
+
+ if((*it_s).action() == MyMoneySplit::ActionInterest) {
+ interestAccountId = (*it_s).accountId();
+ }
+
+ if((*it_s).value() != MyMoneyMoney::autoCalc) {
+ basePayment += (*it_s).value();
+ } else {
+ // remove the splits which should not show up
+ // for additional fees
+ m_transaction.removeSplit(*it_s);
+ }
+
+ }
+ if(m_borrowButton->isChecked()) {
+ basePayment = -basePayment;
+ addPayment = -addPayment;
+ }
+ // now make adjustment to get the amount of the additional fees
+ addPayment -= basePayment;
+
+ // load account selection widgets now that we know if
+ // we borrow or lend money
+ loadAccountList();
+
+ int fraction = m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()));
+ m_paymentEdit->loadText(basePayment.formatMoney(fraction));
+ m_newPaymentEdit->loadText(basePayment.formatMoney(fraction));
+ m_paymentLabel->setText(QString(" ") + basePayment.formatMoney(fraction));
+
+ m_additionalCost->setText(addPayment.formatMoney(fraction));
+ m_interestAccountEdit->setSelected(interestAccountId);
+ m_paymentAccountEdit->setSelected(paymentAccountId);
+ m_nextDueDateEdit->setDate(m_schedule.nextPayment());
+
+ int changeFrequencyUnit;
+ int amt = m_account.interestChangeFrequency(&changeFrequencyUnit);
+ if(amt != -1) {
+ m_interestFrequencyAmountEdit->setValue(amt);
+ m_interestFrequencyUnitEdit->setCurrentItem(changeFrequencyUnit);
+ }
+
+ // keep track, if the loan should be fully repayed
+ m_fullyRepayLoan = m_account.finalPayment() < basePayment;
+
+ updateLoanInfo();
+ updateSummary();
+}
+
+void KEditLoanWizard::next()
+{
+ bool dontLeavePage = false;
+ QButton* button = m_selectionButtonGroup->find(m_lastSelection);
+
+ if(currentPage() == m_editSelectionPage) {
+
+ if(button != 0
+ && m_lastSelection != m_selectionButtonGroup->id(m_selectionButtonGroup->selected())) {
+ QString errMsg = i18n(
+ "Your previous selection was \"%1\". If you select another option, "
+ "KMyMoney will dismiss the changes you have just entered. "
+ "Do you wish to proceed?").arg(button->text());
+
+ if(KMessageBox::questionYesNo(this, errMsg) == KMessageBox::No) {
+ dontLeavePage = true;
+ } else {
+ loadWidgets(m_account);
+ }
+ }
+
+ if(!dontLeavePage) {
+ button = m_selectionButtonGroup->selected();
+
+ // turn off all pages except the summary at the end
+ // and the one's we need for the selected option
+ // and load the widgets with the current values
+
+ // general info
+ setAppropriate(m_namePage, false);
+ setAppropriate(m_interestTypePage, false);
+ setAppropriate(m_previousPaymentsPage, false);
+ setAppropriate(m_recordPaymentPage, false);
+ setAppropriate(m_variableInterestDatePage, false);
+ setAppropriate(m_firstPaymentPage, false);
+ // loan calculation
+ setAppropriate(m_paymentEditPage, false);
+ setAppropriate(m_interestEditPage, false);
+ setAppropriate(m_paymentFrequencyPage, false);
+ setAppropriate(m_interestCalculationPage, false);
+ setAppropriate(m_loanAmountPage, false);
+ setAppropriate(m_interestPage, false);
+ setAppropriate(m_durationPage, false);
+ setAppropriate(m_paymentPage, false);
+ setAppropriate(m_finalPaymentPage, false);
+ setAppropriate(m_calculationOverviewPage, false);
+ // payment
+ setAppropriate(m_interestCategoryPage, false);
+ setAppropriate(m_additionalFeesPage, false);
+ setAppropriate(m_schedulePage, false);
+ setAppropriate(m_summaryPage, true);
+
+ setAppropriate(m_effectiveDatePage, true);
+ if(indexOf(m_summaryPage) != -1) {
+ removePage(m_summaryPage);
+ setFinishEnabled(m_summaryEditPage, true);
+ }
+
+ if(button == m_editInterestRateButton) {
+ setAppropriate(m_interestTypePage, true);
+ setAppropriate(m_variableInterestDatePage, true);
+ setAppropriate(m_paymentEditPage, true);
+ setAppropriate(m_interestEditPage, true);
+ setAppropriate(m_summaryEditPage, true);
+
+ } else if(button == m_editOtherCostButton) {
+ setAppropriate(m_additionalFeesPage, true);
+ setAppropriate(m_summaryEditPage, true);
+
+ } else if(button == m_editOtherInfoButton) {
+ setAppropriate(m_namePage, true);
+ setAppropriate(m_interestCalculationPage, true);
+ setAppropriate(m_interestPage, true);
+ setAppropriate(m_durationPage, true);
+ setAppropriate(m_paymentPage, true);
+ setAppropriate(m_finalPaymentPage, true);
+ setAppropriate(m_calculationOverviewPage, true);
+ setAppropriate(m_interestCategoryPage, true);
+ setAppropriate(m_additionalFeesPage, true);
+ setAppropriate(m_schedulePage, true);
+ setAppropriate(m_summaryEditPage, false);
+ addPage(m_summaryPage, i18n("Summary"));
+ setAppropriate(m_summaryPage, true);
+ setFinishEnabled(m_summaryEditPage, false);
+ setFinishEnabled(m_summaryPage, true);
+
+ } else {
+ qFatal("%s,%d: This should never happen", __FILE__, __LINE__);
+ }
+
+ m_lastSelection = m_selectionButtonGroup->id(m_selectionButtonGroup->selected());
+ } // if(!dontLeavePage)
+
+ } else if(currentPage() == m_additionalFeesPage) {
+ button = m_selectionButtonGroup->selected();
+ if(button == m_editOtherCostButton) {
+ updateLoanInfo();
+ updateEditSummary();
+ }
+
+ } else if(currentPage() == m_interestEditPage) {
+ // copy the necessary data to the widgets used for calculation
+ m_interestRateEdit->setValue(m_newInterestRateEdit->value());
+ m_paymentEdit->setValue(m_newPaymentEdit->value());
+
+ // if interest rate and payment amount is given, then force
+ // the term to be recalculated. The final payment is adjusted to
+ // 0 if the loan was ment to be fully repayed
+ updateTermWidgets(m_account.term());
+ if(!m_interestRateEdit->lineedit()->text().isEmpty()
+ && !m_paymentEdit->lineedit()->text().isEmpty()) {
+ // if there's an amortization going on, we can evaluate
+ // the new term. If the amortization is 0 (interest only
+ // payments) then we keep the term as entered by the user.
+ if(m_loanAmountEdit->value() != m_finalPaymentEdit->value()) {
+ m_durationValueEdit->setValue(0);
+ }
+ if(m_fullyRepayLoan)
+ m_finalPaymentEdit->loadText(MyMoneyMoney(0).formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
+ }
+
+/*
+ // we need to calculate the balance at the time of the change
+ // in order to accurately recalculate the term. A special
+ // situation arises, when we keep track of all payments and
+ // the full loan is not yet paid out. In this case, we take the
+ // the loan amount minus all amortization payments as the current
+ // balance.
+ // FIXME: This needs some more thoughts. We leave it out for
+ // now and always calculate with the full loan amount.
+ MyMoneyMoney balance = m_account.openingBalance();
+
+ QValueList<MyMoneyTransaction> list;
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ MyMoneySplit split;
+ MyMoneyTransactionFilter filter(m_account.id());
+
+ filter.setDateFilter(QDate(), m_effectiveChangeDateEdit->date().addDays(-1));
+ list = MyMoneyFile::instance()->transactionList(filter);
+
+ for(it = list.begin(); it != list.end(); ++it) {
+ try {
+ split = (*it).splitByAccount(m_account.id());
+ balance += split.value();
+
+ } catch(MyMoneyException *e) {
+ // account is not referenced within this transaction
+ delete e;
+ }
+ }
+ m_loanAmountEdit->setText(balance.formatMoney());
+*/
+
+ // now re-calculate the figures
+ dontLeavePage = !calculateLoan();
+
+ // reset the original loan amount to the widget
+ m_loanAmountEdit->setValue(m_account.loanAmount());
+
+ if(!dontLeavePage) {
+ updateLoanInfo();
+ updateEditSummary();
+ }
+ }
+
+ if(!dontLeavePage)
+ KNewLoanWizard::next();
+
+ // These might have been set by KNewLoanWizard::next()
+ setAppropriate(m_previousPaymentsPage, false);
+ setAppropriate(m_recordPaymentPage, false);
+ // we never need to show this page
+ if(currentPage() == m_previousPaymentsPage)
+ KNewLoanWizard::next();
+}
+
+void KEditLoanWizard::slotCheckPageFinished(void)
+{
+ KNewLoanWizard::slotCheckPageFinished();
+
+ // if we're on one of the specific edit pages, the next button
+ // is enabled. If the values in the edit widgets are not
+ // appropriate, we just have to disable it.
+
+ if(currentPage() == m_effectiveDatePage) {
+ if(m_effectiveChangeDateEdit->date() < m_account.openingDate()
+ || m_effectiveChangeDateEdit->date() > QDate::currentDate())
+ nextButton()->setEnabled(false);
+
+ } else if(currentPage() == m_interestEditPage) {
+ if(!m_newPaymentEdit->isValid()
+ && !m_newInterestRateEdit->isValid())
+ nextButton()->setEnabled(false);
+ }
+}
+
+void KEditLoanWizard::updateEditSummary(void)
+{
+ updateSummary();
+ m_payment7->setText(m_summaryPeriodicPayment->text());
+ m_additionalFees7->setText(m_summaryAdditionalFees->text());
+ m_totalPayment7->setText(m_summaryTotalPeriodicPayment->text());
+ m_interestRate7->setText(m_summaryInterestRate->text());
+ m_startDateChanges->setText(KGlobal::locale()->formatDate(m_effectiveChangeDateEdit->date(), true));
+
+ // calculate the number of affected transactions
+ MyMoneyTransactionFilter filter(m_account.id());
+ filter.setDateFilter(m_effectiveChangeDateEdit->date(), QDate());
+
+ int count = 0;
+ QValueList<MyMoneyTransaction> list;
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ list = MyMoneyFile::instance()->transactionList(filter);
+
+ for(it = list.begin(); it != list.end(); ++it) {
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ int match = 0;
+ for(it_s = (*it).splits().begin(); it_s != (*it).splits().end(); ++it_s) {
+ // we only count those transactions that have an interest
+ // and amortization part
+ if((*it_s).action() == MyMoneySplit::ActionInterest)
+ match |= 0x01;
+ if((*it_s).action() == MyMoneySplit::ActionAmortization)
+ match |= 0x02;
+ }
+ if(match == 0x03)
+ count++;
+ }
+
+ m_affectedPayments->setText(QString().sprintf("%d", count));
+}
+
+const MyMoneySchedule KEditLoanWizard::schedule(void) const
+{
+ MyMoneySchedule sched = m_schedule;
+ sched.setTransaction(transaction());
+ sched.setOccurence(MyMoneySchedule::stringToOccurence(m_paymentFrequencyUnitEdit->currentText()));
+ if(m_nextDueDateEdit->date() < m_schedule.startDate())
+ sched.setStartDate(m_nextDueDateEdit->date());
+
+ return sched;
+}
+
+const MyMoneyAccount KEditLoanWizard::account(void) const
+{
+ MyMoneyAccountLoan acc(m_account);
+
+ if(m_interestOnReceptionButton->isChecked())
+ acc.setInterestCalculation(MyMoneyAccountLoan::paymentReceived);
+ else
+ acc.setInterestCalculation(MyMoneyAccountLoan::paymentDue);
+
+ acc.setFixedInterestRate(m_fixedInterestButton->isChecked());
+ acc.setFinalPayment(MyMoneyMoney(m_finalPaymentEdit->text()));
+ acc.setTerm(term());
+ acc.setPeriodicPayment(m_paymentEdit->value());
+ acc.setInterestRate(m_effectiveChangeDateEdit->date(), m_interestRateEdit->value());
+
+ acc.setPayee(m_payeeEdit->selectedItem());
+
+ if(m_variableInterestButton->isChecked()) {
+ acc.setNextInterestChange(m_interestChangeDateEdit->date());
+ acc.setInterestChangeFrequency(m_interestFrequencyAmountEdit->value(),
+ m_interestFrequencyUnitEdit->currentItem());
+ }
+
+ return acc;
+}
+
+const MyMoneyTransaction KEditLoanWizard::transaction() const
+{
+ MyMoneyTransaction t = KNewLoanWizard::transaction();
+ MyMoneySplit s = t.splitByAccount(QString("Phony-ID"));
+
+ s.setAccountId(m_account.id());
+ t.modifySplit(s);
+
+ return t;
+}
+
+#include "keditloanwizard.moc"
diff --git a/kmymoney2/dialogs/keditloanwizard.h b/kmymoney2/dialogs/keditloanwizard.h
new file mode 100644
index 0000000..0598248
--- /dev/null
+++ b/kmymoney2/dialogs/keditloanwizard.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ keditloanwizard.h - description
+ -------------------
+ begin : Wed Nov 12 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KEDITLOANWIZARD_H
+#define KEDITLOANWIZARD_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include <kmymoney/mymoneyaccount.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KEditLoanWizard : public KNewLoanWizard
+{
+ Q_OBJECT
+public:
+ KEditLoanWizard(const MyMoneyAccount& account, QWidget *parent=0, const char *name=0);
+ ~KEditLoanWizard();
+
+ /**
+ * This method returns the schedule for the payments. The account
+ * where the amortization should be transferred to is the one
+ * we currently edited with this wizard.
+ *
+ * @return MyMoneySchedule object for payments
+ */
+ const MyMoneySchedule schedule(void) const;
+
+ /**
+ * This method returns a MyMoneyAccount object with all data
+ * filled out as provided by the wizard.
+ *
+ * @return updated MyMoneyAccount object
+ */
+ const MyMoneyAccount account(void) const;
+
+
+ void loadWidgets(const MyMoneyAccount& acc);
+
+ const MyMoneyTransaction transaction() const;
+
+public slots:
+ void next();
+
+protected slots:
+ virtual void slotCheckPageFinished(void);
+
+protected:
+ void updateEditSummary(void);
+
+private:
+ //MyMoneyAccountLoan m_account;
+ MyMoneySchedule m_schedule;
+ int m_lastSelection;
+ bool m_fullyRepayLoan;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/keditscheduledlg.cpp b/kmymoney2/dialogs/keditscheduledlg.cpp
new file mode 100644
index 0000000..635d564
--- /dev/null
+++ b/kmymoney2/dialogs/keditscheduledlg.cpp
@@ -0,0 +1,558 @@
+/***************************************************************************
+ keditscheduledlg.cpp - description
+ -------------------
+ begin : Mon Sep 3 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtimer.h>
+#include <qwidgetlist.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvaluevector.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <klineedit.h>
+#include <knuminput.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/register.h>
+#include <kmymoney/transactionform.h>
+#include <kmymoney/transaction.h>
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneycombo.h>
+#include <kmymoney/kguiutils.h>
+#include <kmymoney/kmymoneyutils.h>
+
+#include "keditscheduledlg.h"
+#include "../kmymoney2.h"
+
+class KEditScheduleDlg::Private {
+public:
+ MyMoneySchedule m_schedule;
+ KMyMoneyRegister::Transaction* m_item;
+ QWidgetList m_tabOrderWidgets;
+ TransactionEditor* m_editor;
+ kMandatoryFieldGroup* m_requiredFields;
+};
+
+KEditScheduleDlg::KEditScheduleDlg(const MyMoneySchedule& schedule, QWidget *parent, const char *name) :
+ KEditScheduleDlgDecl(parent, name, true),
+ d(new Private)
+{
+ d->m_schedule = schedule;
+ d->m_editor = 0;
+
+ buttonOk->setGuiItem(KStdGuiItem::ok());
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+ buttonHelp->setGuiItem(KStdGuiItem::help());
+
+ d->m_requiredFields = new kMandatoryFieldGroup (this);
+ d->m_requiredFields->setOkButton(buttonOk); // button to be enabled when all fields present
+
+ // make sure, we have a tabbar with the form
+ // insert it after the horizontal line
+ m_paymentInformationLayout->insertWidget(2, m_form->tabBar(m_form->parentWidget()));
+
+ // we never need to see the register
+ m_register->hide();
+
+ // ... setup the form ...
+ m_form->setupForm(d->m_schedule.account());
+
+ // ... and the register ...
+ m_register->clear();
+
+ // ... now add the transaction to register and form ...
+ MyMoneyTransaction t = transaction();
+ d->m_item = KMyMoneyRegister::Register::transactionFactory(m_register, t, d->m_schedule.transaction().splits()[0], 0);
+ m_register->selectItem(d->m_item);
+ // show the account row
+ d->m_item->setShowRowInForm(0, true);
+
+ m_form->slotSetTransaction(d->m_item);
+
+ // setup widget contents
+ m_nameEdit->setText(d->m_schedule.name());
+
+ m_frequencyEdit->setCurrentItem(d->m_schedule.occurencePeriod());
+ if(m_frequencyEdit->currentItem() == -1)
+ m_frequencyEdit->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY);
+ slotFrequencyChanged(m_frequencyEdit->currentItem());
+ m_frequencyNoEdit->setValue(d->m_schedule.occurenceMultiplier());
+
+ // load option widgets
+ m_paymentMethodEdit->insertItem(i18n("Direct deposit"), MyMoneySchedule::STYPE_DIRECTDEPOSIT);
+ m_paymentMethodEdit->insertItem(i18n("Manual deposit"), MyMoneySchedule::STYPE_MANUALDEPOSIT);
+ m_paymentMethodEdit->insertItem(i18n("Direct debit"), MyMoneySchedule::STYPE_DIRECTDEBIT);
+ m_paymentMethodEdit->insertItem(i18n("Standing order"), MyMoneySchedule::STYPE_STANDINGORDER);
+ m_paymentMethodEdit->insertItem(i18n("Bank transfer"), MyMoneySchedule::STYPE_BANKTRANSFER);
+ m_paymentMethodEdit->insertItem(i18n("Write check"), MyMoneySchedule::STYPE_WRITECHEQUE);
+ m_paymentMethodEdit->insertItem(i18n("Other"), MyMoneySchedule::STYPE_OTHER);
+
+ MyMoneySchedule::paymentTypeE method = d->m_schedule.paymentType();
+ if(method == MyMoneySchedule::STYPE_ANY)
+ method = MyMoneySchedule::STYPE_OTHER;
+ m_paymentMethodEdit->setCurrentItem(method);
+
+ switch(d->m_schedule.weekendOption()) {
+ case MyMoneySchedule::MoveNothing:
+ m_weekendOptionEdit->setCurrentItem(0);
+ break;
+ case MyMoneySchedule::MoveFriday:
+ m_weekendOptionEdit->setCurrentItem(1);
+ break;
+ case MyMoneySchedule::MoveMonday:
+ m_weekendOptionEdit->setCurrentItem(2);
+ break;
+ }
+ m_estimateEdit->setChecked(!d->m_schedule.isFixed());
+ m_autoEnterEdit->setChecked(d->m_schedule.autoEnter());
+ m_endSeriesEdit->setChecked(d->m_schedule.willEnd());
+
+ m_endOptionsFrame->setEnabled(d->m_schedule.willEnd());
+ if(d->m_schedule.willEnd()) {
+ m_RemainingEdit->setValue(d->m_schedule.transactionsRemaining());
+ m_FinalPaymentEdit->setDate(d->m_schedule.endDate());
+ }
+
+ connect(m_RemainingEdit, SIGNAL(valueChanged(int)),
+ this, SLOT(slotRemainingChanged(int)));
+ connect(m_FinalPaymentEdit, SIGNAL(dateChanged(const QDate&)),
+ this, SLOT(slotEndDateChanged(const QDate&)));
+ connect(m_frequencyEdit, SIGNAL(itemSelected(int)),
+ this, SLOT(slotFrequencyChanged(int)));
+ connect(m_frequencyNoEdit, SIGNAL(valueChanged(int)),
+ this, SLOT(slotOccurenceMultiplierChanged(int)));
+ connect(buttonHelp, SIGNAL(clicked()), this, SLOT(slotShowHelp()));
+
+ // force the initial height to be as small as possible
+ QTimer::singleShot(0, this, SLOT(slotSetupSize()));
+
+ // we just hide the variation field for now and enable the logic
+ // once we have a respective member in the MyMoneySchedule object
+ m_variation->hide();
+}
+
+KEditScheduleDlg::~KEditScheduleDlg()
+{
+ delete d;
+}
+
+void KEditScheduleDlg::slotSetupSize(void)
+{
+ resize(width(), minimumSizeHint().height());
+}
+
+TransactionEditor* KEditScheduleDlg::startEdit(void)
+{
+ KMyMoneyRegister::SelectedTransactions list(m_register);
+ TransactionEditor* editor = d->m_item->createEditor(m_form, list, QDate());
+
+ // check that we use the same transaction commodity in all selected transactions
+ // if not, we need to update this in the editor's list. The user can also bail out
+ // of this operation which means that we have to stop editing here.
+ if(editor && !d->m_schedule.account().id().isEmpty()) {
+ if(!editor->fixTransactionCommodity(d->m_schedule.account())) {
+ // if the user wants to quit, we need to destroy the editor
+ // and bail out
+ delete editor;
+ editor = 0;
+ }
+ }
+
+ if(editor) {
+ connect(editor, SIGNAL(transactionDataSufficient(bool)), buttonOk, SLOT(setEnabled(bool)));
+ connect(editor, SIGNAL(escapePressed()), buttonCancel, SLOT(animateClick()));
+ connect(editor, SIGNAL(returnPressed()), buttonOk, SLOT(animateClick()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets()));
+ // connect(editor, SIGNAL(finishEdit(const KMyMoneyRegister::SelectedTransactions&)), this, SLOT(slotLeaveEditMode(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(editor, SIGNAL(createPayee(const QString&, QString&)), kmymoney2, SLOT(slotPayeeNew(const QString&, QString&)));
+ connect(editor, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotCategoryNew(MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(editor, SIGNAL(createSecurity(MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotInvestmentNew(MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets()));
+
+ // create the widgets, place them in the parent and load them with data
+ // setup tab order
+ d->m_tabOrderWidgets.clear();
+ KMyMoneyRegister::Action action = KMyMoneyRegister::ActionWithdrawal;
+ switch(d->m_schedule.type()) {
+ case MyMoneySchedule::TYPE_DEPOSIT:
+ action = KMyMoneyRegister::ActionDeposit;
+ break;
+ case MyMoneySchedule::TYPE_BILL:
+ action = KMyMoneyRegister::ActionWithdrawal;
+ break;
+ case MyMoneySchedule::TYPE_TRANSFER:
+ action = KMyMoneyRegister::ActionTransfer;
+ break;
+ default:
+ // if we end up here, we don't have a known schedule type (yet). in this case, we just glimpse
+ // into the transaction and determine the type. in case we don't have a transaction with splits
+ // we stick with the default action already set up
+ if(d->m_schedule.transaction().splits().count() > 0) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ bool isDeposit = false;
+ bool isTransfer = false;
+ for(it_s = d->m_schedule.transaction().splits().begin(); it_s != d->m_schedule.transaction().splits().end(); ++it_s) {
+ if((*it_s).accountId() == d->m_schedule.account().id()) {
+ isDeposit = !((*it_s).shares().isNegative());
+ } else {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.isAssetLiability() && d->m_schedule.transaction().splits().count() == 2) {
+ isTransfer = true;
+ }
+ }
+ }
+
+ if(isTransfer)
+ action = KMyMoneyRegister::ActionTransfer;
+ else if(isDeposit)
+ action = KMyMoneyRegister::ActionDeposit;
+ }
+ break;
+ }
+ editor->setup(d->m_tabOrderWidgets, d->m_schedule.account(), action);
+
+ // if it's not a check, then we need to clear
+ // a possibly assigned check number
+ if(d->m_schedule.paymentType() != MyMoneySchedule::STYPE_WRITECHEQUE) {
+ QWidget* w = editor->haveWidget("number");
+ if(w)
+ dynamic_cast<kMyMoneyLineEdit*>(w)->loadText(QString());
+ }
+
+ Q_ASSERT(!d->m_tabOrderWidgets.isEmpty());
+
+ // don't forget our three buttons and additional widgets
+ d->m_tabOrderWidgets.append(m_weekendOptionEdit);
+ d->m_tabOrderWidgets.append(m_estimateEdit);
+ d->m_tabOrderWidgets.append(m_variation);
+ d->m_tabOrderWidgets.append(m_autoEnterEdit);
+ d->m_tabOrderWidgets.append(m_endSeriesEdit);
+ d->m_tabOrderWidgets.append(m_RemainingEdit);
+ d->m_tabOrderWidgets.append(m_FinalPaymentEdit);
+
+ d->m_tabOrderWidgets.append(buttonOk);
+ d->m_tabOrderWidgets.append(buttonCancel);
+ d->m_tabOrderWidgets.append(buttonHelp);
+ d->m_tabOrderWidgets.append(m_nameEdit);
+ d->m_tabOrderWidgets.append(m_frequencyNoEdit);
+ d->m_tabOrderWidgets.append(m_frequencyEdit);
+ d->m_tabOrderWidgets.append(m_paymentMethodEdit);
+ d->m_tabOrderWidgets.append(m_form);
+
+ // install event filter in all taborder widgets
+ QWidget* w;
+ for(w = d->m_tabOrderWidgets.first(); w; w = d->m_tabOrderWidgets.next()) {
+ w->installEventFilter(this);
+ w->installEventFilter(editor);
+ }
+
+ // connect the postdate modification signal to our update routine
+ kMyMoneyDateInput* dateEdit = dynamic_cast<kMyMoneyDateInput*>(editor->haveWidget("postdate"));
+ if(dateEdit)
+ connect(dateEdit, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotPostDateChanged(const QDate&)));
+
+
+ m_nameEdit->setFocus();
+
+ // add the required fields to the mandatory group
+ d->m_requiredFields->add(m_nameEdit);
+ d->m_requiredFields->add(editor->haveWidget("account"));
+ d->m_requiredFields->add(editor->haveWidget("category"));
+
+ // fix labels
+ QLabel* label = dynamic_cast<QLabel*>(editor->haveWidget("date-label"));
+ if(label) {
+ label->setText(i18n("Next due date"));
+ }
+
+ d->m_editor = editor;
+ slotSetPaymentMethod(d->m_schedule.paymentType());
+
+ connect(m_paymentMethodEdit, SIGNAL(itemSelected(int)), this, SLOT(slotSetPaymentMethod(int)));
+ }
+
+ return editor;
+}
+
+void KEditScheduleDlg::accept(void)
+{
+ // Force the focus to be on the OK button. This will trigger creation
+ // of any unknown objects (payees, categories etc.)
+ buttonOk->setFocus();
+
+ // only accept if the button is really still enabled. We could end
+ // up here, if the user filled all fields, the focus is on the category
+ // field, but the category is not yet existant. When the user presses the
+ // OK button in this context, he will be asked if he wants to create
+ // the category or not. In case he decides no, we end up here with no
+ // category filled in, so we don't run through the final acceptance.
+ if(buttonOk->isEnabled())
+ KEditScheduleDlgDecl::accept();
+}
+
+const MyMoneySchedule& KEditScheduleDlg::schedule(void) const
+{
+ if(d->m_editor) {
+ MyMoneyTransaction t = transaction();
+ if(d->m_schedule.nextDueDate() != t.postDate())
+ d->m_schedule.setNextDueDate(t.postDate());
+ d->m_schedule.setTransaction(t);
+ d->m_schedule.setName(m_nameEdit->text());
+ d->m_schedule.setFixed(!m_estimateEdit->isChecked());
+ d->m_schedule.setOccurencePeriod(static_cast<MyMoneySchedule::occurenceE>(m_frequencyEdit->currentItem()));
+ d->m_schedule.setOccurenceMultiplier( m_frequencyNoEdit->value() );
+
+ switch(m_weekendOptionEdit->currentItem()) {
+ case 0:
+ d->m_schedule.setWeekendOption(MyMoneySchedule::MoveNothing);
+ break;
+ case 1:
+ d->m_schedule.setWeekendOption(MyMoneySchedule::MoveFriday);
+ break;
+ case 2:
+ d->m_schedule.setWeekendOption(MyMoneySchedule::MoveMonday);
+ break;
+ }
+
+ d->m_schedule.setType(MyMoneySchedule::TYPE_BILL);
+ KMyMoneyTransactionForm::TabBar* tabbar = dynamic_cast<KMyMoneyTransactionForm::TabBar*>(d->m_editor->haveWidget("tabbar"));
+ if(tabbar) {
+ switch(static_cast<KMyMoneyRegister::Action>(tabbar->currentTab())) {
+ case KMyMoneyRegister::ActionDeposit:
+ d->m_schedule.setType(MyMoneySchedule::TYPE_DEPOSIT);
+ break;
+ default:
+ case KMyMoneyRegister::ActionWithdrawal:
+ d->m_schedule.setType(MyMoneySchedule::TYPE_BILL);
+ break;
+ case KMyMoneyRegister::ActionTransfer:
+ d->m_schedule.setType(MyMoneySchedule::TYPE_TRANSFER);
+ break;
+ }
+ } else {
+ qDebug("No tabbar found in KEditScheduleDlg::schedule(). Defaulting type to BILL");
+ }
+
+ d->m_schedule.setAutoEnter(m_autoEnterEdit->isChecked());
+ d->m_schedule.setPaymentType(static_cast<MyMoneySchedule::paymentTypeE>(m_paymentMethodEdit->currentItem()));
+ if(m_endSeriesEdit->isEnabled() && m_endSeriesEdit->isChecked()) {
+ d->m_schedule.setEndDate(m_FinalPaymentEdit->date());
+ } else {
+ d->m_schedule.setEndDate(QDate());
+ }
+ }
+ return d->m_schedule;
+}
+
+MyMoneyTransaction KEditScheduleDlg::transaction(void) const
+{
+ MyMoneyTransaction t = d->m_schedule.transaction();
+
+ if(d->m_editor) {
+ d->m_editor->createTransaction(t, d->m_schedule.transaction(), d->m_schedule.transaction().splits()[0], false);
+ }
+
+ t.clearId();
+ t.setEntryDate(QDate());
+ return t;
+}
+
+bool KEditScheduleDlg::focusNextPrevChild(bool next)
+{
+ bool rc = false;
+
+ // qDebug("KEditScheduleDlg::focusNextPrevChild(editmode=%s)", m_inEditMode ? "true" : "false");
+ QWidget *w = 0;
+ QWidget *currentWidget;
+
+ w = qApp->focusWidget();
+ while(w && d->m_tabOrderWidgets.find(w) == -1) {
+ // qDebug("'%s' not in list, use parent", w->className());
+ w = w->parentWidget();
+ }
+ // if(w) qDebug("tab order is at '%s'", w->className());
+ currentWidget = d->m_tabOrderWidgets.current();
+ w = next ? d->m_tabOrderWidgets.next() : d->m_tabOrderWidgets.prev();
+
+ do {
+ if(!w) {
+ w = next ? d->m_tabOrderWidgets.first() : d->m_tabOrderWidgets.last();
+ }
+
+ if(w != currentWidget
+ && ((w->focusPolicy() & TabFocus) == TabFocus)
+ && w->isVisible() && w->isEnabled()) {
+ // qDebug("Selecting '%s' as focus", w->className());
+ w->setFocus();
+ rc = true;
+ break;
+ }
+ w = next ? d->m_tabOrderWidgets.next() : d->m_tabOrderWidgets.prev();
+ } while(w != currentWidget);
+
+ return rc;
+}
+
+void KEditScheduleDlg::resizeEvent(QResizeEvent* ev)
+{
+ m_register->resize(KMyMoneyRegister::DetailColumn);
+ m_form->resize(KMyMoneyTransactionForm::ValueColumn1);
+ KEditScheduleDlgDecl::resizeEvent(ev);
+}
+
+
+void KEditScheduleDlg::slotRemainingChanged(int value)
+{
+ // Make sure the required fields are set
+ kMyMoneyDateInput* dateEdit = dynamic_cast<kMyMoneyDateInput*>(d->m_editor->haveWidget("postdate"));
+ d->m_schedule.setNextDueDate(dateEdit->date());
+ d->m_schedule.setOccurencePeriod(static_cast<MyMoneySchedule::occurenceE>(m_frequencyEdit->currentItem()));
+ d->m_schedule.setOccurenceMultiplier(m_frequencyNoEdit->value());
+
+ if(d->m_schedule.transactionsRemaining() != value) {
+ m_FinalPaymentEdit->blockSignals(true);
+ m_FinalPaymentEdit->setDate(d->m_schedule.dateAfter(value));
+ m_FinalPaymentEdit->blockSignals(false);
+ }
+}
+
+void KEditScheduleDlg::slotEndDateChanged(const QDate& date)
+{
+ // Make sure the required fields are set
+ kMyMoneyDateInput* dateEdit = dynamic_cast<kMyMoneyDateInput*>(d->m_editor->haveWidget("postdate"));
+ d->m_schedule.setNextDueDate(dateEdit->date());
+ d->m_schedule.setOccurencePeriod(static_cast<MyMoneySchedule::occurenceE>(m_frequencyEdit->currentItem()));
+ d->m_schedule.setOccurenceMultiplier(m_frequencyNoEdit->value());
+
+ if(d->m_schedule.endDate() != date) {
+ d->m_schedule.setEndDate(date);
+ updateTransactionsRemaining();
+ }
+}
+
+void KEditScheduleDlg::slotPostDateChanged(const QDate& date)
+{
+ if(d->m_schedule.nextDueDate() != date) {
+ if (m_endOptionsFrame->isEnabled()) {
+ d->m_schedule.setNextDueDate(date);
+ d->m_schedule.setOccurenceMultiplier(m_frequencyNoEdit->value());
+ d->m_schedule.setOccurencePeriod(static_cast<MyMoneySchedule::occurenceE>(m_frequencyEdit->currentItem()));
+ d->m_schedule.setEndDate(m_FinalPaymentEdit->date());
+ updateTransactionsRemaining();
+ }
+ }
+}
+
+void KEditScheduleDlg::slotSetPaymentMethod(int item)
+{
+ kMyMoneyLineEdit* dateEdit = dynamic_cast<kMyMoneyLineEdit*>(d->m_editor->haveWidget("number"));
+ if(dateEdit) {
+ dateEdit->setShown(item == MyMoneySchedule::STYPE_WRITECHEQUE);
+
+ // hiding the label does not work, because the label underneath will shine
+ // through. So we either write the label or a blank
+ QLabel* label = dynamic_cast<QLabel *>(d->m_editor->haveWidget("number-label"));
+ if(label) {
+ label->setText((item == MyMoneySchedule::STYPE_WRITECHEQUE) ? i18n("Number") : " ");
+ }
+ }
+}
+
+void KEditScheduleDlg::slotFrequencyChanged(int item)
+{
+ m_endSeriesEdit->setEnabled(item != MyMoneySchedule::OCCUR_ONCE);
+ bool isEndSeries = m_endSeriesEdit->isChecked();
+ if(isEndSeries )
+ m_endOptionsFrame->setEnabled(item != MyMoneySchedule::OCCUR_ONCE);
+ switch( item )
+ {
+ case MyMoneySchedule::OCCUR_DAILY:
+ case MyMoneySchedule::OCCUR_WEEKLY:
+ case MyMoneySchedule::OCCUR_EVERYHALFMONTH:
+ case MyMoneySchedule::OCCUR_MONTHLY:
+ case MyMoneySchedule::OCCUR_YEARLY:
+ // Supports Frequency Number
+ m_frequencyNoEdit->setEnabled(true);
+ break;
+ default:
+ // Multiplier is always 1
+ m_frequencyNoEdit->setEnabled(false);
+ m_frequencyNoEdit->setValue(1);
+ break;
+ }
+ if ( isEndSeries && ( item != MyMoneySchedule::OCCUR_ONCE ) )
+ {
+ // Changing the frequency changes the number
+ // of remaining transactions
+ kMyMoneyDateInput* dateEdit = dynamic_cast<kMyMoneyDateInput*>(d->m_editor->haveWidget("postdate"));
+ d->m_schedule.setNextDueDate(dateEdit->date());
+ d->m_schedule.setOccurenceMultiplier(m_frequencyNoEdit->value());
+ d->m_schedule.setOccurencePeriod(static_cast<MyMoneySchedule::occurenceE>(item));
+ d->m_schedule.setEndDate(m_FinalPaymentEdit->date());
+ updateTransactionsRemaining();
+ }
+}
+
+void KEditScheduleDlg::slotOccurenceMultiplierChanged(int multiplier)
+{
+ // Make sure the required fields are set
+ int oldOccurenceMultiplier = d->m_schedule.occurenceMultiplier();
+ if ( multiplier != oldOccurenceMultiplier )
+ {
+ if (m_endOptionsFrame->isEnabled())
+ {
+ kMyMoneyDateInput* dateEdit = dynamic_cast<kMyMoneyDateInput*>(d->m_editor->haveWidget("postdate"));
+ d->m_schedule.setNextDueDate(dateEdit->date());
+ d->m_schedule.setOccurenceMultiplier(multiplier);
+ d->m_schedule.setOccurencePeriod(static_cast<MyMoneySchedule::occurenceE>(m_frequencyEdit->currentItem()));
+ d->m_schedule.setEndDate(m_FinalPaymentEdit->date());
+ updateTransactionsRemaining();
+ }
+ }
+}
+
+void KEditScheduleDlg::updateTransactionsRemaining(void)
+{
+ int remain = d->m_schedule.transactionsRemaining();
+ if ( remain != m_RemainingEdit->value() )
+ {
+ m_RemainingEdit->blockSignals(true);
+ m_RemainingEdit->setValue(remain);
+ m_RemainingEdit->blockSignals(false);
+ }
+}
+
+void KEditScheduleDlg::slotShowHelp(void)
+{
+ kapp->invokeHelp("details.schedules.intro");
+}
+
+#include <keditscheduledlg.moc>
diff --git a/kmymoney2/dialogs/keditscheduledlg.h b/kmymoney2/dialogs/keditscheduledlg.h
new file mode 100644
index 0000000..94c3101
--- /dev/null
+++ b/kmymoney2/dialogs/keditscheduledlg.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ keditscheduledlg.h - description
+ -------------------
+ begin : Mon Sep 3 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KEDITSCHEDULEDLG_H
+#define KEDITSCHEDULEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include "../dialogs/keditscheduledlgdecl.h"
+
+class TransactionEditor;
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KEditScheduleDlg : public KEditScheduleDlgDecl
+{
+ Q_OBJECT
+public:
+ /**
+ * Standard QWidget constructor.
+ **/
+ KEditScheduleDlg(const MyMoneySchedule& schedule, QWidget *parent=0, const char *name=0);
+
+ /**
+ * Standard destructor.
+ **/
+ ~KEditScheduleDlg();
+
+ TransactionEditor* startEdit(void);
+
+ /**
+ * Returns the edited schedule.
+ *
+ * @return MyMoneySchedule The schedule details.
+ **/
+ const MyMoneySchedule& schedule(void) const;
+
+protected:
+ MyMoneyTransaction transaction(void) const;
+ /**
+ * This method adjusts @a _date according to the rules specified by
+ * the schedule's weekend option.
+ */
+ QDate adjustDate(const QDate& _date) const;
+
+ /// Overridden for internal reasons. No API changes.
+ bool focusNextPrevChild(bool next);
+
+ /// Overridden for internal reasons. No API changes.
+ void resizeEvent(QResizeEvent* ev);
+
+private slots:
+ void slotSetupSize(void);
+ void slotRemainingChanged(int);
+ void slotEndDateChanged(const QDate& date);
+ void slotPostDateChanged(const QDate& date);
+ void slotSetPaymentMethod(int);
+ void slotFrequencyChanged(int item);
+ void slotShowHelp(void);
+ void slotOccurenceMultiplierChanged(int mult);
+
+ /// Overridden for internal reasons. No API changes.
+ void accept(void);
+
+private:
+ /**
+ * Helper method to recalculate and update Transactions Remaining
+ * when other values are changed
+ */
+ void updateTransactionsRemaining(void);
+
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/keditscheduledlgdecl.ui b/kmymoney2/dialogs/keditscheduledlgdecl.ui
new file mode 100644
index 0000000..8555c58
--- /dev/null
+++ b/kmymoney2/dialogs/keditscheduledlgdecl.ui
@@ -0,0 +1,532 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KEditScheduleDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KEditScheduleDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>798</width>
+ <height>640</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Edit Scheduled transaction</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Schedule name:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>m_nameEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Frequency:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>m_frequencyNoEdit</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Number of selected periods between entries</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyOccurencePeriodCombo">
+ <property name="name">
+ <cstring>m_frequencyEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_paymentInformation</cstring>
+ </property>
+ <property name="title">
+ <string>Payment information</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Payment method</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo">
+ <property name="name">
+ <cstring>m_paymentMethodEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="KMyMoneyRegister::Register">
+ <column>
+ <property name="text">
+ <string>Security</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Details</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>C</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Payment</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Deposit</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Quantity</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Balance</string>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_register</cstring>
+ </property>
+ <property name="numRows">
+ <number>0</number>
+ </property>
+ <property name="numCols">
+ <number>12</number>
+ </property>
+ </widget>
+ <widget class="KMyMoneyTransactionForm::TransactionForm">
+ <property name="name">
+ <cstring>m_form</cstring>
+ </property>
+ <property name="numRows">
+ <number>5</number>
+ </property>
+ <property name="numCols">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Do nothing</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Change the date to the previous Friday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Change the date to the next Monday</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_weekendOptionEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>If this schedule occurs on the weekend:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_estimateEdit</cstring>
+ </property>
+ <property name="text">
+ <string>The amount is an estimate because it varies for each payment</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_variation</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_autoEnterEdit</cstring>
+ </property>
+ <property name="text">
+ <string>Enter this schedule into the register automatically when it is due</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_endSeriesEdit</cstring>
+ </property>
+ <property name="text">
+ <string>This schedule will end at some time</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_endOptionsFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_endLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Number of transactions remaining:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>m_RemainingEdit</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>9999</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_endLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Date of final transaction:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_FinalPaymentEdit</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10_3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>280</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KEditScheduleDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>m_endSeriesEdit</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_endOptionsFrame</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KEditScheduleDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>m_estimateEdit</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_variation</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kendingbalancedlg.cpp b/kmymoney2/dialogs/kendingbalancedlg.cpp
new file mode 100644
index 0000000..0760cc2
--- /dev/null
+++ b/kmymoney2/dialogs/kendingbalancedlg.cpp
@@ -0,0 +1,611 @@
+/***************************************************************************
+ kendingbalancedlg.cpp
+ -------------------
+ copyright : (C) 2000,2003 by Michael Edwardes, Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kactivelabel.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kendingbalancedlg.h"
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+
+#include "../dialogs/kcurrencycalculator.h"
+
+class KEndingBalanceDlg::Private
+{
+public:
+ MyMoneyTransaction m_tInterest;
+ MyMoneyTransaction m_tCharges;
+ MyMoneyAccount m_account;
+ QMap<QWidget*, QString> m_helpAnchor;
+};
+
+class KEndingBalanceLoanDlg::Private
+{
+public:
+ MyMoneyTransaction m_tInterest;
+ MyMoneyTransaction m_tCharges;
+ MyMoneyAccountLoan m_account;
+ QMap<QWidget*, QString> m_helpAnchor;
+};
+
+KEndingBalanceDlg::KEndingBalanceDlg(const MyMoneyAccount& account, QWidget *parent, const char *name) :
+ KEndingBalanceDlgDecl(parent, name, true),
+ d(new Private)
+{
+ QString value;
+ MyMoneyMoney endBalance, startBalance;
+
+ d->m_account = account;
+
+ MyMoneySecurity currency = MyMoneyFile::instance()->security(account.currencyId());
+ m_enterInformationLabel->setText(QString("<qt>")+i18n("Please enter the following fields with the information as you find them on your statement. Make sure to enter all values in <b>%1</b>.").arg(currency.name())+QString("</qt>"));
+
+ m_statementDate->setDate(QDate::currentDate());
+
+ // If the previous reconciliation was postponed,
+ // we show a different first page
+ value = account.value("lastReconciledBalance");
+ if(value.isEmpty()) {
+ // if the last statement has been entered long enough ago (more than one month),
+ // then take the last statement date and add one month and use that as statement
+ // date.
+ QDate lastStatementDate = account.lastReconciliationDate();
+ if(lastStatementDate.addMonths(1) < QDate::currentDate()) {
+ m_statementDate->setDate(lastStatementDate.addMonths(1));
+ }
+
+ slotUpdateBalances();
+
+ setAppropriate(m_startPageCheckings, true);
+ setAppropriate(m_pagePreviousPostpone, false);
+ setAppropriate(m_interestChargeCheckings, true);
+ setFinishEnabled(m_interestChargeCheckings, true);
+ } else {
+ setAppropriate(m_startPageCheckings, false);
+ setAppropriate(m_pagePreviousPostpone, true);
+ removePage(m_interestChargeCheckings);
+ setFinishEnabled(m_statementInfoPageCheckings, true);
+ // make sure, we show the correct start page
+ showPage(m_pagePreviousPostpone);
+
+ MyMoneyMoney factor(1,1);
+ if(d->m_account.accountGroup() == MyMoneyAccount::Liability)
+ factor = -factor;
+
+ startBalance = MyMoneyMoney(value)*factor;
+ value = account.value("statementBalance");
+ endBalance = MyMoneyMoney(value)*factor;
+
+ m_previousBalance->setValue(startBalance);
+ m_endingBalance->setValue(endBalance);
+ }
+
+ // We don't need to add the default into the list (see ::help() why)
+ // m_helpAnchor[m_startPageCheckings] = QString("");
+ d->m_helpAnchor[m_interestChargeCheckings] = QString("details.reconcile.wizard.interest");
+ d->m_helpAnchor[m_statementInfoPageCheckings] = QString("details.reconcile.wizard.statement");
+
+ value = account.value("statementDate");
+ if(!value.isEmpty())
+ m_statementDate->setDate(QDate::fromString(value, Qt::ISODate));
+
+ m_lastStatementDate->setText(QString());
+ if(account.lastReconciliationDate().isValid()) {
+ m_lastStatementDate->setText(i18n("Last reconciled statement: %1")
+ .arg(KGlobal::locale()->formatDate(account.lastReconciliationDate(), true)));
+ }
+
+ // remove all unwanted pages
+ removePage(m_startPageLoan);
+ removePage(m_checkPaymentsPage);
+ removePage(m_adjustmentTransactionPage);
+
+ // connect the signals with the slots
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadEditWidgets()));
+ connect(m_payeeEdit, SIGNAL(createItem(const QString&, QString&)), this, SIGNAL(createPayee(const QString&, QString&)));
+ connect(m_interestCategoryEdit, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateInterestCategory(const QString&, QString&)));
+ connect(m_chargesCategoryEdit, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateChargesCategory(const QString&, QString&)));
+
+ connect(m_interestEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_interestCategoryEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_chargesEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_chargesCategoryEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_statementDate, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotUpdateBalances()));
+
+ slotReloadEditWidgets();
+
+ // preset payee if possible
+ try {
+ // if we find a payee with the same name as the institution,
+ // than this is what we use as payee.
+ if(!d->m_account.institutionId().isEmpty()) {
+ MyMoneyInstitution inst = MyMoneyFile::instance()->institution(d->m_account.institutionId());
+ MyMoneyPayee payee = MyMoneyFile::instance()->payeeByName(inst.name());
+ m_payeeEdit->setSelectedItem(payee.id());
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+KEndingBalanceDlg::~KEndingBalanceDlg()
+{
+ delete d;
+}
+
+void KEndingBalanceDlg::slotUpdateBalances(void)
+{
+ MYMONEYTRACER(tracer);
+
+ // determine the beginning balance and ending balance based on the following
+ // forumulas:
+ //
+ // end balance = current balance - sum(all non cleared transactions)
+ // - sum(all cleared transactions posted
+ // after statement date)
+ // start balance = end balance - sum(all cleared transactions
+ // up to statement date)
+ MyMoneyTransactionFilter filter(d->m_account.id());
+ filter.addState(MyMoneyTransactionFilter::notReconciled);
+ filter.addState(MyMoneyTransactionFilter::cleared);
+ filter.setReportAllSplits(true);
+
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> > transactionList;
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::const_iterator it;
+
+ // retrieve the list from the engine
+ MyMoneyFile::instance()->transactionList(transactionList, filter);
+
+ MyMoneyMoney balance = MyMoneyFile::instance()->balance(d->m_account.id());
+ MyMoneyMoney factor(1,1);
+ if(d->m_account.accountGroup() == MyMoneyAccount::Liability)
+ factor = -factor;
+
+ MyMoneyMoney endBalance, startBalance;
+ balance = balance * factor;
+ endBalance = startBalance = balance;
+
+ tracer.printf("total balance = %s", endBalance.formatMoney("", 2).data());
+
+ for(it = transactionList.begin(); it != transactionList.end(); ++it) {
+ const MyMoneySplit& split = (*it).second;
+ balance -= split.shares() * factor;
+ if((*it).first.postDate() > m_statementDate->date()) {
+ tracer.printf("Reducing balances by %s because postdate of %s/%s(%s) is past statement date", (split.shares() * factor).formatMoney("", 2).data(), (*it).first.id().data(),split.id().data(), (*it).first.postDate().toString(Qt::ISODate).data());
+ endBalance -= split.shares() * factor;
+ startBalance -= split.shares() * factor;
+ } else {
+ switch(split.reconcileFlag()) {
+ case MyMoneySplit::NotReconciled:
+ tracer.printf("Reducing balances by %s because %s/%s(%s) is not reconciled", (split.shares() * factor).formatMoney("", 2).data(), (*it).first.id().data(), split.id().data(), (*it).first.postDate().toString(Qt::ISODate).data());
+ endBalance -= split.shares() * factor;
+ startBalance -= split.shares() * factor;
+ break;
+ case MyMoneySplit::Cleared:
+ tracer.printf("Reducing start balance by %s because %s/%s(%s) is cleared", (split.shares() * factor).formatMoney("", 2).data(), (*it).first.id().data(), split.id().data(), (*it).first.postDate().toString(Qt::ISODate).data());
+ startBalance -= split.shares() * factor;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ m_previousBalance->setValue(startBalance);
+ m_endingBalance->setValue(endBalance);
+ tracer.printf("total balance = %s", endBalance.formatMoney("", 2).data());
+ tracer.printf("start balance = %s", startBalance.formatMoney("", 2).data());
+
+ m_interestDateEdit->setDate(m_statementDate->date());
+ m_chargesDateEdit->setDate(m_statementDate->date());
+}
+
+void KEndingBalanceDlg::accept(void)
+{
+ if(createTransaction(d->m_tInterest, -1, m_interestEdit, m_interestCategoryEdit, m_interestDateEdit)
+ && createTransaction(d->m_tCharges, 1, m_chargesEdit, m_chargesCategoryEdit, m_chargesDateEdit))
+ KEndingBalanceDlgDecl::accept();
+}
+
+void KEndingBalanceDlg::slotCreateInterestCategory(const QString& txt, QString& id)
+{
+ createCategory(txt, id, MyMoneyFile::instance()->income());
+}
+
+void KEndingBalanceDlg::slotCreateChargesCategory(const QString& txt, QString& id)
+{
+ createCategory(txt, id, MyMoneyFile::instance()->expense());
+}
+
+void KEndingBalanceDlg::createCategory(const QString& txt, QString& id, const MyMoneyAccount& parent)
+{
+ MyMoneyAccount acc;
+ acc.setName(txt);
+
+ emit createCategory(acc, parent);
+
+ id = acc.id();
+}
+
+const MyMoneyMoney KEndingBalanceDlg::endingBalance(void) const
+{
+ return adjustedReturnValue(m_endingBalance->value());
+}
+
+const MyMoneyMoney KEndingBalanceDlg::previousBalance(void) const
+{
+ return adjustedReturnValue(m_previousBalance->value());
+}
+
+const MyMoneyMoney KEndingBalanceDlg::adjustedReturnValue(const MyMoneyMoney& v) const
+{
+ return d->m_account.accountGroup() == MyMoneyAccount::Liability ? -v : v;
+}
+
+void KEndingBalanceDlg::slotReloadEditWidgets(void)
+{
+ QString payeeId, interestId, chargesId;
+
+ // keep current selected items
+ payeeId = m_payeeEdit->selectedItem();
+ interestId = m_interestCategoryEdit->selectedItem();
+ chargesId = m_chargesCategoryEdit->selectedItem();
+
+ // load the payee and category widgets with data from the engine
+ m_payeeEdit->loadPayees(MyMoneyFile::instance()->payeeList());
+
+ // a user request to show all categories in both selectors due to a valid use case.
+ AccountSet aSet;
+ aSet.addAccountGroup(MyMoneyAccount::Expense);
+ aSet.addAccountGroup(MyMoneyAccount::Income);
+ aSet.load(m_interestCategoryEdit->selector());
+ aSet.load(m_chargesCategoryEdit->selector());
+
+ // reselect currently selected items
+ if(!payeeId.isEmpty())
+ m_payeeEdit->setSelectedItem(payeeId);
+ if(!interestId.isEmpty())
+ m_interestCategoryEdit->setSelectedItem(interestId);
+ if(!chargesId.isEmpty())
+ m_chargesCategoryEdit->setSelectedItem(chargesId);
+}
+
+void KEndingBalanceDlg::slotCheckPageFinished(void)
+{
+ nextButton()->setEnabled(true);
+ finishButton()->setEnabled(true);
+
+ if(currentPage() == m_interestChargeCheckings) {
+ int cnt1, cnt2;
+ cnt1 = !m_interestEdit->value().isZero() + !m_interestCategoryEdit->selectedItem().isEmpty();
+ cnt2 = !m_chargesEdit->value().isZero() + !m_chargesCategoryEdit->selectedItem().isEmpty();
+ if(cnt1 == 1 || cnt2 == 1) {
+ finishButton()->setEnabled(false);
+ nextButton()->setEnabled(false);
+ }
+ }
+}
+
+const MyMoneyTransaction KEndingBalanceDlg::interestTransaction(void)
+{
+ return d->m_tInterest;
+}
+
+const MyMoneyTransaction KEndingBalanceDlg::chargeTransaction(void)
+{
+ return d->m_tCharges;
+}
+
+bool KEndingBalanceDlg::createTransaction(MyMoneyTransaction &t, const int sign, kMyMoneyEdit *amountEdit, KMyMoneyCategory *categoryEdit, kMyMoneyDateInput* dateEdit)
+{
+ t = MyMoneyTransaction();
+
+ if(!amountEdit->isValid() || categoryEdit->selectedItem().isEmpty() || !dateEdit->date().isValid())
+ return true;
+
+ MyMoneySplit s1, s2;
+ MyMoneyMoney val = amountEdit->value() * MyMoneyMoney(sign, 1);
+ try {
+ t.setPostDate(dateEdit->date());
+ t.setCommodity(d->m_account.currencyId());
+
+ s1.setPayeeId(m_payeeEdit->selectedItem());
+ s1.setReconcileFlag(MyMoneySplit::Cleared);
+ s1.setAccountId(d->m_account.id());
+ s1.setValue(-val);
+ s1.setShares(-val);
+
+ s2 = s1;
+ s2.setAccountId(categoryEdit->selectedItem());
+ s2.setValue(val);
+
+ t.addSplit(s1);
+ t.addSplit(s2);
+
+ QMap<QString, MyMoneyMoney> priceInfo; // just empty
+ MyMoneyMoney shares;
+ if(!KCurrencyCalculator::setupSplitPrice(shares, t, s2, priceInfo, this)) {
+ t = MyMoneyTransaction();
+ return false;
+ }
+
+ s2.setShares(shares);
+ t.modifySplit(s2);
+
+ } catch(MyMoneyException *e) {
+ qDebug("%s", e->what().data());
+ delete e;
+ t = MyMoneyTransaction();
+ return false;
+ }
+
+ return true;
+}
+
+void KEndingBalanceDlg::help(void)
+{
+ QString anchor = d->m_helpAnchor[currentPage()];
+ if(anchor.isEmpty())
+ anchor = QString("details.reconcile.whatis");
+
+ kapp->invokeHelp(anchor);
+}
+
+KEndingBalanceLoanDlg::KEndingBalanceLoanDlg(const MyMoneyAccount& account, QWidget *parent, const char *name) :
+ KEndingBalanceDlgDecl(parent, name, true),
+ d(new Private)
+{
+ d->m_account = account;
+ QDate value = account.lastReconciliationDate();
+ if(value.isValid())
+ m_startDateEdit->setDate(value.addDays(1));
+ else
+ m_startDateEdit->setDate(d->m_account.openingDate());
+
+ // make sure, we show the correct start page
+ showPage(m_startPageLoan);
+
+ // enable the finish button on the last page
+ setAppropriate(m_checkPaymentsPage, true);
+
+ // remove all unwanted pages
+ removePage(m_startPageCheckings);
+ removePage(m_statementInfoPageCheckings);
+ removePage(m_pagePreviousPostpone);
+ removePage(m_interestChargeCheckings);
+
+ // connect the signals with the slots
+ connect(m_amortizationTotalEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_interestTotalEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_accountEdit, SIGNAL(stateChanged(void)), this, SLOT(slotCheckPageFinished(void)));
+ connect(m_categoryEdit, SIGNAL(stateChanged(void)), this, SLOT(slotCheckPageFinished(void)));
+}
+
+KEndingBalanceLoanDlg::~KEndingBalanceLoanDlg()
+{
+}
+
+void KEndingBalanceLoanDlg::slotCheckPageFinished(void)
+{
+ nextButton()->setEnabled(true);
+ finishButton()->setEnabled(true);
+
+ if(currentPage() == m_checkPaymentsPage) {
+ MyMoneyMoney interest = totalInterest(m_startDateEdit->date(), m_endDateEdit->date());
+ MyMoneyMoney amortization = totalAmortization(m_startDateEdit->date(), m_endDateEdit->date());
+
+ if(interest == m_interestTotalEdit->value()
+ && amortization == m_amortizationTotalEdit->value()) {
+ if(indexOf(m_adjustmentTransactionPage) != -1) {
+ removePage(m_adjustmentTransactionPage);
+ // the following line forces to update the buttons
+ showPage(m_checkPaymentsPage);
+ nextButton()->setEnabled(true);
+ finishButton()->setEnabled(true);
+ }
+ } else {
+ if(indexOf(m_adjustmentTransactionPage) == -1) {
+ addPage(m_adjustmentTransactionPage, i18n("Adjustment transaction"));
+ // the following line forces to update the buttons
+ showPage(m_checkPaymentsPage);
+ }
+ }
+ } else if(currentPage() == m_adjustmentTransactionPage) {
+ if(m_accountEdit->selectedItems().count() == 0) {
+ nextButton()->setEnabled(false);
+ finishButton()->setEnabled(false);
+
+ } else if(m_categoryEdit->isEnabled()
+ && m_categoryEdit->selectedItems().count() == 0) {
+ nextButton()->setEnabled(false);
+ finishButton()->setEnabled(false);
+ }
+ }
+}
+
+const MyMoneyMoney KEndingBalanceLoanDlg::totalInterest(const QDate& start, const QDate& end) const
+{
+ MyMoneyMoney interest;
+ MyMoneyTransactionFilter filter(d->m_account.id());
+ filter.setDateFilter(start, end);
+
+ QValueList<MyMoneyTransaction> list = MyMoneyFile::instance()->transactionList(filter);
+ QValueList<MyMoneyTransaction>::ConstIterator it_t;
+
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ if((*it_s).action() == MyMoneySplit::ActionInterest) {
+ interest += (*it_s).value();
+ }
+ }
+ }
+ return interest;
+}
+
+const MyMoneyMoney KEndingBalanceLoanDlg::totalAmortization(const QDate& start, const QDate& end) const
+{
+ MyMoneyMoney amortization;
+ MyMoneyMoney adjust(1,1);
+ MyMoneyTransactionFilter filter(d->m_account.id());
+ filter.setDateFilter(start, end);
+
+ if(d->m_account.accountType() == MyMoneyAccount::AssetLoan)
+ adjust = -adjust;
+
+ QValueList<MyMoneyTransaction> list = MyMoneyFile::instance()->transactionList(filter);
+ QValueList<MyMoneyTransaction>::ConstIterator it_t;
+
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ if((*it_s).accountId() == d->m_account.id()
+ && (*it_s).action() == MyMoneySplit::ActionAmortization
+ && ((*it_s).value() * MyMoneyMoney(adjust, 1)).isPositive()) {
+ amortization += (*it_s).value();
+ }
+ }
+ }
+ // make sure to return a positive number
+ return amortization * adjust;
+}
+
+void KEndingBalanceLoanDlg::next(void)
+{
+ bool dontLeavePage = false;
+
+ if(currentPage() == m_startPageLoan) {
+ MyMoneyMoney interest = totalInterest(m_startDateEdit->date(), m_endDateEdit->date());
+ MyMoneyMoney amortization = totalAmortization(m_startDateEdit->date(), m_endDateEdit->date());
+
+ m_loanOverview->setText(i18n("KMyMoney has calculated the following amounts for "
+ "interest and amortization according to recorded payments "
+ "between %1 and %2.")
+ .arg(KGlobal::locale()->formatDate(m_startDateEdit->date(), true))
+ .arg(KGlobal::locale()->formatDate(m_endDateEdit->date(), true)));
+
+ // preload widgets with calculated values if they are empty
+ if(m_amortizationTotalEdit->value().isZero() && !amortization.isZero())
+ m_amortizationTotalEdit->setValue(amortization);
+ if(m_interestTotalEdit->value().isZero() && !interest.isZero())
+ m_interestTotalEdit->setValue(interest);
+
+ } else if(currentPage() == m_checkPaymentsPage) {
+ AccountSet assetSet, incomeSet;
+ assetSet.addAccountGroup(MyMoneyAccount::Asset);
+ incomeSet.addAccountGroup(MyMoneyAccount::Income);
+ assetSet.load(m_accountEdit);
+ incomeSet.load(m_categoryEdit);
+#if 0
+ m_accountEdit->loadList(static_cast<KMyMoneyUtils::categoryTypeE>(KMyMoneyUtils::asset | KMyMoneyUtils::liability));
+ m_categoryEdit->loadList(static_cast<KMyMoneyUtils::categoryTypeE>(KMyMoneyUtils::income | KMyMoneyUtils::expense));
+#endif
+ m_categoryEdit->setEnabled(false);
+
+ MyMoneyMoney interest = totalInterest(m_startDateEdit->date(), m_endDateEdit->date());
+ if(interest != m_interestTotalEdit->value()) {
+ m_categoryEdit->setEnabled(true);
+ }
+ }
+
+ if(!dontLeavePage)
+ KEndingBalanceDlgDecl::next();
+
+ slotCheckPageFinished();
+}
+
+const MyMoneyTransaction KEndingBalanceLoanDlg::adjustmentTransaction(void) const
+{
+ MyMoneyTransaction t;
+
+ MyMoneyMoney interest = totalInterest(m_startDateEdit->date(), m_endDateEdit->date());
+ MyMoneyMoney amortization = totalAmortization(m_startDateEdit->date(), m_endDateEdit->date());
+
+ if(interest != m_interestTotalEdit->value()
+ || amortization != m_amortizationTotalEdit->value()) {
+ MyMoneySplit sAccount, sAmortization, sInterest;
+ int adjust = 1;
+
+ if(d->m_account.accountType() == MyMoneyAccount::AssetLoan)
+ adjust = -1;
+
+ // fix sign if asset
+ interest = interest * MyMoneyMoney(adjust,1);
+ amortization = amortization * MyMoneyMoney(adjust,1);
+
+ sAmortization.setValue((m_amortizationTotalEdit->value() - amortization) * MyMoneyMoney(adjust,1));
+ sInterest.setValue((m_interestTotalEdit->value() - interest) * MyMoneyMoney(adjust,1));
+ sAccount.setValue( -(sAmortization.value() + sInterest.value()));
+
+ try {
+ sAmortization.setAccountId(d->m_account.id());
+ sAmortization.setPayeeId(d->m_account.payee());
+ sAccount.setAccountId(m_accountEdit->selectedItems()[0]);
+ sAccount.setPayeeId(d->m_account.payee());
+ if(m_categoryEdit->isEnabled())
+ sInterest.setAccountId(m_categoryEdit->selectedItems()[0]);
+
+ sAccount.setMemo(i18n("Adjustment transaction"));
+ sAmortization.setMemo(sAccount.memo());
+ sInterest.setMemo(sAccount.memo());
+
+ sAccount.setAction(MyMoneySplit::ActionAmortization);
+ sAmortization.setAction(MyMoneySplit::ActionAmortization);
+ sInterest.setAction(MyMoneySplit::ActionInterest);
+
+ t.addSplit(sAccount);
+ t.addSplit(sAmortization);
+ if(!sInterest.value().isZero())
+ t.addSplit(sInterest);
+
+ t.setPostDate(m_endDateEdit->date());
+
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to create adjustment transaction for loan reconciliation: %s", e->what().data());
+ delete e;
+ return MyMoneyTransaction();
+ }
+ }
+ return t;
+}
+
+void KEndingBalanceLoanDlg::help(void)
+{
+ QString anchor = d->m_helpAnchor[currentPage()];
+ if(anchor.isEmpty())
+ anchor = QString("details.reconcile.whatis");
+
+ kapp->invokeHelp(anchor);
+}
+
+#include "kendingbalancedlg.moc"
+
diff --git a/kmymoney2/dialogs/kendingbalancedlg.h b/kmymoney2/dialogs/kendingbalancedlg.h
new file mode 100644
index 0000000..3b9de00
--- /dev/null
+++ b/kmymoney2/dialogs/kendingbalancedlg.h
@@ -0,0 +1,147 @@
+/***************************************************************************
+ kendingbalancedlg.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KENDINGBALANCEDLG_H
+#define KENDINGBALANCEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qdialog.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class kMyMoneyEdit;
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/mymoneyaccount.h>
+#include "../dialogs/kendingbalancedlgdecl.h"
+
+/**
+ * This dialog is wizard based and used to enter additional
+ * information required to start the reconciliation process.
+ * This version implements the behaviour for checkings,
+ * savings and credit card accounts.
+ *
+ * @author Thomas Baumgart
+ */
+class KEndingBalanceDlg : public KEndingBalanceDlgDecl
+{
+ Q_OBJECT
+public:
+ KEndingBalanceDlg(const MyMoneyAccount& account, QWidget *parent=0, const char *name=0);
+ ~KEndingBalanceDlg();
+
+ const MyMoneyMoney endingBalance(void) const;
+ const MyMoneyMoney previousBalance(void) const;
+ const QDate statementDate(void) const { return m_statementDate->date(); };
+
+ const MyMoneyTransaction interestTransaction(void);
+ const MyMoneyTransaction chargeTransaction(void);
+
+protected:
+ bool createTransaction(MyMoneyTransaction& t, const int sign, kMyMoneyEdit *amountEdit, KMyMoneyCategory *categoryEdit, kMyMoneyDateInput* dateEdit);
+ const MyMoneyMoney adjustedReturnValue(const MyMoneyMoney& v) const;
+ void createCategory(const QString& txt, QString& id, const MyMoneyAccount& parent);
+
+protected slots:
+ void slotCheckPageFinished(void);
+ void slotReloadEditWidgets(void);
+ void help(void);
+ void slotCreateInterestCategory(const QString& txt, QString& id);
+ void slotCreateChargesCategory(const QString& txt, QString& id);
+ void accept(void);
+ void slotUpdateBalances(void);
+
+signals:
+ /**
+ * proxy signal for KMyMoneyPayeeCombo::createItem(const QString&, QString&)
+ */
+ void createPayee(const QString&, QString&);
+
+ /**
+ * emit when a category is about to be created
+ */
+ void createCategory(MyMoneyAccount& acc, const MyMoneyAccount& parent);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+/**
+ * This dialog is wizard based and used to enter additional
+ * information required to start the reconciliation process.
+ * This version is implements the behaviour for loan accounts.
+ */
+class KEndingBalanceLoanDlg : public KEndingBalanceDlgDecl
+{
+ Q_OBJECT
+public:
+ KEndingBalanceLoanDlg(const MyMoneyAccount& account, QWidget *parent=0, const char *name=0);
+ ~KEndingBalanceLoanDlg();
+
+ /**
+ * This method returns the adjustment transaction if one
+ * has been created. If not, an empty transaction will be returned.
+ */
+ const MyMoneyTransaction adjustmentTransaction(void) const;
+
+ /**
+ * This method returns the starting date of the statement as provided
+ * by the user. The value returned is only valid if the dialog returned
+ * with QDialog::accept.
+ */
+ const QDate startDate(void) const { return m_startDateEdit->date(); };
+
+ /**
+ * This method returns the ending date of the statement as provided
+ * by the user. The value returned is only valid if the dialog returned
+ * with QDialog::accept.
+ */
+ const QDate endDate(void) const { return m_endDateEdit->date(); };
+
+protected:
+ const MyMoneyMoney totalInterest(const QDate& start, const QDate& end) const;
+ const MyMoneyMoney totalAmortization(const QDate& start, const QDate& end) const;
+
+public slots:
+ void next();
+
+protected slots:
+ void slotCheckPageFinished(void);
+ void help(void);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kendingbalancedlgdecl.ui b/kmymoney2/dialogs/kendingbalancedlgdecl.ui
new file mode 100644
index 0000000..0f77810
--- /dev/null
+++ b/kmymoney2/dialogs/kendingbalancedlgdecl.ui
@@ -0,0 +1,980 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KEndingBalanceDlgDecl</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>KEndingBalanceDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>589</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Reconciliation Wizard</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_startPageCheckings</cstring>
+ </property>
+ <attribute name="title">
+ <string>General Information</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Reconciling your account assures, that your recordings match those of your institution and that there are no mistakes on either side. You should reconcile your account whenever you receive a statement from your institution.
+
+All relevant information necessary for this process is usually printed on your statement.
+
+On the next page you will verify, that the starting and ending balance are matching those on your statement. If not, please modify the figures.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_startPageLoan</cstring>
+ </property>
+ <attribute name="title">
+ <string>General Information</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>KMyMoney calculates your loan payments automatically. The amounts can deviate from those calculated by the creditor. Therefore, you possibly have to adjust amortization, interest and other costs according to your statement.
+
+Please enter the following information found on your statement:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>19</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>42</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="kMyMoneyDateInput" row="0" column="1">
+ <property name="name">
+ <cstring>m_startDateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Ending date of statement</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="1" column="1">
+ <property name="name">
+ <cstring>m_endDateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Starting date of statement</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>44</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_checkPaymentsPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Verify payments</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_loanOverview</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout11</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Amortization</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_amortizationTotalEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Interest</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestTotalEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>If your statement shows different amounts, please cancel this dialog and correct the false transactions or correct the values in this dialog. In the later case, KMyMoney will create an adjustment transaction and add it to the ledger.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>19</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_adjustmentTransactionPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Adjustment transaction</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel5_2</cstring>
+ </property>
+ <property name="text">
+ <string>In order to create the adjustment transaction, KMyMoney requires an account and possibly an interest category to assign the differences to. Please select an account and - if necessary - a category.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout16</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel7_2</cstring>
+ </property>
+ <property name="text">
+ <string>Account</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_accountEdit</cstring>
+ </property>
+ </widget>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_accountEdit</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout18</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6_2</cstring>
+ </property>
+ <property name="text">
+ <string>Interest-Category</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_categoryEdit</cstring>
+ </property>
+ </widget>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_categoryEdit</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_pagePreviousPostpone</cstring>
+ </property>
+ <attribute name="title">
+ <string>Restarting postponed reconciliation</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>You have previously postponed the reconciliation of this account. If you have entered charges or interests the last time you started reconciling this account you can modify these in the ledger later on.
+
+It is important, that you continue with the same statement you used when you postponed the reconciliation.
+
+All information you have entered into this wizard will be shown and all transactions that you already cleared are marked with a 'C'.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_statementInfoPageCheckings</cstring>
+ </property>
+ <attribute name="title">
+ <string>Statement Information</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>m_enterInformationLabel</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>50</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>42</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Statement date:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="0" column="1">
+ <property name="name">
+ <cstring>m_statementDate</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Starting balance of this statement:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_previousBalance</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Ending balance of this statement:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_endingBalance</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>46</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>87</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_lastStatementDate</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_interestChargeCheckings</cstring>
+ </property>
+ <attribute name="title">
+ <string>Interest / Charges</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>If necessary, enter information about interest or charges here. KMyMoney will create transactions and clear them directly for you.</string>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>60</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Payee</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyPayeeCombo">
+ <property name="name">
+ <cstring>m_payeeEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Interest</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <widget class="KMyMoneyCategory">
+ <property name="name">
+ <cstring>m_interestCategoryEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_interestEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_interestDateEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Charges</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <widget class="KMyMoneyCategory">
+ <property name="name">
+ <cstring>m_chargesCategoryEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_chargesEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_chargesDateEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>60</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyAccountSelector</class>
+ <header location="global">../widgets/kmymoneyaccountselector.h</header>
+ <sizehint>
+ <width>80</width>
+ <height>80</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1114">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042149444154789c8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d096e8b11261871837bc8e282ac7ac82187e049a317e32d37110992bf42123c694eea414c0e0bf1b0ec6c402139485a54e8810c54c10e741146fa110bd643f74c12bd642e4d75f77cf5d5ef7dafdfc2ce7087d9eff32fdfdff74e5114104011e489d6e952cce5cfbe5998692dec0c77b87aedd3fddd9f2b3efce02291082209aa3504685022e4ffd7a000a82a765c515615ce95acae659c3f7765c100ec6e575cf8f822e991025f3b6a6f890c484f181ccfc1583428f5d4e2fe84da039aa04121b40eb32483a0ec6e5bce9f8385d36fa7fb9b1b17c8f31cbfe7a95c45be94520c72b2141a1caa160d1666e24ea94aa11ee7685054159d2ada34d41387c40dc63b8844f0b5c73a4bb19cb3f9de001f2aac1fa23aa209168c004224902e29d22ff1e38abbdb275055c4800610233867311a1491847a62c98f66ac6f14d8e99072f22daa15b68a8108424d6422e24c88e3966fbce4c9d786945b27f0be0103ed13c16004d59a2c4d58df28a87548e9aee2274ab95d60c7193c9a0281fc959ae2a4450364a9e2572c7a2b43438374ef2dd2154012d050514dbec7396578a3130d9d6850066f0ad9d186f2d78cdbbb799b0a202f2c48d3aebbb418310240b112637588574bf54b8efaa4fd9b691dacbf5b305813542bae63a9eee4c4694d967b5494eca8c7ef0933bdc5d90e6a2caa0e3f013b7adce9fa5b03d637561113a30106a71d18c5fd9677058338ad01e91c0b8b743b880182ce19cd9c0e5e2b583fbdda565d3d04cfedad180942133af201b2bc3588e111c680068f489780ce69b192b279768088524f2b3458ea694d3de99a4323bc976ed34eb86b98c51993f6be10f77240c99685cd731991f1582df15aa15a213d583f5313a7806988fb8a0640e336359d9e9933568bf44062214ba19e2a7652a13d8b068ff596b807182189234e9da9f1ceb78c81b28c3ac6fe21e306c58e41d5118952acd6a0c2f56b9e6a5c72f346cdcd6b19a3bf8010010d714f89533b674c90c7189b598eab12a45fb5c75b8253672b863fbcccf5af93b6904119fe9851bf5153ac3a746ae7b9d5698c1dc58f313e70e4707ce9d84bafa2f79fc23fb8c7c1438ef04031a2642fee21060ec69ee47020796ecaa12313ccd333d1b67935047acf2be3bb11aa010dbe656cc755dbe3b772084a7ebc6d5711253b593dfcc0cc8fcd3cafda455512c7f200ec56cbfac0f1d7d34b7fdf0f98fd88a92a7e9cb0e70cc933c0b38a2c823ea0bd76c70c016adb67f47bc2a117a6d40abeea33fa23c2fb867edfb413e4a34fded94ffb3991c46dc7754cd3634ad2af490b857f5a5137126a97e02a8120a485235b6a28ef80bd077ee2b9f2d54fed04595dcbd8ddb6c4bd87334c10cadb2064e856177e7864e669fbe1df154a0142839f7ad2e5b6880bff1da66eece78e315d959f609da670f98befe6c3f45fb42672c9acff7f660000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kenterscheduledlg.cpp b/kmymoney2/dialogs/kenterscheduledlg.cpp
new file mode 100644
index 0000000..f39f003
--- /dev/null
+++ b/kmymoney2/dialogs/kenterscheduledlg.cpp
@@ -0,0 +1,327 @@
+/***************************************************************************
+ kenterscheduledlg.cpp
+ -------------------
+ begin : Sat Apr 7 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtimer.h>
+#include <qwidgetlist.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kiconloader.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kenterscheduledlg.h"
+#include "../dialogs/kcurrencycalculator.h"
+#include <kmymoney/register.h>
+#include <kmymoney/transactionform.h>
+#include <kmymoney/transaction.h>
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/kmymoneyutils.h>
+#include <kmymoney/mymoneyfinancialcalculator.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kmymoneydateinput.h>
+
+#include "../kmymoney2.h"
+
+class KEnterScheduleDlg::Private
+{
+public:
+ Private() : m_item(0), m_showWarningOnce(true) {}
+ ~Private() {}
+
+ MyMoneySchedule m_schedule;
+ KMyMoneyRegister::Transaction* m_item;
+ QWidgetList m_tabOrderWidgets;
+ bool m_showWarningOnce;
+ KMyMoneyUtils::EnterScheduleResultCodeE m_extendedReturnCode;
+};
+
+KEnterScheduleDlg::KEnterScheduleDlg(QWidget *parent, const MyMoneySchedule& schedule) :
+ KEnterScheduleDlgDecl(parent, "kenterscheduledlg"),
+ d(new Private)
+{
+ d->m_schedule = schedule;
+ d->m_extendedReturnCode = KMyMoneyUtils::Enter;
+ buttonOk->setIconSet(KGlobal::iconLoader()->loadIconSet("key_enter", KIcon::NoGroup, KIcon::SizeSmall, true));
+ buttonSkip->setIconSet(KGlobal::iconLoader()->loadIconSet("player_fwd", KIcon::NoGroup, KIcon::SizeSmall, true));
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+ buttonHelp->setGuiItem(KStdGuiItem::help());
+ buttonIgnore->setHidden(true);
+ buttonSkip->setHidden(true);
+
+ // make sure, we have a tabbar with the form
+ KMyMoneyTransactionForm::TabBar* tabbar = m_form->tabBar(m_form->parentWidget());
+
+ // we never need to see the register
+ m_register->hide();
+
+ // ... setup the form ...
+ m_form->setupForm(d->m_schedule.account());
+
+ // ... and the register ...
+ m_register->clear();
+
+ // ... now add the transaction to register and form ...
+ MyMoneyTransaction t = transaction();
+ d->m_item = KMyMoneyRegister::Register::transactionFactory(m_register, t, d->m_schedule.transaction().splits()[0], 0);
+ m_register->selectItem(d->m_item);
+ // show the account row
+ d->m_item->setShowRowInForm(0, true);
+
+ m_form->slotSetTransaction(d->m_item);
+
+ // no need to see the tabbar
+ tabbar->hide();
+
+ // setup name and type
+ m_scheduleName->setText(d->m_schedule.name());
+ m_type->setText(KMyMoneyUtils::scheduleTypeToString(d->m_schedule.type()));
+
+ connect(buttonHelp, SIGNAL(clicked()), this, SLOT(slotShowHelp()));
+ connect(buttonIgnore, SIGNAL(clicked()), this, SLOT(slotIgnore()));
+ connect(buttonSkip, SIGNAL(clicked()), this, SLOT(slotSkip()));
+
+ // force the initial height to be as small as possible
+ QTimer::singleShot(0, this, SLOT(slotSetupSize()));
+}
+
+KEnterScheduleDlg::~KEnterScheduleDlg()
+{
+ delete d;
+}
+
+KMyMoneyUtils::EnterScheduleResultCodeE KEnterScheduleDlg::resultCode(void) const
+{
+ if(result() == QDialog::Accepted)
+ return d->m_extendedReturnCode;
+ return KMyMoneyUtils::Cancel;
+}
+
+void KEnterScheduleDlg::showExtendedKeys(bool visible)
+{
+ buttonIgnore->setShown(visible);
+ buttonSkip->setShown(visible);
+}
+
+void KEnterScheduleDlg::slotIgnore(void)
+{
+ d->m_extendedReturnCode = KMyMoneyUtils::Ignore;
+ accept();
+}
+
+void KEnterScheduleDlg::slotSkip(void)
+{
+ d->m_extendedReturnCode = KMyMoneyUtils::Skip;
+ accept();
+}
+
+MyMoneyTransaction KEnterScheduleDlg::transaction(void)
+{
+ MyMoneyTransaction t = d->m_schedule.transaction();
+
+ try {
+ if (d->m_schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT) {
+ KMyMoneyUtils::calculateAutoLoan(d->m_schedule, t, QMap<QString, MyMoneyMoney>());
+ }
+ } catch (MyMoneyException* e) {
+ KMessageBox::detailedError(this, i18n("Unable to load schedule details"), e->what());
+ delete e;
+ }
+
+ t.clearId();
+ t.setEntryDate(QDate());
+ return t;
+}
+
+QDate KEnterScheduleDlg::date(const QDate& _date) const
+{
+ QDate date(_date);
+ return d->m_schedule.adjustedDate(date, d->m_schedule.weekendOption());
+}
+
+void KEnterScheduleDlg::resizeEvent(QResizeEvent* ev)
+{
+ m_register->resize(KMyMoneyRegister::DetailColumn);
+ m_form->resize(KMyMoneyTransactionForm::ValueColumn1);
+ KEnterScheduleDlgDecl::resizeEvent(ev);
+}
+
+
+void KEnterScheduleDlg::slotSetupSize(void)
+{
+ resize(width(), minimumSizeHint().height());
+}
+
+int KEnterScheduleDlg::exec(void)
+{
+ if(d->m_showWarningOnce) {
+ d->m_showWarningOnce = false;
+ KMessageBox::information(this, QString("<qt>")+i18n("<p>Please check that all the details in the following dialog are correct and press OK.</p><p>Editable data can be changed and can either be applied to just this occurence or for all subsequent occurences for this schedule. (You will be asked what you intend after pressing OK in the following dialog)</p>")+QString("</qt>"), i18n("Enter scheduled transaction"), "EnterScheduleDlgInfo");
+ }
+
+ return KEnterScheduleDlgDecl::exec();
+}
+
+TransactionEditor* KEnterScheduleDlg::startEdit(void)
+{
+ KMyMoneyRegister::SelectedTransactions list(m_register);
+ TransactionEditor* editor = d->m_item->createEditor(m_form, list, QDate());
+
+ // check that we use the same transaction commodity in all selected transactions
+ // if not, we need to update this in the editor's list. The user can also bail out
+ // of this operation which means that we have to stop editing here.
+ if(editor) {
+ if(!editor->fixTransactionCommodity(d->m_schedule.account())) {
+ // if the user wants to quit, we need to destroy the editor
+ // and bail out
+ delete editor;
+ editor = 0;
+ }
+ }
+
+ if(editor) {
+ connect(editor, SIGNAL(transactionDataSufficient(bool)), buttonOk, SLOT(setEnabled(bool)));
+ connect(editor, SIGNAL(escapePressed()), buttonCancel, SLOT(animateClick()));
+ connect(editor, SIGNAL(returnPressed()), buttonOk, SLOT(animateClick()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets()));
+ // connect(editor, SIGNAL(finishEdit(const KMyMoneyRegister::SelectedTransactions&)), this, SLOT(slotLeaveEditMode(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(editor, SIGNAL(createPayee(const QString&, QString&)), kmymoney2, SLOT(slotPayeeNew(const QString&, QString&)));
+ connect(editor, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotCategoryNew(MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(editor, SIGNAL(createSecurity(MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotInvestmentNew(MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets()));
+
+ // create the widgets, place them in the parent and load them with data
+ // setup tab order
+ d->m_tabOrderWidgets.clear();
+ KMyMoneyRegister::Action action = KMyMoneyRegister::ActionWithdrawal;
+ switch(d->m_schedule.type()) {
+ case MyMoneySchedule::TYPE_DEPOSIT:
+ action = KMyMoneyRegister::ActionDeposit;
+ break;
+ case MyMoneySchedule::TYPE_TRANSFER:
+ action = KMyMoneyRegister::ActionTransfer;
+ break;
+ case MyMoneySchedule::TYPE_LOANPAYMENT:
+ switch(d->m_schedule.paymentType()) {
+ case MyMoneySchedule::STYPE_DIRECTDEPOSIT:
+ case MyMoneySchedule::STYPE_MANUALDEPOSIT:
+ action = KMyMoneyRegister::ActionDeposit;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ editor->setup(d->m_tabOrderWidgets, d->m_schedule.account(), action);
+
+ // if it's not a check, then we need to clear
+ // a possibly assigned check number
+ if(d->m_schedule.paymentType() != MyMoneySchedule::STYPE_WRITECHEQUE) {
+ QWidget* w = editor->haveWidget("number");
+ if(w)
+ dynamic_cast<kMyMoneyLineEdit*>(w)->loadText(QString());
+ }
+
+ Q_ASSERT(!d->m_tabOrderWidgets.isEmpty());
+
+ // don't forget our three buttons
+ d->m_tabOrderWidgets.append(buttonOk);
+ d->m_tabOrderWidgets.append(buttonCancel);
+ d->m_tabOrderWidgets.append(buttonHelp);
+
+ // install event filter in all taborder widgets
+ for(QWidget* w = d->m_tabOrderWidgets.first(); w; w = d->m_tabOrderWidgets.next()) {
+ w->installEventFilter(this);
+ w->installEventFilter(editor);
+ }
+
+ // Check if the editor has some preference on where to set the focus
+ // If not, set the focus to the first widget in the tab order
+ QWidget* focusWidget = editor->firstWidget();
+ if(!focusWidget)
+ focusWidget = d->m_tabOrderWidgets.first();
+ focusWidget->setFocus();
+
+ // Make sure, we use the adjusted date
+ kMyMoneyDateInput* dateEdit = dynamic_cast<kMyMoneyDateInput*>(editor->haveWidget("postdate"));
+ if(dateEdit) {
+ dateEdit->setDate(d->m_schedule.adjustedNextDueDate());
+ }
+ }
+
+ return editor;
+}
+
+bool KEnterScheduleDlg::focusNextPrevChild(bool next)
+{
+ bool rc = false;
+
+ // qDebug("KGlobalLedgerView::focusNextPrevChild(editmode=%s)", m_inEditMode ? "true" : "false");
+ QWidget *w = 0;
+ QWidget *currentWidget;
+
+ w = qApp->focusWidget();
+ while(w && d->m_tabOrderWidgets.find(w) == -1) {
+ // qDebug("'%s' not in list, use parent", w->className());
+ w = w->parentWidget();
+ }
+ // if(w) qDebug("tab order is at '%s'", w->className());
+ currentWidget = d->m_tabOrderWidgets.current();
+ w = next ? d->m_tabOrderWidgets.next() : d->m_tabOrderWidgets.prev();
+
+ do {
+ if(!w) {
+ w = next ? d->m_tabOrderWidgets.first() : d->m_tabOrderWidgets.last();
+ }
+
+ if(w != currentWidget
+ && ((w->focusPolicy() & TabFocus) == TabFocus)
+ && w->isVisible() && w->isEnabled()) {
+ // qDebug("Selecting '%s' as focus", w->className());
+ w->setFocus();
+ rc = true;
+ break;
+ }
+ w = next ? d->m_tabOrderWidgets.next() : d->m_tabOrderWidgets.prev();
+ } while(w != currentWidget);
+
+ return rc;
+}
+
+void KEnterScheduleDlg::slotShowHelp(void)
+{
+ kapp->invokeHelp("details.schedules.entering");
+}
+
+
+#include "kenterscheduledlg.moc"
+
diff --git a/kmymoney2/dialogs/kenterscheduledlg.h b/kmymoney2/dialogs/kenterscheduledlg.h
new file mode 100644
index 0000000..0e14ad4
--- /dev/null
+++ b/kmymoney2/dialogs/kenterscheduledlg.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ kenterscheduledlg.h - description
+ -------------------
+ begin : Sat Apr 7 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KENTERSCHEDULEDLG_H
+#define KENTERSCHEDULEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class TransactionEditor;
+
+#include "../dialogs/kenterscheduledlgdecl.h"
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/kmymoneyutils.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+class KEnterScheduleDlg : public KEnterScheduleDlgDecl
+{
+ Q_OBJECT
+public:
+ KEnterScheduleDlg(QWidget *parent, const MyMoneySchedule& schedule);
+ ~KEnterScheduleDlg();
+
+ TransactionEditor* startEdit(void);
+ MyMoneyTransaction transaction(void);
+
+ /**
+ * Show (or hide) the extended dialog keys for 'Skip' and 'Ignore'
+ * depending on the value of the parameter @a visible which defaults
+ * to @a true.
+ */
+ void showExtendedKeys(bool visible = true);
+
+ /**
+ * Return the extended result code. Usage of the returned
+ * value only makes sense, once the dialog has been executed.
+ * Before execution it returns @a Cancel.
+ */
+ KMyMoneyUtils::EnterScheduleResultCodeE resultCode(void) const;
+
+protected:
+ /// Overridden for internal reasons. No API changes.
+ bool focusNextPrevChild(bool next);
+
+ /**
+ * This method returns the adjusts @a _date according to
+ * the setting of the schedule's weekend option.
+ */
+ QDate date(const QDate& _date) const;
+
+ void resizeEvent(QResizeEvent* ev);
+
+public slots:
+ int exec(void);
+
+private slots:
+ void slotSetupSize(void);
+ void slotShowHelp(void);
+ void slotIgnore(void);
+ void slotSkip(void);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kenterscheduledlgdecl.ui b/kmymoney2/dialogs/kenterscheduledlgdecl.ui
new file mode 100644
index 0000000..3efed94
--- /dev/null
+++ b/kmymoney2/dialogs/kenterscheduledlgdecl.ui
@@ -0,0 +1,330 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KEnterScheduleDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KEnterScheduleDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>679</width>
+ <height>410</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Enter Schedule</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Schedule Details</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ </font>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_scheduleName</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ </font>
+ </property>
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="3">
+ <property name="name">
+ <cstring>m_type</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="KMyMoneyRegister::Register">
+ <column>
+ <property name="text">
+ <string>Security</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Details</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>C</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Payment</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Deposit</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Quantity</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Balance</string>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_register</cstring>
+ </property>
+ <property name="numRows">
+ <number>0</number>
+ </property>
+ <property name="numCols">
+ <number>12</number>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame4</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KMyMoneyTransactionForm::TransactionForm">
+ <property name="name">
+ <cstring>m_form</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>5</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="numRows">
+ <number>5</number>
+ </property>
+ <property name="numCols">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>190</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>Enter</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the transaction and advance the next due date of this schedule to the next payment date.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonSkip</cstring>
+ </property>
+ <property name="text">
+ <string>Skip</string>
+ </property>
+ <property name="isDragEnabled" stdset="0">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Do not enter the transaction but advance the next due date of this schedule to the next payment date.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonIgnore</cstring>
+ </property>
+ <property name="text">
+ <string>Ignore</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Do not enter or skip payments for this schedule but continue with the next schedule.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Cancel processing of schedule entry.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KEnterScheduleDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KEnterScheduleDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kequitypriceupdatedlg.cpp b/kmymoney2/dialogs/kequitypriceupdatedlg.cpp
new file mode 100644
index 0000000..4111bfa
--- /dev/null
+++ b/kmymoney2/dialogs/kequitypriceupdatedlg.cpp
@@ -0,0 +1,588 @@
+/***************************************************************************
+ kequitypriceupdatedlg.cpp - description
+ -------------------
+ begin : Mon Sep 1 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <ktextedit.h>
+#include <klistview.h>
+#include <kdebug.h>
+#include <kprogress.h>
+#include <kglobal.h>
+#include <kconfig.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kequitypriceupdatedlg.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyprice.h"
+#include "../kmymoneyglobalsettings.h"
+
+#define SYMBOL_COL 0
+#define NAME_COL 1
+#define PRICE_COL 2
+#define DATE_COL 3
+#define ID_COL 4
+#define SOURCE_COL 5
+
+KEquityPriceUpdateDlg::KEquityPriceUpdateDlg(QWidget *parent, const QString& securityId) :
+ KEquityPriceUpdateDlgDecl(parent),
+ m_fUpdateAll(false)
+{
+ lvEquityList->setRootIsDecorated(false);
+ lvEquityList->setColumnText(0, i18n("Symbol"));
+ lvEquityList->addColumn(i18n("Symbol"));
+ lvEquityList->addColumn(i18n("Name"),125);
+ lvEquityList->addColumn(i18n("Price"));
+ lvEquityList->addColumn(i18n("Date"));
+
+ // This is a "get it up and running" hack. Will replace this in the future.
+ lvEquityList->addColumn("ID");
+ lvEquityList->addColumn("Source");
+ lvEquityList->setColumnWidth(ID_COL, 0);
+
+ lvEquityList->setMultiSelection(true);
+ lvEquityList->setColumnWidthMode(SYMBOL_COL, QListView::Maximum);
+ lvEquityList->setColumnWidthMode(ID_COL, QListView::Manual);
+ lvEquityList->setAllColumnsShowFocus(true);
+
+ btnUpdateAll->setEnabled(false);
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //
+ // Add each price pair that we know about
+ //
+
+ // send in securityId == "XXX YYY" to get a single-shot update for XXX to YYY.
+ // for consistency reasons, this accepts the same delimiters as WebPriceQuote::launch()
+ QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)",false /*case sensitive*/);
+ MyMoneySecurityPair currencyIds;
+ if ( splitrx.search(securityId) != -1 )
+ currencyIds = MyMoneySecurityPair(splitrx.cap(1).utf8(),splitrx.cap(2).utf8());
+
+ MyMoneyPriceList prices = file->priceList();
+ for(MyMoneyPriceList::ConstIterator it_price = prices.begin(); it_price != prices.end(); ++it_price)
+ {
+ const MyMoneySecurityPair& pair = it_price.key();
+ if ( file->security( pair.first ).isCurrency() && ( securityId.isEmpty() || ( pair == currencyIds ) ) )
+ {
+ const MyMoneyPriceEntries& entries = (*it_price);
+ if(entries.count() > 0 && entries.begin().key() <= QDate::currentDate()) {
+ addPricePair(pair);
+ btnUpdateAll->setEnabled(true);
+ }
+ }
+ }
+
+ //
+ // Add each investment
+ //
+
+ QValueList<MyMoneySecurity> securities = file->securityList();
+ for(QValueList<MyMoneySecurity>::ConstIterator it = securities.begin(); it != securities.end(); ++it)
+ {
+ if ( !(*it).isCurrency()
+ && ( securityId.isEmpty() || ( (*it).id() == securityId ) )
+ && !(*it).value("kmm-online-source").isEmpty()
+ )
+ {
+ addInvestment(*it);
+ btnUpdateAll->setEnabled(true);
+ }
+ }
+
+ // if list is empty, add the request price pair
+ if(lvEquityList->firstChild() == 0) {
+ addPricePair(currencyIds, true);
+ }
+
+ connect(btnOK, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(btnUpdateSelected, SIGNAL(clicked()), this, SLOT(slotUpdateSelectedClicked()));
+ connect(btnUpdateAll, SIGNAL(clicked()), this, SLOT(slotUpdateAllClicked()));
+
+ connect(&m_webQuote,SIGNAL(quote(const QString&, const QString&,const QDate&, const double&)),
+ this,SLOT(slotReceivedQuote(const QString&, const QString&,const QDate&, const double&)));
+ connect(&m_webQuote,SIGNAL(failed(const QString&, const QString&)),
+ this,SLOT(slotQuoteFailed(const QString&, const QString&)));
+ connect(&m_webQuote,SIGNAL(status(const QString&)),
+ this,SLOT(logStatusMessage(const QString&)));
+ connect(&m_webQuote,SIGNAL(error(const QString&)),
+ this,SLOT(logErrorMessage(const QString&)));
+
+ connect(lvEquityList, SIGNAL(selectionChanged()), this, SLOT(slotUpdateSelection()));
+
+ // Not implemented yet.
+ btnConfigure->hide();
+ //connect(btnConfigure, SIGNAL(clicked()), this, SLOT(slotConfigureClicked()));
+
+ if ( !securityId.isEmpty() )
+ {
+ btnUpdateSelected->hide();
+ btnUpdateAll->hide();
+ // delete layout1;
+
+ QTimer::singleShot(100,this,SLOT(slotUpdateAllClicked()));
+ }
+
+ // Hide OK button until we have received the first update
+ btnOK->setEnabled(false);
+
+ slotUpdateSelection();
+
+ // previous versions of this dialog allowed to store a "Don't ask again" switch.
+ // Since we don't support it anymore, we just get rid of it
+ KConfig* config = KGlobal::config();
+ config->setGroup("Notification Messages");
+ config->deleteEntry("KEquityPriceUpdateDlg::slotQuoteFailed::Price Update Failed");
+}
+
+KEquityPriceUpdateDlg::~KEquityPriceUpdateDlg()
+{
+
+}
+
+void KEquityPriceUpdateDlg::addPricePair(const MyMoneySecurityPair& pair, bool dontCheckExistance)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString symbol = QString("%1 > %2").arg(pair.first,pair.second);
+ QString id = QString("%1 %2").arg(pair.first,pair.second);
+ if ( ! lvEquityList->findItem(id,ID_COL,Qt::ExactMatch) )
+ {
+ MyMoneyPrice pr = file->price(pair.first,pair.second);
+ if(pr.source() != "KMyMoney") {
+ bool keep = true;
+ if((pair.first == file->baseCurrency().id())
+ || (pair.second == file->baseCurrency().id())) {
+ const QString& foreignCurrency = file->foreignCurrency(pair.first, pair.second);
+ // check that the foreign currency is still in use
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ QValueList<MyMoneyAccount> list;
+ file->accountList(list);
+ for(it_a = list.begin(); !dontCheckExistance && it_a != list.end(); ++it_a) {
+ // if it's an account denominated in the foreign currency
+ // keep it
+ if(((*it_a).currencyId() == foreignCurrency)
+ && !(*it_a).isClosed())
+ break;
+ // if it's an investment traded in the foreign currency
+ // keep it
+ if((*it_a).isInvest() && !(*it_a).isClosed()) {
+ MyMoneySecurity sec = file->security((*it_a).currencyId());
+ if(sec.tradingCurrency() == foreignCurrency)
+ break;
+ }
+ }
+ // if it is in use, it_a is not equal to list.end()
+ if(it_a == list.end() && !dontCheckExistance)
+ keep = false;
+ }
+
+ if(keep) {
+ KListViewItem* item = new KListViewItem(lvEquityList,
+ symbol,
+ i18n("%1 units in %2").arg(pair.first,pair.second));
+ if(pr.isValid()) {
+ item->setText(PRICE_COL, pr.rate(pair.second).formatMoney(file->currency(pair.second).tradingSymbol(), KMyMoneyGlobalSettings::pricePrecision()));
+ item->setText(DATE_COL, pr.date().toString(Qt::ISODate));
+ }
+ item->setText(ID_COL,id);
+ item->setText(SOURCE_COL, "Yahoo Currency"); // This string value should not be localized
+ }
+ }
+ }
+}
+
+void KEquityPriceUpdateDlg::addInvestment(const MyMoneySecurity& inv)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString symbol = inv.tradingSymbol();
+ QString id = inv.id();
+ if ( ! lvEquityList->findItem(id, ID_COL, Qt::ExactMatch) )
+ {
+ // check that the security is still in use
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ QValueList<MyMoneyAccount> list;
+ file->accountList(list);
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ if((*it_a).isInvest()
+ && ((*it_a).currencyId() == inv.id())
+ && !(*it_a).isClosed())
+ break;
+ }
+ // if it is in use, it_a is not equal to list.end()
+ if(it_a != list.end()) {
+ KListViewItem* item = new KListViewItem(lvEquityList, symbol, inv.name());
+ MyMoneySecurity currency = file->currency(inv.tradingCurrency());
+ MyMoneyPrice pr = file->price(id.utf8(), inv.tradingCurrency());
+ if(pr.isValid()) {
+ item->setText(PRICE_COL, pr.rate(currency.id()).formatMoney(currency.tradingSymbol(), KMyMoneyGlobalSettings::pricePrecision()));
+ item->setText(DATE_COL, pr.date().toString(Qt::ISODate));
+ }
+ item->setText(ID_COL,id);
+ if (inv.value("kmm-online-quote-system") == "Finance::Quote")
+ item->setText(SOURCE_COL, QString("Finance::Quote %1").arg( inv.value("kmm-online-source")));
+ else
+ item->setText(SOURCE_COL, inv.value("kmm-online-source"));
+
+ // If this investment is denominated in a foreign currency, ensure that
+ // the appropriate price pair is also on the list
+
+ if ( currency.id() != file->baseCurrency().id() )
+ {
+ addPricePair(MyMoneySecurityPair(currency.id(),file->baseCurrency().id()));
+ }
+ }
+ }
+}
+
+void KEquityPriceUpdateDlg::logErrorMessage(const QString& message)
+{
+ logStatusMessage(QString("<font color=\"red\"><b>") + message + QString("</b></font>"));
+}
+
+void KEquityPriceUpdateDlg::logStatusMessage(const QString& message)
+{
+ lbStatus->append(message);
+}
+
+MyMoneyPrice KEquityPriceUpdateDlg::price(const QString& id) const
+{
+ MyMoneyPrice price;
+ QListViewItem* item;
+
+ if((item = lvEquityList->findItem(id, ID_COL, Qt::ExactMatch)) != 0) {
+ MyMoneyMoney rate(item->text(PRICE_COL));
+ if ( !rate.isZero() )
+ {
+ QString id = item->text(ID_COL).utf8();
+
+ // if the ID has a space, then this is TWO ID's, so it's a currency quote
+ if ( QString(id).contains(" ") )
+ {
+ QStringList ids = QStringList::split(" ",QString(id));
+ QString fromid = ids[0].utf8();
+ QString toid = ids[1].utf8();
+ price = MyMoneyPrice(fromid,toid,QDate().fromString(item->text(DATE_COL), Qt::ISODate),rate,item->text(SOURCE_COL));
+ }
+ else
+ // otherwise, it's a security quote
+ {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(id);
+ price = MyMoneyPrice(id, security.tradingCurrency(), QDate().fromString(item->text(DATE_COL), Qt::ISODate), rate, item->text(SOURCE_COL));
+ }
+ }
+ }
+ return price;
+}
+
+void KEquityPriceUpdateDlg::storePrices(void)
+{
+ // update the new prices into the equities
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneySecurity> equities = file->securityList();
+
+ QListViewItem* item = lvEquityList->firstChild();
+ MyMoneyFileTransaction ft;
+ QString name;
+ try {
+ while ( item )
+ {
+ // turn on signals before we modify the last entry in the list
+ MyMoneyFile::instance()->blockSignals(item->nextSibling() != 0);
+
+ MyMoneyMoney rate(item->text(PRICE_COL));
+ if ( !rate.isZero() )
+ {
+ QString id = item->text(ID_COL).utf8();
+
+ // if the ID has a space, then this is TWO ID's, so it's a currency quote
+ if ( QString(id).contains(" ") )
+ {
+ QStringList ids = QStringList::split(" ",QString(id));
+ QString fromid = ids[0].utf8();
+ QString toid = ids[1].utf8();
+ name = QString("%1 --> %2").arg(fromid).arg(toid);
+ MyMoneyPrice price(fromid,toid,QDate().fromString(item->text(DATE_COL), Qt::ISODate),rate,item->text(SOURCE_COL));
+ file->addPrice(price);
+ }
+ else
+ // otherwise, it's a security quote
+ {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(id);
+ name = security.name();
+ MyMoneyPrice price(id, security.tradingCurrency(), QDate().fromString(item->text(DATE_COL), Qt::ISODate), rate, item->text(SOURCE_COL));
+
+ // TODO (Ace) Better handling of the case where there is already a price
+ // for this date. Currently, it just overrides the old value. Really it
+ // should check to see if the price is the same and prompt the user.
+ MyMoneyFile::instance()->addPrice(price);
+ }
+
+ }
+ item = item->nextSibling();
+ }
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to add price information for %s", name.data());
+ delete e;
+ }
+}
+
+void KEquityPriceUpdateDlg::slotUpdateSelection(void)
+{
+ btnUpdateSelected->setEnabled(false);
+
+ QListViewItem* item = lvEquityList->firstChild();
+ while ( item && !item->isSelected())
+ item = item->nextSibling();
+
+ if(item)
+ btnUpdateSelected->setEnabled(true);
+}
+
+void KEquityPriceUpdateDlg::slotUpdateSelectedClicked(void)
+{
+ QListViewItem* item = lvEquityList->firstChild();
+ int skipCnt = 1;
+ while ( item && !item->isSelected())
+ {
+ skipCnt++;
+ item = item->nextSibling();
+ }
+
+ if(item) {
+ prgOnlineProgress->setTotalSteps(1+lvEquityList->childCount());
+ prgOnlineProgress->setProgress(skipCnt);
+ m_webQuote.launch(item->text(SYMBOL_COL),item->text(ID_COL),item->text(SOURCE_COL));
+ }
+ else
+ logErrorMessage("No security selected.");
+}
+
+void KEquityPriceUpdateDlg::slotUpdateAllClicked(void)
+{
+ QListViewItem* item = lvEquityList->firstChild();
+ if ( item )
+ {
+ prgOnlineProgress->setTotalSteps(1+lvEquityList->childCount());
+ prgOnlineProgress->setProgress(1);
+ m_fUpdateAll = true;
+ m_webQuote.launch(item->text(SYMBOL_COL),item->text(ID_COL),item->text(SOURCE_COL));
+ }
+ else
+ logErrorMessage("Security list is empty.");
+}
+
+void KEquityPriceUpdateDlg::slotQuoteFailed(const QString& _id, const QString& _symbol)
+{
+ QListViewItem* item = lvEquityList->findItem(_id,ID_COL,Qt::ExactMatch);
+
+ // Give the user some options
+ int result;
+ if(_id.contains(" ")) {
+ result = KMessageBox::warningContinueCancel(this, i18n("Failed to retrieve an exchange rate for %1 from %2. It will be skipped this time.").arg(_symbol, item->text(SOURCE_COL)), i18n("Price Update Failed"));
+ } else {
+ result = KMessageBox::questionYesNoCancel(this, QString("<qt>%1</qt>").arg(i18n("Failed to retrieve a quote for %1 from %2. Press <b>No</b> to remove the online price source from this security permanently, <b>Yes</b> to continue updating this security during future price updates or <b>Cancel</b> to stop the current update operation.").arg(_symbol, item->text(SOURCE_COL))), i18n("Price Update Failed"), KStdGuiItem::yes(), KStdGuiItem::no());
+ }
+
+ if ( result == KMessageBox::No )
+ {
+ // Disable price updates for this security
+
+ MyMoneyFileTransaction ft;
+ try {
+ // Get this security (by ID)
+ MyMoneySecurity security = MyMoneyFile::instance()->security(_id.utf8());
+
+ // Set the quote source to blank
+ security.setValue("kmm-online-source",QString());
+ security.setValue("kmm-online-quote-system",QString());
+
+ // Re-commit the security
+ MyMoneyFile::instance()->modifySecurity(security);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::error(this, QString("<qt>")+i18n("Cannot update security <b>%1</b>: %2").arg(_symbol, e->what())+QString("</qt>"), i18n("Price Update Failed"));
+ delete e;
+ }
+ }
+
+ // As long as the user doesn't want to cancel, move on!
+ if ( result != KMessageBox::Cancel )
+ {
+ QListViewItem* next = NULL;
+ prgOnlineProgress->advance(1);
+ item->listView()->setSelected(item, false);
+
+ // launch the NEXT one ... in case of m_fUpdateAll == false, we
+ // need to parse the list to find the next selected one
+ next = item->nextSibling();
+ if ( !m_fUpdateAll )
+ {
+ while(next && !next->isSelected())
+ {
+ prgOnlineProgress->advance(1);
+ next = next->nextSibling();
+ }
+ }
+ if (next)
+ {
+ m_webQuote.launch(next->text(SYMBOL_COL),next->text(ID_COL),next->text(SOURCE_COL));
+ }
+ else
+ {
+ finishUpdate();
+ }
+ }
+ else
+ {
+ finishUpdate();
+ }
+}
+
+void KEquityPriceUpdateDlg::slotReceivedQuote(const QString& _id, const QString& _symbol,const QDate& _date, const double& _price)
+{
+ QListViewItem* item = lvEquityList->findItem(_id,ID_COL,Qt::ExactMatch);
+ QListViewItem* next = NULL;
+
+ if ( item )
+ {
+ if ( _price > 0.0f && _date.isValid() )
+ {
+ QDate date = _date;
+ if ( date > QDate::currentDate() )
+ date = QDate::currentDate();
+
+ double price = _price;
+ QString id = _id.utf8();
+ MyMoneySecurity sec;
+ if ( _id.contains(" ") == 0) {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(id);
+ QString factor = security.value("kmm-online-factor");
+ if(!factor.isEmpty()) {
+ price *= MyMoneyMoney(factor).toDouble();
+ }
+ try {
+ sec = MyMoneyFile::instance()->security(id);
+ sec = MyMoneyFile::instance()->security(sec.tradingCurrency());
+ } catch(MyMoneyException *e) {
+ sec = MyMoneySecurity();
+ delete e;
+ }
+
+ } else {
+ QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)",false /*case sensitive*/);
+ if ( splitrx.search(_id) != -1 ) {
+ try {
+ sec = MyMoneyFile::instance()->security(splitrx.cap(2).utf8());
+ } catch(MyMoneyException *e) {
+ sec = MyMoneySecurity();
+ delete e;
+ }
+ }
+ }
+ item->setText(PRICE_COL, KGlobal::locale()->formatMoney(price, sec.tradingSymbol(), KMyMoneyGlobalSettings::pricePrecision()));
+ item->setText(DATE_COL, date.toString(Qt::ISODate));
+ logStatusMessage(i18n("Price for %1 updated (id %2)").arg(_symbol,_id));
+ // make sure to make OK button available
+ btnOK->setEnabled(true);
+ }
+ else
+ {
+ logErrorMessage(i18n("Received an invalid price for %1, unable to update.").arg(_symbol));
+ }
+
+ prgOnlineProgress->advance(1);
+ item->listView()->setSelected(item, false);
+
+ // launch the NEXT one ... in case of m_fUpdateAll == false, we
+ // need to parse the list to find the next selected one
+ next = item->nextSibling();
+ if ( !m_fUpdateAll )
+ {
+ while(next && !next->isSelected())
+ {
+ prgOnlineProgress->advance(1);
+ next = next->nextSibling();
+ }
+ }
+ }
+ else
+ {
+ logErrorMessage(i18n("Received a price for %1 (id %2), but this symbol is not on the list! Aborting entire update.").arg(_symbol,_id));
+ }
+
+ if (next)
+ {
+ m_webQuote.launch(next->text(SYMBOL_COL),next->text(ID_COL),next->text(SOURCE_COL));
+ }
+ else
+ {
+ finishUpdate();
+ }
+}
+
+void KEquityPriceUpdateDlg::finishUpdate(void)
+{
+ // we've run past the end, reset to the default value.
+ m_fUpdateAll = false;
+ // force progress bar to show 100%
+ prgOnlineProgress->setProgress(prgOnlineProgress->totalSteps());
+}
+
+// Make sure, that these definitions are only used within this file
+// this does not seem to be necessary, but when building RPMs the
+// build option 'final' is used and all CPP files are concatenated.
+// So it could well be, that in another CPP file these definitions
+// are also used.
+#undef SYMBOL_COL
+#undef NAME_COL
+#undef PRICE_COL
+#undef DATE_COL
+#undef ID_COL
+#undef SOURCE_COL
+
+#include "kequitypriceupdatedlg.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kequitypriceupdatedlg.h b/kmymoney2/dialogs/kequitypriceupdatedlg.h
new file mode 100644
index 0000000..7dbc6a5
--- /dev/null
+++ b/kmymoney2/dialogs/kequitypriceupdatedlg.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ kequitypriceupdatedlg.h - description
+ -------------------
+ begin : Tuesday June 22nd, 2004
+ copyright : (C) 2000-2004 by Kevin Tambascio
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KEQUITYPRICEUPDATEDIALOG_H
+#define KEQUITYPRICEUPDATEDIALOG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qpair.h>
+#include <qdatastream.h>
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kprocess.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../converter/webpricequote.h"
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyprice.h"
+#include "../dialogs/kequitypriceupdatedlgdecl.h"
+
+/**
+ * @author Kevin Tambascio & Ace Jones
+ */
+
+class KEquityPriceUpdateDlg : public KEquityPriceUpdateDlgDecl
+{
+ Q_OBJECT
+public:
+ KEquityPriceUpdateDlg(QWidget *parent, const QString& securityId = QString());
+ ~KEquityPriceUpdateDlg();
+ void storePrices(void);
+ MyMoneyPrice price(const QString& id) const;
+
+protected slots:
+ void slotUpdateSelectedClicked(void);
+ void slotUpdateAllClicked(void);
+ void slotUpdateSelection(void);
+
+ void logStatusMessage(const QString&);
+ void logErrorMessage(const QString&);
+ void slotReceivedQuote(const QString&, const QString&,const QDate&, const double&);
+ void slotQuoteFailed(const QString& _id, const QString& _symbol);
+
+protected:
+ void addPricePair(const MyMoneySecurityPair& pair, bool dontCheckExistance = false);
+ void addInvestment(const MyMoneySecurity& inv);
+ void finishUpdate(void);
+
+private:
+ bool m_fUpdateAll;
+ WebPriceQuote m_webQuote;
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kequitypriceupdatedlgdecl.ui b/kmymoney2/dialogs/kequitypriceupdatedlgdecl.ui
new file mode 100644
index 0000000..a06c44d
--- /dev/null
+++ b/kmymoney2/dialogs/kequitypriceupdatedlgdecl.ui
@@ -0,0 +1,179 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KEquityPriceUpdateDlgDecl</class>
+<author>Kevin Tambascio &lt;ktambascio@users.sourceforge.net&gt;</author>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kequitypriceupdatedlgdecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>537</width>
+ <height>482</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Update Stock and Currency Prices</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>lvEquityList</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>350</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="showSortIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="itemsMovable">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>List of known Equities, and the date they were last updated on.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnConfigure</cstring>
+ </property>
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnUpdateAll</cstring>
+ </property>
+ <property name="text">
+ <string>Update All</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnUpdateSelected</cstring>
+ </property>
+ <property name="text">
+ <string>Update Selected</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Status:</string>
+ </property>
+ </widget>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>lbStatus</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>LogText</enum>
+ </property>
+ </widget>
+ <widget class="KProgress">
+ <property name="name">
+ <cstring>prgOnlineProgress</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>91</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnOK</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>2</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kexportdlg.cpp b/kmymoney2/dialogs/kexportdlg.cpp
new file mode 100644
index 0000000..c00e3cf
--- /dev/null
+++ b/kmymoney2/dialogs/kexportdlg.cpp
@@ -0,0 +1,284 @@
+/***************************************************************************
+ kexportdlg.cpp - description
+ -------------------
+ begin : Tue May 22 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kglobal.h>
+#include <klocale.h>
+#if QT_VERSION > 300
+#include <kstandarddirs.h>
+#else
+#include <kstddirs.h>
+#endif
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "kexportdlg.h"
+#include "../mymoney/mymoneycategory.h"
+#include "../dialogs/mymoneyqifprofileeditor.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../widgets/kmymoneyaccountcombo.h"
+#include "../kmymoneyutils.h"
+
+KExportDlg::KExportDlg(QWidget *parent)
+ : KExportDlgDecl(parent, 0, true)
+{
+ // Set (almost) all the last used options
+ readConfig();
+
+ loadProfiles(true);
+ loadAccounts();
+
+ // load button icons
+ KIconLoader* il = KGlobal::iconLoader();
+ m_qbuttonCancel->setGuiItem(KStdGuiItem::cancel());
+
+ KGuiItem okButtenItem( i18n( "&Export" ),
+ QIconSet(il->loadIcon("fileexport", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Start operation"),
+ i18n("Use this to start the export operation"));
+ m_qbuttonOk->setGuiItem(okButtenItem);
+
+ KGuiItem browseButtenItem( i18n( "&Browse..." ),
+ QIconSet(il->loadIcon("fileopen", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Select filename"),
+ i18n("Use this to select a filename to export to"));
+ m_qbuttonBrowse->setGuiItem(browseButtenItem);
+
+ KGuiItem newButtenItem( i18n( "&New..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new profile"),
+ i18n("Use this to open the profile editor"));
+ m_profileEditorButton->setGuiItem(newButtenItem);
+
+
+ // connect the buttons to their functionality
+ connect(m_qbuttonBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowse() ) );
+ connect(m_profileEditorButton, SIGNAL(clicked()), this, SLOT(slotNewProfile()));
+ connect(m_qbuttonOk, SIGNAL(clicked()), this, SLOT(slotOkClicked()));
+ connect(m_qbuttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+ // connect the change signals to the check slot and perform initial check
+ connect(m_qlineeditFile, SIGNAL(textChanged(const QString&)), this, SLOT(checkData()));
+ connect(m_qcheckboxAccount, SIGNAL(toggled(bool)), this, SLOT(checkData()));
+ connect(m_qcheckboxCategories, SIGNAL(toggled(bool)), this, SLOT(checkData()));
+ connect(m_accountComboBox, SIGNAL(accountSelected(const QString&)), this, SLOT(checkData(const QString&)));
+ connect(m_profileComboBox, SIGNAL(highlighted(int)), this, SLOT(checkData()));
+ connect(m_kmymoneydateStart, SIGNAL(dateChanged(const QDate&)), this, SLOT(checkData()));
+ connect(m_kmymoneydateEnd, SIGNAL(dateChanged(const QDate&)), this, SLOT(checkData()));
+
+ checkData(QString());
+}
+
+KExportDlg::~KExportDlg()
+{
+}
+
+void KExportDlg::slotBrowse()
+{
+ QString newName(KFileDialog::getSaveFileName(QString::null,"*.QIF"));
+ KMyMoneyUtils::appendCorrectFileExt(newName, QString("qif"));
+ if (!newName.isEmpty())
+ m_qlineeditFile->setText(newName);
+}
+
+void KExportDlg::slotNewProfile(void)
+{
+ MyMoneyQifProfileEditor* editor = new MyMoneyQifProfileEditor(true, this, "QIF Profile Editor");
+ if(editor->exec()) {
+ m_profileComboBox->setCurrentText(editor->selectedProfile());
+ loadProfiles();
+ }
+ delete editor;
+}
+
+void KExportDlg::loadProfiles(const bool selectLast)
+{
+ // Creating an editor object here makes sure that
+ // we have at least the default profile available
+ MyMoneyQifProfileEditor* edit = new MyMoneyQifProfileEditor(true, 0, 0);
+ edit->slotOk();
+ delete edit;
+
+ QString current = m_profileComboBox->currentText();
+
+ m_profileComboBox->clear();
+
+ QStringList list;
+ KConfig* config = KGlobal::config();
+ config->setGroup("Profiles");
+
+ list = config->readListEntry("profiles");
+ list.sort();
+ m_profileComboBox->insertStringList(list);
+
+ if(selectLast == true) {
+ config->setGroup("Last Use Settings");
+ current = config->readEntry("KExportDlg_LastProfile");
+ }
+
+ m_profileComboBox->setCurrentItem(0);
+ if(list.contains(current) > 0)
+ m_profileComboBox->setCurrentText(current);
+}
+
+void KExportDlg::slotOkClicked()
+{
+ // Make sure we save the last used settings for use next time,
+ writeConfig();
+ accept();
+}
+
+void KExportDlg::readConfig(void)
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("Last Use Settings");
+ m_qlineeditFile->setText(kconfig->readEntry("KExportDlg_LastFile"));
+ m_qcheckboxAccount->setChecked(kconfig->readBoolEntry("KExportDlg_AccountOpt", true));
+ m_qcheckboxCategories->setChecked(kconfig->readBoolEntry("KExportDlg_CatOpt", true));
+ m_kmymoneydateStart->setDate(kconfig->readDateTimeEntry("KExportDlg_StartDate").date());
+ m_kmymoneydateEnd->setDate(kconfig->readDateTimeEntry("KExportDlg_EndDate").date());
+ // m_profileComboBox is loaded in loadProfiles(), so we don't worry here
+ // m_accountComboBox is loaded in loadAccounts(), so we don't worry here
+}
+
+void KExportDlg::writeConfig(void)
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("Last Use Settings");
+ kconfig->writeEntry("KExportDlg_LastFile", m_qlineeditFile->text());
+ kconfig->writeEntry("KExportDlg_AccountOpt", m_qcheckboxAccount->isChecked());
+ kconfig->writeEntry("KExportDlg_CatOpt", m_qcheckboxCategories->isChecked());
+ kconfig->writeEntry("KExportDlg_StartDate", QDateTime(m_kmymoneydateStart->date()));
+ kconfig->writeEntry("KExportDlg_EndDate", QDateTime(m_kmymoneydateEnd->date()));
+ kconfig->writeEntry("KExportDlg_LastProfile", m_profileComboBox->currentText());
+ kconfig->sync();
+}
+
+void KExportDlg::checkData(const QString& accountId)
+{
+ bool okEnabled = false;
+
+ if(!m_qlineeditFile->text().isEmpty()) {
+ QString strFile(m_qlineeditFile->text());
+ if(KMyMoneyUtils::appendCorrectFileExt(strFile, QString("qif")))
+ m_qlineeditFile->setText(strFile);
+ }
+
+ MyMoneyAccount account;
+ if(!accountId.isEmpty()) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ account = file->account(accountId);
+ if(m_lastAccount != accountId) {
+ MyMoneyTransactionFilter filter(accountId);
+ QValueList<MyMoneyTransaction> list = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::Iterator it;
+
+ if(!list.isEmpty()) {
+ it = list.begin();
+ m_kmymoneydateStart->loadDate((*it).postDate());
+ it = list.end();
+ --it;
+ m_kmymoneydateEnd->loadDate((*it).postDate());
+ }
+ m_lastAccount = accountId;
+ m_accountComboBox->setSelected(account);
+ }
+ }
+
+ if(!m_qlineeditFile->text().isEmpty()
+ && m_accountComboBox->selectedAccounts().count() != 0
+ && !m_profileComboBox->currentText().isEmpty()
+ && m_kmymoneydateStart->date() <= m_kmymoneydateEnd->date()
+ && (m_qcheckboxAccount->isChecked() || m_qcheckboxCategories->isChecked()))
+ okEnabled = true;
+
+ m_qbuttonOk->setEnabled(okEnabled);
+}
+
+void KExportDlg::loadAccounts(void)
+{
+/*
+ QStringList strList;
+
+ try {
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ // read all account items from the MyMoneyFile objects and add them to the listbox
+ addCategories(strList, file->liability().id(), QString());
+ addCategories(strList, file->asset().id(), QString());
+
+ } catch (MyMoneyException *e) {
+ qDebug("Exception '%s' thrown in %s, line %ld caught in KExportDlg::loadAccounts:%d",
+ e->what().latin1(), e->file().latin1(), e->line(), __LINE__);
+ delete e;
+ }
+*/
+ m_accountComboBox->loadList((KMyMoneyUtils::categoryTypeE)(KMyMoneyUtils::asset | KMyMoneyUtils::liability));
+
+/*
+ m_accountComboBox->setCurrentItem(0);
+ if(strList.contains(current) > 0)
+ m_accountComboBox->setCurrentText(current);
+*/
+}
+
+QString KExportDlg::accountId() const
+{
+ return m_lastAccount;
+}
+
+/*
+void KExportDlg::addCategories(QStringList& strList, const QString& id, const QString& leadIn) const
+{
+ MyMoneyFile *file = MyMoneyFile::instance();
+ QString name;
+
+ MyMoneyAccount account = file->account(id);
+
+ QStringList accList = account.accountList();
+ QStringList::ConstIterator it_a;
+
+ for(it_a = accList.begin(); it_a != accList.end(); ++it_a) {
+ account = file->account(*it_a);
+ strList << leadIn + account.name();
+ addCategories(strList, *it_a, leadIn + account.name() + ":");
+ }
+}
+
+QString KExportDlg::accountId(const QString& account) const
+{
+ return MyMoneyFile::instance()->nameToAccount(account);
+}
+*/
+
+#include "kexportdlg.moc"
diff --git a/kmymoney2/dialogs/kexportdlg.h b/kmymoney2/dialogs/kexportdlg.h
new file mode 100644
index 0000000..cad5091
--- /dev/null
+++ b/kmymoney2/dialogs/kexportdlg.h
@@ -0,0 +1,180 @@
+/***************************************************************************
+ kexportdlg.h - description
+ -------------------
+ begin : Tue May 22 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KEXPORTDLG_H
+#define KEXPORTDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qstring.h>
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "../widgets/kmymoneydateinput.h"
+#include "../dialogs/kexportdlgdecl.h"
+
+/**
+ * This class is used to select the required user input to export
+ * a specified account to the popular QIF format.
+ * It relies upon the QIF file handling routines in MyMoneyQifProfile and
+ * MyMoneyQifWriter to do the actual writing of QIF files.
+ *
+ * It uses the global KConfig object to read and write the application
+ * settings.
+ *
+ * @see MyMoneyAccount, MyMoneyQifProfile, MyMoneyQifProfileEditor
+ *
+ * @author Felix Rodriguez, Michael Edwardes, Thomas Baumgart 2000-2003
+ *
+ * @short A class to select user data required to export a specified account to the popular QIF format.
+ **/
+class KExportDlg : public KExportDlgDecl
+{
+ Q_OBJECT
+
+public:
+ KExportDlg(QWidget *parent);
+ ~KExportDlg();
+
+ /**
+ * This method returns the filename entered into the edit field
+ *
+ * @return QString with filename
+ */
+ const QString filename(void) const { return m_qlineeditFile->text(); };
+
+ /**
+ * This method returns the account id that has been selected for export
+ *
+ * @return QString with account id
+ */
+ QString accountId(void) const;
+
+ /**
+ * This method returns the name of the profile that has been selected
+ * for the export operation
+ *
+ * @return QString with profile name
+ */
+ const QString profile(void) const { return m_profileComboBox->currentText(); };
+
+ /**
+ * This method returns the start date of the export dialog
+ */
+ const QDate startDate(void) const { return m_kmymoneydateStart->date(); };
+
+ /**
+ * This method returns the end date of the export dialog
+ */
+ const QDate endDate(void) const { return m_kmymoneydateEnd->date(); };
+
+ /**
+ * This method returns the state of the account checkbox
+ */
+ bool accountSelected(void) const { return m_qcheckboxAccount->isChecked(); };
+
+ /**
+ * This method returns the state of the account checkbox
+ */
+ bool categorySelected(void) const { return m_qcheckboxCategories->isChecked(); };
+
+protected slots:
+ /**
+ * Called when the user clicked on the OK button
+ */
+ void slotOkClicked();
+
+ /**
+ * Called when the user needs to browse the filesystem for a QIF file
+ */
+ void slotBrowse();
+
+ /**
+ * Called when the user needs a new profile
+ */
+ void slotNewProfile(void);
+
+ /**
+ * This slot checks whether all data is correct to enable
+ * the 'Export' button. The enable state of the 'Export' button
+ * is updated appropriately.
+ *
+ * If the parameter @p account is not empty, then it is assumed
+ * a new account is selected and the date fields will be loaded
+ * with the date of the first and last transaction within this
+ * account.
+ *
+ * @param account The id of the selected account.
+ */
+ void checkData(const QString& account = QString());
+
+private:
+ void readConfig(void);
+ void writeConfig(void);
+
+ /**
+ * This method loads the available profiles into
+ * the combo box. The parameter @p selectLast controls if
+ * the last profile used is preset or not. If preset is not
+ * selected, the current selection remains. If the currently selected
+ * text is not present in the list anymore, the first item will be
+ * selected.
+ *
+ * @param selectLast If true, the last used profile is selected. The
+ * default is false.
+ */
+ void loadProfiles(const bool selectLast = false);
+
+ /**
+ * This method is used to load the available accounts into the
+ * combo box for selection.
+ */
+ void loadAccounts(void);
+
+ /**
+ * This method is used to load an account hierarchy into a string list
+ *
+ * @param strList Reference to the string list to setup
+ * @param id Account id to add
+ * @param leadIn constant leadin to be added in front of the account name
+ */
+ // void addCategories(QStringList& strList, const QString& id, const QString& leadIn) const;
+
+ /**
+ * This method is used to return the account id of a given account name
+ *
+ * @param account name of the account
+ * @return the ID of the account will be returned.
+ * See MyMoneyFile::nameToAccount() for details.
+ */
+ // QString accountId(const QString& account) const;
+
+private:
+ QString m_lastAccount;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kexportdlgdecl.ui b/kmymoney2/dialogs/kexportdlgdecl.ui
new file mode 100644
index 0000000..5425210
--- /dev/null
+++ b/kmymoney2/dialogs/kexportdlgdecl.ui
@@ -0,0 +1,507 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KExportDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KExportDlgDecl</cstring>
+ </property>
+ <property name="caption">
+ <string>QIF Export</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>MShape</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>MShadow</enum>
+ </property>
+ <property name="text">
+ <string>From this dialog you are able to export transactions to a quicken compatible file, (known as a QIF file, because of the extension). Please enter the path to the QIF file or select it by clicking on the Browse button.
+
+You can choose the file's path, the account and the format of the QIF file (profile). Choose Account to export all the transactions between the specified dates or just categories. You can also limit the transactions that are exported by start and ending date. Once you have pressed the Export button a message box will appear when the export has completed detailing how many transactions, categories and payees were exported.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout45</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lblFileExport</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>File to export to:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_qlineeditFile</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonBrowse</cstring>
+ </property>
+ <property name="text">
+ <string>Browse...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Account to export</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyAccountCombo">
+ <property name="name">
+ <cstring>m_accountComboBox</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout47</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>QIF Profile</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout46</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>m_profileComboBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_profileEditorButton</cstring>
+ </property>
+ <property name="text">
+ <string>New...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_qgroupboxContents</cstring>
+ </property>
+ <property name="title">
+ <string>Contents to Export</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_qcheckboxAccount</cstring>
+ </property>
+ <property name="text">
+ <string>Account</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_qcheckboxCategories</cstring>
+ </property>
+ <property name="text">
+ <string>Categories</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_qgroupboxDates</cstring>
+ </property>
+ <property name="title">
+ <string>Date Range</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyDateInput" row="0" column="1">
+ <property name="name">
+ <cstring>m_kmymoneydateStart</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblEndDate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>End on:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lblStartDate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Start on:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="1" column="1">
+ <property name="name">
+ <cstring>m_kmymoneydateEnd</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>230</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout49</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>451</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>Export</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyDateInput</class>
+ <header location="local">../widgets/kmymoneydateinput.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>1</hordata>
+ <verdata>1</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ <slot access="protected" specifier="">slotDateChosen(QDate date)</slot>
+ </customwidget>
+ <customwidget>
+ <class>KMyMoneyAccountCombo</class>
+ <header location="local">../widgets/kmymoneyaccountcombo.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>3</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image1</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data>
+ </image>
+ <image name="image1">
+ <data format="XPM.GZ" length="3368">789c9595c94eeb581086f73c4544ed50ab6eecd889ad562f1802843961a6d58b632764228c616cf5bb77f9d45fe75e11165c4c703e55d55fc319f8b152bb38daafadfc587a9abbf9b8ac9523f7585be93fcf66ef7ffff3d7bf4bcb715c93df2891d7f21f4bcb5cd4cadac1ddedc003fd02ddf9af16274075ffe3b91738f33c01276aa722b0b753ec390b7c0cce107f092e238d7fa838aa578fe713b0c5bf1aabdddd8033e49f1923be052e11df31867dc77366fe1c81cdbeab1c5b3d4d30f2d351c571dd988fc196ffda731e43cf811b98a79b06d6fa5e8c11ff1458e775054ec0dd8a1b91f9731d9ca9dd0d9513d35ff79c9b9dc7c68ddcdbf7c125ecefca16cf7e9e4994987dcfb34b73d86363e41f559cc6691ff93f8c119f2a3723b5bb8931faffc91abf691cabfd0e9c42ffd21876bf9ea90bf946c6a9f37ca66cf16e0c463fb46a8cf95e0456bb3346be3ad8fa3d34463fcf153763b33b678cf853e516e6415bc688bf31567fde04a7e8cffcd13ffbf56f4afea6ef971265f157bdd218f9d7c0e8878fc0a88ffdfe6f355a51abe1b9ad9c59ff0781fd7e62afdf2a5a79abf0f63765f377857123f2f67bb0e5f3e7256bb4f24cf3ed83fbcad4530efe99e722373e5476981faf05d679ad1aa3fe0b63ad8737c0982fed19c33ea8384ff2284f3c1f283b9be746609dc79bb19e37877837403d3bca458cf3531a23de9fdfbc147fed673bb0d6f7688cfc5960cdd737c6bc87caa2affe8dc09aefc338d17e3be026f291b1fad318ecb0bf38b0f677628cf5f1f7ab4b4c8f7363d4731b58eb2763d43f02231f9f0656bd8631f44cdfe6d535c67afaf9b8d245aef43c05a7e04439c44f8d511f2b9736cf79609d0ff44b9bd719d8ea7b0763fdd89f8742ea6beabfed73e53206df05d6fbecd618e7f311dc84ff0bd82993df7f453fd81f02abdecc58f737a56087fbf3d518f14f81f5bed17afb7dac07b58dd19fbfcfcab418383d3f73e550df36d8fa7f0eacfa57ca03ccbb3b67928ffbc6435eaf10ef92fb3ce06b1e7ef18c78cc138d80bee329dff08c6ff98eeff9811ff989e7fcecdf2ffcca6ffcfed39f0bf93610ef0f5ee5355ee70d6ef3266fc9df6deec8b3c3bbbcf7497f5fb40ff8503c8eb8cb3d6fedf1b1d0099f4accd927fd219f7bef0bf1eaf1255f719d23ff3de606279c7ed26f4addeba25629b738e39c98881c891695d45fd4a7016fd075e54d431ad1980f684253bae11ecde896ee16f41fe95e6c0f9c55def4484f92ab4573afd1a6e785fa5f65264ebc72effd22b1aff446eff421d60b5a5dd09fd39af8af134b254fbe8f8836a84d958aa3ad85fab765de3dea48979b555db4237ebbb447fbf23ea0c3c5fa799b643ea2d595ba7ba2bd2b9e0f744c27dca0d32feaef5029fe056f499767744e173413cb842ee98aea5fe877a4d7a85a577aa148a6b94fb1ecb3091d5183924ffa234a659f9c4ae61b8e6cffd2896837a945d9c2fa8e650fcadea2bc72e3b69399b842a2afe41eebbb81bbfea43f7143d983a91b714a776e4cab74e89f3a6db9899bba9b4ffadf7c82fe6ff857e7f7f7f425e25b39baf3e5fffe5cfa1fdc4beba0</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kfindtransactiondlg.cpp b/kmymoney2/dialogs/kfindtransactiondlg.cpp
new file mode 100644
index 0000000..f122ba2
--- /dev/null
+++ b/kmymoney2/dialogs/kfindtransactiondlg.cpp
@@ -0,0 +1,843 @@
+/***************************************************************************
+ kfindtransactiondlg.cpp
+ -------------------
+ copyright : (C) 2003, 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qtimer.h>
+#include <qtabwidget.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+#include <klistview.h>
+#include <kcombobox.h>
+#include <kstdguiitem.h>
+#include <kiconloader.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kfindtransactiondlg.h"
+
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneychecklistitem.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/register.h>
+#include <kmymoney/transaction.h>
+#include <kmymoney/kmymoneycombo.h>
+
+#include "ksortoptiondlg.h"
+
+KFindTransactionDlg::KFindTransactionDlg(QWidget *parent, const char *name) :
+ KFindTransactionDlgDecl(parent, name, false),
+ m_needReload(false)
+{
+ m_register->installEventFilter(this);
+ m_tabWidget->setTabEnabled(m_resultPage, false);
+
+ // 'cause we don't have a separate setupTextPage
+ connect(m_textEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+
+ setupAccountsPage();
+ setupCategoriesPage();
+ setupDatePage();
+ setupAmountPage();
+ setupPayeesPage();
+ setupDetailsPage();
+
+ // We don't need to add the default into the list (see ::slotShowHelp() why)
+ // m_helpAnchor[m_textTab] = QString("details.search");
+ m_helpAnchor[m_accountTab] = QString("details.search.account");
+ m_helpAnchor[m_dateTab] = QString("details.search.date");
+ m_helpAnchor[m_amountTab] = QString("details.search.amount");
+ m_helpAnchor[m_categoryTab] = QString("details.search.category");
+ m_helpAnchor[m_payeeTab] = QString("details.search.payee");
+ m_helpAnchor[m_detailsTab] = QString("details.search.details");
+
+ // setup the register
+ QValueList<KMyMoneyRegister::Column> cols;
+ cols << KMyMoneyRegister::DateColumn;
+ cols << KMyMoneyRegister::AccountColumn;
+ cols << KMyMoneyRegister::DetailColumn;
+ cols << KMyMoneyRegister::ReconcileFlagColumn;
+ cols << KMyMoneyRegister::PaymentColumn;
+ cols << KMyMoneyRegister::DepositColumn;
+ m_register->setupRegister(MyMoneyAccount(), cols);
+ m_register->setSelectionMode(QTable::Single);
+
+ connect(m_register, SIGNAL(editTransaction()), this, SLOT(slotSelectTransaction()));
+ connect(m_register, SIGNAL(headerClicked()), this, SLOT(slotSortOptions()));
+
+ slotUpdateSelections();
+
+ // setup the connections
+ connect(m_searchButton, SIGNAL(clicked()), this, SLOT(slotSearch()));
+ connect(m_resetButton, SIGNAL(clicked()), this, SLOT(slotReset()));
+ connect(m_resetButton, SIGNAL(clicked()), m_accountsView, SLOT(slotSelectAllAccounts()));
+ connect(m_resetButton, SIGNAL(clicked()), m_categoriesView, SLOT(slotSelectAllAccounts()));
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(deleteLater()));
+ connect(m_helpButton, SIGNAL(clicked()), this, SLOT(slotShowHelp()));
+
+ // only allow searches when a selection has been made
+ connect(this, SIGNAL(selectionEmpty(bool)), m_searchButton, SLOT(setDisabled(bool)));
+
+ // get signal about engine changes
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotRefreshView()));
+
+ slotUpdateSelections();
+
+ m_textEdit->setFocus();
+}
+
+void KFindTransactionDlg::slotReset(void)
+{
+ m_textEdit->setText(QString());
+ m_regExp->setChecked(false);
+ m_caseSensitive->setChecked(false);
+ m_textNegate->setCurrentItem(0);
+
+ m_amountEdit->setEnabled(true);
+ m_amountFromEdit->setEnabled(false);
+ m_amountToEdit->setEnabled(false);
+ m_amountEdit->loadText(QString());
+ m_amountFromEdit->loadText(QString());
+ m_amountToEdit->loadText(QString());
+ m_amountButton->setChecked(true);
+ m_amountRangeButton->setChecked(false);
+
+ m_emptyPayeesButton->setChecked(false);
+ selectAllItems(m_payeesView, true);
+
+ m_typeBox->setCurrentItem(MyMoneyTransactionFilter::allTypes);
+ m_stateBox->setCurrentItem(MyMoneyTransactionFilter::allStates);
+ m_validityBox->setCurrentItem(MyMoneyTransactionFilter::anyValidity);
+
+ m_nrEdit->setEnabled(true);
+ m_nrFromEdit->setEnabled(false);
+ m_nrToEdit->setEnabled(false);
+ m_nrEdit->setText(QString());
+ m_nrFromEdit->setText(QString());
+ m_nrToEdit->setText(QString());
+ m_nrButton->setChecked(true);
+ m_nrRangeButton->setChecked(false);
+
+ m_tabWidget->setTabEnabled(m_resultPage, false);
+ m_tabWidget->setCurrentPage(m_tabWidget->indexOf(m_criteriaTab));
+
+ // the following call implies a call to slotUpdateSelections,
+ // that's why we call it last
+ m_dateRange->setCurrentItem(MyMoneyTransactionFilter::allDates);
+ slotDateRangeChanged(MyMoneyTransactionFilter::allDates);
+}
+
+void KFindTransactionDlg::slotUpdateSelections(void)
+{
+ QString txt;
+
+ // Text tab
+ if(!m_textEdit->text().isEmpty()) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Text");
+ m_regExp->setEnabled(QRegExp(m_textEdit->text()).isValid());
+ } else
+ m_regExp->setEnabled(false);
+
+ m_caseSensitive->setEnabled(!m_textEdit->text().isEmpty());
+ m_textNegate->setEnabled(!m_textEdit->text().isEmpty());
+
+ // Account tab
+ if(!m_accountsView->allItemsSelected()) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Account");
+ }
+
+ // Date tab
+ if(m_dateRange->currentItem() != 0) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Date");
+ }
+
+ // Amount tab
+ if((m_amountButton->isChecked() && m_amountEdit->isValid())
+ || (m_amountRangeButton->isChecked()
+ && (m_amountFromEdit->isValid() || m_amountToEdit->isValid()))) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Amount");
+ }
+
+ // Categories tab
+ if(!m_categoriesView->allItemsSelected()) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Category");
+ }
+
+ // Payees tab
+ if(!allItemsSelected(m_payeesView)
+ || m_emptyPayeesButton->isChecked()) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Payees");
+ }
+ m_payeesView->setEnabled(!m_emptyPayeesButton->isChecked());
+
+ // Details tab
+ if(m_typeBox->currentItem() != 0
+ || m_stateBox->currentItem() != 0
+ || m_validityBox->currentItem() != 0
+ || (m_nrButton->isChecked() && m_nrEdit->text().length() != 0)
+ || (m_nrRangeButton->isChecked()
+ && (m_nrFromEdit->text().length() != 0 || m_nrToEdit->text().length() != 0))) {
+ if(!txt.isEmpty())
+ txt += ", ";
+ txt += i18n("Details");
+ }
+
+ //Show a warning about transfers if Categories are filtered - bug #1523508
+ if(!m_categoriesView->allItemsSelected()) {
+ m_transferWarning->setText( i18n("Warning: Filtering by Category will exclude all transfers from the results.") );
+ } else {
+ m_transferWarning->setText("");
+ }
+
+ // disable the search button if no selection is made
+ emit selectionEmpty(txt.isEmpty());
+
+ if(txt.isEmpty()) {
+ txt = i18n("(None)");
+ }
+ m_selectedCriteria->setText(i18n("Current selections: ") + txt);
+}
+
+bool KFindTransactionDlg::allItemsSelected(const QListViewItem *item) const
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ QCheckListItem* it_c = static_cast<QCheckListItem*>(it_v);
+ if(!(it_c->isOn() && allItemsSelected(it_v)))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool KFindTransactionDlg::allItemsSelected(const QListView* view) const
+{
+ QListViewItem* it_v;
+
+ for(it_v = view->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ QCheckListItem* it_c = static_cast<QCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(!(it_c->isOn() && allItemsSelected(it_v)))
+ return false;
+ } else {
+ if(!allItemsSelected(it_v))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void KFindTransactionDlg::setupAccountsPage(void)
+{
+ m_accountsView->setSelectionMode(QListView::Multi);
+ AccountSet accountSet;
+ accountSet.addAccountGroup(MyMoneyAccount::Asset);
+ accountSet.addAccountGroup(MyMoneyAccount::Liability);
+ //set the accountset to show closed account if the settings say so
+ accountSet.setHideClosedAccounts(KMyMoneyGlobalSettings::hideClosedAccounts());
+ accountSet.load(m_accountsView);
+ connect(m_accountsView, SIGNAL(stateChanged()), this, SLOT(slotUpdateSelections()));
+}
+
+void KFindTransactionDlg::selectAllItems(QListView* view, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = view->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ QCheckListItem* it_c = static_cast<QCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ it_c->setOn(state);
+ }
+ selectAllSubItems(it_v, state);
+ }
+
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::selectItems(QListView* view, const QStringList& list, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = view->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ KMyMoneyCheckListItem* it_c = static_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox && list.contains(it_c->id())) {
+ it_c->setOn(state);
+ }
+ selectSubItems(it_v, list, state);
+ }
+
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::setupCategoriesPage(void)
+{
+ m_categoriesView->setSelectionMode(QListView::Multi);
+ AccountSet categorySet;
+ categorySet.addAccountGroup(MyMoneyAccount::Income);
+ categorySet.addAccountGroup(MyMoneyAccount::Expense);
+ categorySet.load(m_categoriesView);
+ connect(m_categoriesView, SIGNAL(stateChanged()), this, SLOT(slotUpdateSelections()));
+}
+
+void KFindTransactionDlg::selectAllSubItems(QListViewItem* item, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ static_cast<QCheckListItem*>(it_v)->setOn(state);
+ selectAllSubItems(it_v, state);
+ }
+}
+
+void KFindTransactionDlg::selectSubItems(QListViewItem* item, const QStringList& list, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ KMyMoneyCheckListItem* it_c = static_cast<KMyMoneyCheckListItem*>(it_v);
+ if(list.contains(it_c->id()))
+ it_c->setOn(state);
+ selectSubItems(it_v, list, state);
+ }
+}
+
+void KFindTransactionDlg::setupDatePage(void)
+{
+ int i;
+ for(i = MyMoneyTransactionFilter::allDates; i < MyMoneyTransactionFilter::dateOptionCount; ++i) {
+ MyMoneyTransactionFilter::translateDateRange(static_cast<MyMoneyTransactionFilter::dateOptionE>(i), m_startDates[i], m_endDates[i]);
+ }
+
+ connect(m_dateRange, SIGNAL(itemSelected(int)), this, SLOT(slotDateRangeChanged(int)));
+ connect(m_fromDate, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotDateChanged()));
+ connect(m_toDate, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotDateChanged()));
+
+ slotDateRangeChanged(MyMoneyTransactionFilter::allDates);
+}
+
+void KFindTransactionDlg::slotDateRangeChanged(int idx)
+{
+ switch(idx) {
+ case MyMoneyTransactionFilter::allDates:
+ case MyMoneyTransactionFilter::userDefined:
+ m_fromDate->loadDate(QDate());
+ m_toDate->loadDate(QDate());
+ break;
+ default:
+ m_fromDate->loadDate(m_startDates[idx]);
+ m_toDate->loadDate(m_endDates[idx]);
+ break;
+ }
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::slotDateChanged(void)
+{
+ int idx;
+ for(idx = MyMoneyTransactionFilter::asOfToday; idx < MyMoneyTransactionFilter::dateOptionCount; ++idx) {
+ if(m_fromDate->date() == m_startDates[idx]
+ && m_toDate->date() == m_endDates[idx]) {
+ break;
+ }
+ }
+ //if no filter matched, set to user defined
+ if(idx == MyMoneyTransactionFilter::dateOptionCount)
+ idx = MyMoneyTransactionFilter::userDefined;
+
+ m_dateRange->blockSignals(true);
+ m_dateRange->setCurrentItem(static_cast<MyMoneyTransactionFilter::dateOptionE>(idx));
+ m_dateRange->blockSignals(false);
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::setupAmountPage(void)
+{
+ connect(m_amountButton, SIGNAL(clicked()), this, SLOT(slotAmountSelected()));
+ connect(m_amountRangeButton, SIGNAL(clicked()), this, SLOT(slotAmountRangeSelected()));
+
+ connect(m_amountEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+ connect(m_amountFromEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+ connect(m_amountToEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+
+ m_amountButton->setChecked(true);
+ slotAmountSelected();
+}
+
+void KFindTransactionDlg::slotAmountSelected(void)
+{
+ m_amountEdit->setEnabled(true);
+ m_amountFromEdit->setEnabled(false);
+ m_amountToEdit->setEnabled(false);
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::slotAmountRangeSelected(void)
+{
+ m_amountEdit->setEnabled(false);
+ m_amountFromEdit->setEnabled(true);
+ m_amountToEdit->setEnabled(true);
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::setupPayeesPage(void)
+{
+ m_payeesView->setSelectionMode(QListView::Single);
+ m_payeesView->header()->hide();
+
+ loadPayees();
+ m_emptyPayeesButton->setChecked(false);
+
+ connect(m_allPayeesButton, SIGNAL(clicked()), this, SLOT(slotSelectAllPayees()));
+ connect(m_clearPayeesButton, SIGNAL(clicked()), this, SLOT(slotDeselectAllPayees()));
+ connect(m_emptyPayeesButton, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateSelections()));
+}
+
+void KFindTransactionDlg::loadPayees(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyPayee> list;
+ QValueList<MyMoneyPayee>::Iterator it_l;
+
+ list = file->payeeList();
+ // load view
+ for(it_l = list.begin(); it_l != list.end(); ++it_l) {
+ KMyMoneyCheckListItem* item = new KMyMoneyCheckListItem(m_payeesView, (*it_l).name(), QString(), (*it_l).id());
+ connect(item, SIGNAL(stateChanged(bool)), this, SLOT(slotUpdateSelections()));
+ item->setOn(true);
+ }
+}
+void KFindTransactionDlg::slotSelectAllPayees(void)
+{
+ selectAllItems(m_payeesView, true);
+}
+
+void KFindTransactionDlg::slotDeselectAllPayees(void)
+{
+ selectAllItems(m_payeesView, false);
+}
+
+void KFindTransactionDlg::setupDetailsPage(void)
+{
+ connect(m_typeBox, SIGNAL(activated(int)), this, SLOT(slotUpdateSelections()));
+ connect(m_stateBox, SIGNAL(activated(int)), this, SLOT(slotUpdateSelections()));
+ connect(m_validityBox, SIGNAL(activated(int)), this, SLOT(slotUpdateSelections()));
+
+ connect(m_nrButton, SIGNAL(clicked()), this, SLOT(slotNrSelected()));
+ connect(m_nrRangeButton, SIGNAL(clicked()), this, SLOT(slotNrRangeSelected()));
+ connect(m_nrEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+ connect(m_nrFromEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+ connect(m_nrToEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateSelections()));
+
+ m_nrButton->setChecked(true);
+ slotNrSelected();
+}
+
+void KFindTransactionDlg::slotNrSelected(void)
+{
+ m_nrEdit->setEnabled(true);
+ m_nrFromEdit->setEnabled(false);
+ m_nrToEdit->setEnabled(false);
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::slotNrRangeSelected(void)
+{
+ m_nrEdit->setEnabled(false);
+ m_nrFromEdit->setEnabled(true);
+ m_nrToEdit->setEnabled(true);
+ slotUpdateSelections();
+}
+
+void KFindTransactionDlg::addItemToFilter(const opTypeE op, const QString& id)
+{
+ switch(op) {
+ case addAccountToFilter:
+ m_filter.addAccount(id);
+ break;
+ case addCategoryToFilter:
+ m_filter.addCategory(id);
+ break;
+ case addPayeeToFilter:
+ m_filter.addPayee(id);
+ break;
+ }
+}
+
+void KFindTransactionDlg::scanCheckListItems(const QListViewItem* item, const opTypeE op)
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = static_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(it_c->isOn())
+ addItemToFilter(op, (*it_c).id());
+ }
+ scanCheckListItems(it_v, op);
+ }
+ }
+}
+
+void KFindTransactionDlg::scanCheckListItems(const QListView* view, const opTypeE op)
+{
+ QListViewItem* it_v;
+
+ for(it_v = view->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = static_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(it_c->isOn())
+ addItemToFilter(op, (*it_c).id());
+ }
+ scanCheckListItems(it_v, op);
+ }
+ }
+}
+
+void KFindTransactionDlg::setupFilter(void)
+{
+ m_filter.clear();
+
+ // Text tab
+ if(!m_textEdit->text().isEmpty()) {
+ QRegExp exp(m_textEdit->text(), m_caseSensitive->isChecked(), !m_regExp->isChecked());
+ m_filter.setTextFilter(exp, m_textNegate->currentItem() != 0);
+ }
+
+ // Account tab
+ if(!m_accountsView->allItemsSelected()) {
+ // retrieve a list of selected accounts
+ QStringList list;
+ m_accountsView->selectedItems(list);
+
+ // if we're not in expert mode, we need to make sure
+ // that all stock accounts for the selected investment
+ // account are also selected
+ if(!KMyMoneyGlobalSettings::expertMode()) {
+ QStringList missing;
+ QStringList::const_iterator it_a, it_b;
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
+ if(!list.contains(*it_b)) {
+ missing.append(*it_b);
+ }
+ }
+ }
+ }
+ list += missing;
+ }
+
+ m_filter.addAccount(list);
+ }
+
+ // Date tab
+ if(m_dateRange->currentItem() != 0) {
+ m_filter.setDateFilter(m_fromDate->date(), m_toDate->date());
+ }
+
+ // Amount tab
+ if((m_amountButton->isChecked() && m_amountEdit->isValid())) {
+ m_filter.setAmountFilter(m_amountEdit->value(), m_amountEdit->value());
+
+ } else if((m_amountRangeButton->isChecked()
+ && (m_amountFromEdit->isValid() || m_amountToEdit->isValid()))) {
+
+ MyMoneyMoney from(MyMoneyMoney::minValue), to(MyMoneyMoney::maxValue);
+ if(m_amountFromEdit->isValid())
+ from = m_amountFromEdit->value();
+ if(m_amountToEdit->isValid())
+ to = m_amountToEdit->value();
+
+ m_filter.setAmountFilter(from, to);
+ }
+
+ // Categories tab
+ if(!m_categoriesView->allItemsSelected()) {
+ m_filter.addCategory(m_categoriesView->selectedItems());
+ }
+
+ // Payees tab
+ if(m_emptyPayeesButton->isChecked()) {
+ m_filter.addPayee(QString());
+
+ } else if(!allItemsSelected(m_payeesView)) {
+ scanCheckListItems(m_payeesView, addPayeeToFilter);
+ }
+
+ // Details tab
+ if(m_typeBox->currentItem() != 0)
+ m_filter.addType(m_typeBox->currentItem());
+
+ if(m_stateBox->currentItem() != 0)
+ m_filter.addState(m_stateBox->currentItem());
+
+ if(m_validityBox->currentItem() != 0)
+ m_filter.addValidity(m_validityBox->currentItem());
+
+ if(m_nrButton->isChecked() && !m_nrEdit->text().isEmpty())
+ m_filter.setNumberFilter(m_nrEdit->text(), m_nrEdit->text());
+
+ if(m_nrRangeButton->isChecked()
+ && (!m_nrFromEdit->text().isEmpty() || !m_nrToEdit->text().isEmpty())) {
+ m_filter.setNumberFilter(m_nrFromEdit->text(), m_nrToEdit->text());
+ }
+}
+
+void KFindTransactionDlg::slotSearch(void)
+{
+ // setup the filter from the dialog widgets
+ setupFilter();
+
+ // filter is setup, now fill the register
+ slotRefreshView();
+
+ m_register->setFocus();
+}
+
+void KFindTransactionDlg::slotRefreshView(void)
+{
+ m_needReload = true;
+ if(isVisible()) {
+ loadView();
+ m_needReload = false;
+ }
+}
+
+void KFindTransactionDlg::show(void)
+{
+ if(m_needReload) {
+ loadView();
+ m_needReload = false;
+ }
+ KFindTransactionDlgDecl::show();
+}
+
+void KFindTransactionDlg::loadView(void)
+{
+ // setup sort order
+ m_register->setSortOrder(KMyMoneyGlobalSettings::sortSearchView());
+
+ // clear out old data
+ m_register->clear();
+
+ // retrieve the list from the engine
+ MyMoneyFile::instance()->transactionList(m_transactionList, m_filter);
+
+ // create the elements for the register
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::const_iterator it;
+ QMap<QString, int>uniqueMap;
+ MyMoneyMoney deposit, payment;
+
+ int splitCount = 0;
+ for(it = m_transactionList.begin(); it != m_transactionList.end(); ++it) {
+ const MyMoneySplit& split = (*it).second;
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(split.accountId());
+ ++splitCount;
+ uniqueMap[(*it).first.id()]++;
+
+ KMyMoneyRegister::Register::transactionFactory(m_register, (*it).first, (*it).second, uniqueMap[(*it).first.id()]);
+ { // debug stuff
+ if(split.shares().isNegative()) {
+ payment += split.shares().abs();
+ } else {
+ deposit += split.shares().abs();
+ }
+ }
+ }
+
+ // add the group markers
+ m_register->addGroupMarkers();
+
+ // sort the transactions according to the sort setting
+ m_register->sortItems();
+
+ // remove trailing and adjacent markers
+ m_register->removeUnwantedGroupMarkers();
+
+ // turn on the ledger lens for the register
+ m_register->setLedgerLensForced();
+
+ m_register->updateRegister(true);
+
+ m_register->setFocusToTop();
+ m_register->selectItem(m_register->focusItem());
+
+#if KMM_DEBUG
+ m_foundText->setText(i18n("Found %1 matching transactions (D %2 / P %3 = %4)")
+ .arg(splitCount).arg(deposit.formatMoney("", 2)).arg(payment.formatMoney("", 2)).arg((deposit-payment).formatMoney("", 2)));
+#else
+ m_foundText->setText(i18n("Found %1 matching transactions") .arg(splitCount));
+#endif
+
+ m_tabWidget->setTabEnabled(m_resultPage, true);
+ m_tabWidget->setCurrentPage(m_tabWidget->indexOf(m_resultPage));
+
+ QTimer::singleShot(10, this, SLOT(slotRightSize()));
+}
+
+void KFindTransactionDlg::slotRightSize(void)
+{
+ m_register->updateContents();
+}
+
+void KFindTransactionDlg::resizeEvent(QResizeEvent* ev)
+{
+ // Columns
+ // 1 = Date
+ // 2 = Account
+ // 4 = Detail
+ // 5 = C
+ // 6 = Payment
+ // 7 = Deposit
+
+ // don't forget the resizer
+ KFindTransactionDlgDecl::resizeEvent(ev);
+
+ if(!m_register->isVisible())
+ return;
+
+ // resize the register
+ int w = m_register->visibleWidth();
+
+ int m_debitWidth = 80;
+ int m_creditWidth = 80;
+
+ m_register->adjustColumn(1);
+ m_register->adjustColumn(2);
+ m_register->adjustColumn(5);
+
+ m_register->setColumnWidth(6, m_debitWidth);
+ m_register->setColumnWidth(7, m_creditWidth);
+
+ for(int i = 0; i < m_register->numCols(); ++i) {
+ switch(i) {
+ case 4: // skip the one, we want to set
+ break;
+ default:
+ w -= m_register->columnWidth(i);
+ break;
+ }
+ }
+
+ m_register->setColumnWidth(4, w);
+}
+
+
+void KFindTransactionDlg::slotSelectTransaction(void)
+{
+ QValueList<KMyMoneyRegister::RegisterItem*> list = m_register->selectedItems();
+ if(!list.isEmpty()) {
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(list[0]);
+ if(t) {
+ emit transactionSelected(t->split().accountId(), t->transaction().id());
+ hide();
+ }
+ }
+}
+
+bool KFindTransactionDlg::eventFilter(QObject* o, QEvent* e)
+{
+ bool rc = false;
+
+ if(o->isWidgetType()) {
+ if(e->type() == QEvent::KeyPress) {
+ const QWidget* w = dynamic_cast<const QWidget*>(o);
+ QKeyEvent *k = static_cast<QKeyEvent *> (e);
+ if(w == m_register) {
+ switch(k->key()) {
+ default:
+ break;
+
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ rc = true;
+ slotSelectTransaction();
+ break;
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+void KFindTransactionDlg::slotShowHelp(void)
+{
+ QString anchor = m_helpAnchor[m_criteriaTab->currentPage()];
+ if(anchor.isEmpty())
+ anchor = QString("details.search");
+
+ kapp->invokeHelp(anchor);
+}
+
+void KFindTransactionDlg::slotSortOptions(void)
+{
+ KSortOptionDlg* dlg = new KSortOptionDlg(this);
+
+ dlg->setSortOption(KMyMoneyGlobalSettings::sortSearchView(), QString());
+ dlg->hideDefaultButton();
+
+ if(dlg->exec() == QDialog::Accepted) {
+ QString sortOrder = dlg->sortOption();
+ if(sortOrder != KMyMoneyGlobalSettings::sortSearchView()) {
+ KMyMoneyGlobalSettings::setSortSearchView(sortOrder);
+ slotRefreshView();
+ }
+ }
+ delete dlg;
+}
+
+
+// vim:cin:si:ai:et:ts=2:sw=2:
+
+
+#include "kfindtransactiondlg.moc"
diff --git a/kmymoney2/dialogs/kfindtransactiondlg.h b/kmymoney2/dialogs/kfindtransactiondlg.h
new file mode 100644
index 0000000..edf9504
--- /dev/null
+++ b/kmymoney2/dialogs/kfindtransactiondlg.h
@@ -0,0 +1,203 @@
+/***************************************************************************
+ kfindtransactiondlg.h
+ -------------------
+ copyright : (C) 2003 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KFINDTRANSACTIONDLG_H
+#define KFINDTRANSACTIONDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlistview.h>
+#include <qdatetime.h>
+#include <qmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+// #include "../views/kledgerview.h"
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneytransactionfilter.h>
+
+#include "../dialogs/kfindtransactiondlgdecl.h"
+
+class QListView;
+class QListViewItem;
+
+/**
+ * @author Thomas Baumgart
+ */
+class KFindTransactionDlg : public KFindTransactionDlgDecl
+{
+ Q_OBJECT
+public:
+
+ /*
+ // Make sure to keep the following enum valus in sync with the values
+ // used by the GUI in kfindtransactiondlgdecl.ui
+ enum dateOptionE {
+ allDates = 0,
+ asOfToday,
+ currentMonth,
+ currentYear,
+ monthToDate,
+ yearToDate,
+ yearToMonth,
+ lastMonth,
+ lastYear,
+ last7Days,
+ last30Days,
+ last3Months,
+ last6Months,
+ last12Months,
+ next7Days,
+ next30Days,
+ next3Months,
+ next6Months,
+ next12Months,
+ userDefined,
+ last3ToNext3Months,
+ last11Months,
+ // insert new constants above of this line
+ dateOptionCount
+ };
+*/
+ KFindTransactionDlg(QWidget *parent=0, const char *name=0);
+ ~KFindTransactionDlg() {}
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+public slots:
+ void show(void);
+
+protected:
+ void resizeEvent(QResizeEvent*);
+
+protected slots:
+ virtual void slotReset(void);
+ virtual void slotSearch(void);
+
+ /**
+ * This slot opens the detailed help page in khelpcenter. The
+ * anchor for the information is taken from m_helpAnchor.
+ */
+ virtual void slotShowHelp(void);
+
+
+ void slotUpdateSelections(void);
+
+ virtual void slotDateRangeChanged(int);
+ virtual void slotDateChanged(void);
+
+ virtual void slotAmountSelected(void);
+ virtual void slotAmountRangeSelected(void);
+
+ virtual void slotSelectAllPayees(void);
+ virtual void slotDeselectAllPayees(void);
+
+ virtual void slotNrSelected(void);
+ virtual void slotNrRangeSelected(void);
+
+ void slotRefreshView(void);
+
+ /**
+ * This slot selects the current selected transaction/split and emits
+ * the signal @a transactionSelected(const QString& accountId, const QString& transactionId)
+ */
+ void slotSelectTransaction(void);
+
+ void slotRightSize(void);
+
+ void slotSortOptions(void);
+
+signals:
+ void transactionSelected(const QString& accountId, const QString& transactionId);
+
+ /**
+ * This signal is sent out when no selection has been made. It is
+ * used to control the state of the Search button.
+ */
+ void selectionEmpty(bool);
+
+protected:
+ enum opTypeE {
+ addAccountToFilter = 0,
+ addCategoryToFilter,
+ addPayeeToFilter
+ };
+
+ void setupCategoriesPage(void);
+ void setupDatePage(void);
+ void setupAccountsPage(void);
+ void setupAmountPage(void);
+ void setupPayeesPage(void);
+ void setupDetailsPage(void);
+
+ void setupFilter(void);
+
+ void selectAllItems(QListView* view, const bool state);
+ void selectAllSubItems(QListViewItem* item, const bool state);
+ void selectItems(QListView* view, const QStringList& list, const bool state);
+ void selectSubItems(QListViewItem* item, const QStringList& list, const bool state);
+
+ /**
+ * This method loads the m_payeesView with the payees name
+ * found in the engine.
+ */
+ void loadPayees(void);
+
+ /**
+ * This method loads the register with the matching transactions
+ */
+ void loadView(void);
+
+ /**
+ * This method returns information about the selection state
+ * of the items in the m_accountsView.
+ *
+ * @param view pointer to the listview to scan
+ *
+ * @retval true if all items in the view are marked
+ * @retval false if at least one item is not marked
+ *
+ * @note If the view contains no items the method returns @p true.
+ */
+ bool allItemsSelected(const QListView* view) const;
+ bool allItemsSelected(const QListViewItem *item) const;
+
+ void scanCheckListItems(const QListView* view, const opTypeE op);
+ void scanCheckListItems(const QListViewItem* item, const opTypeE op);
+ void addItemToFilter(const opTypeE op, const QString& id);
+
+protected:
+ QDate m_startDates[MyMoneyTransactionFilter::dateOptionCount];
+ QDate m_endDates[MyMoneyTransactionFilter::dateOptionCount];
+
+ /**
+ * This member holds a list of all transactions matching the filter criteria
+ */
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> > m_transactionList;
+
+ MyMoneyTransactionFilter m_filter;
+
+ QMap<QWidget*, QString> m_helpAnchor;
+
+ bool m_needReload;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kfindtransactiondlgdecl.ui b/kmymoney2/dialogs/kfindtransactiondlgdecl.ui
new file mode 100644
index 0000000..3340afd
--- /dev/null
+++ b/kmymoney2/dialogs/kfindtransactiondlgdecl.ui
@@ -0,0 +1,1101 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KFindTransactionDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KFindTransactionDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>771</width>
+ <height>481</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Search transactions</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_criteriaPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Criteria</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Define your search criteria</string>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_criteriaTab</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>3</verstretch>
+ </sizepolicy>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_textTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Text</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="2">
+ <property name="name">
+ <cstring>Spacer20</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>83</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_textEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="0">
+ <item>
+ <property name="text">
+ <string>Contains</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Does not contain</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_textNegate</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_regExp</cstring>
+ </property>
+ <property name="text">
+ <string>Treat text as regular expression</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_caseSensitive</cstring>
+ </property>
+ <property name="text">
+ <string>Case sensitive</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_accountTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Account</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_accountsView</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_dateTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Date</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneyPeriodCombo" row="0" column="1">
+ <property name="name">
+ <cstring>m_dateRange</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Range</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="1" column="1">
+ <property name="name">
+ <cstring>m_fromDate</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>To</string>
+ <comment>To (Date)</comment>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>From</string>
+ <comment>From (Date)</comment>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="2" column="1">
+ <property name="name">
+ <cstring>m_toDate</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer25</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer22</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_amountTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Amount</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout22</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_amountButton</cstring>
+ </property>
+ <property name="text">
+ <string>Search this amount</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_amountRangeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Search amount in the range</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_amountToEdit</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel9</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>to</string>
+ <comment>to (amount)</comment>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_amountEdit</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>from</string>
+ <comment>from (amount)</comment>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_amountFromEdit</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer28</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer27</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>75</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_categoryTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Category</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_categoriesView</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_payeeTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Payee</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout46</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Payee</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_payeesView</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_emptyPayeesButton</cstring>
+ </property>
+ <property name="text">
+ <string>Select transactions without payees</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout45</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_allPayeesButton</cstring>
+ </property>
+ <property name="text">
+ <string>Select all</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_clearPayeesButton</cstring>
+ </property>
+ <property name="text">
+ <string>Select none</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer29</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>42</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_detailsTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Details</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel11_2</cstring>
+ </property>
+ <property name="text">
+ <string>Validity</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel10</cstring>
+ </property>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>All states</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Not reconciled</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Cleared</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Reconciled</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_stateBox</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>All types</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Payments</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Deposits</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Transfers</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_typeBox</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Any transaction</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Valid transaction</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Invalid transaction</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_validityBox</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel11</cstring>
+ </property>
+ <property name="text">
+ <string>State</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer30</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>130</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_nrButton</cstring>
+ </property>
+ <property name="text">
+ <string>Search this number</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_nrRangeButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Search number in range</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel12</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel14</cstring>
+ </property>
+ <property name="text">
+ <string>to</string>
+ <comment>to (number)</comment>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_nrToEdit</cstring>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_nrEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel13</cstring>
+ </property>
+ <property name="text">
+ <string>from</string>
+ <comment>from (number)</comment>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_nrFromEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer31</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer32</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_selectedCriteria</cstring>
+ </property>
+ <property name="text">
+ <string>text</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_transferWarning</cstring>
+ </property>
+ <property name="paletteForegroundColor">
+ <color>
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>warning</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>24</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_resultPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Result</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneyRegister::Register">
+ <column>
+ <property name="text">
+ <string>Security</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Details</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>C</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Payment</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Deposit</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Quantity</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Balance</string>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_register</cstring>
+ </property>
+ <property name="numRows">
+ <number>0</number>
+ </property>
+ <property name="numCols">
+ <number>12</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_foundText</cstring>
+ </property>
+ <property name="text">
+ <string>F</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout25</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_helpButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>11</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>13</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_resetButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Reset</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>21</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_searchButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Find</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>25</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyLineEdit</class>
+ <header location="local">../widgets/kmymoneylineedit.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>kMyMoneyAccountSelector</class>
+ <header location="global">../widgets/kmymoneyaccountselector.h</header>
+ <sizehint>
+ <width>80</width>
+ <height>80</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1110">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000041d49444154388d8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d09a6c508138cb8c13d647141163de49043bca9f1628eb9294810f24f88c15b728b07617358888785d980427290b4a8d00b19a8821da8228cf42316ac87eed9247ac95c9aeaeef9eaabdffb5ebf85f178ccfcf7f5b79fec07a7280a08a008f25ceb7c29e5da573716e65a0be3f198ef6f5ededff9b9e1b34faf90882092a1ea21428b9220ffbf46054055b19386ba6970ae6665b5e0d2c5eb0b066067bbe1f21757c88f5504eff0c192189081303a5582b16854fccce2fe041f00cdd0a8103b874556405476b62d972ec2c2b90ff3fd8df5cb946549d80b34aea15ccaa94625450e2d0e558b460b7371a734b5e027251a155545678ab62d7eea90b4c504078908c107acb354cb251b1f8f08b1c18631aabbb4d18211404804f22545863561d2f060fb34aa8a18d0086204e72c46a32292e1a796f278c1da7a859d8da9a737506db04d0a24103d8949480b214d3bbee952a05c1d536f9d2684160c744f048311543d459eb1b65ee1754cedae13a64abd5d6127053c9d0281f22d4f75c6a2118a5c09272d7ab740638bf4ef2dd2174032d0d8d04c6fe19c32bedd8bc65e342aa3f785e2784bfd6bc1bd9db24b05505616a4edd67d5a8c1801a03a9962754c504bf34b8986acfb9be91cac7d54315a15541b36b134f74bd2dc53940115a5381e087bc25c6f71be831a8baa234cc1ee3eeb74ed83116beb2b8849d108a3730e8ce27e2bfb82419a7b407ac7c222fd0e6280a8078ce64e47ef54ac9d5be9aaae0162e0de568a44a18d3df90845d919c4f01463406340a44f40efb43a99b371618488e2670d1a2d7ee6f1d3be39342104e937ed85fb86599c33e9ee0be9a004946259d8b858909880d59aa00daa0d3280b5f39e34074c4b3a5434029a76a9e9f5cc0163b5c80024158a1cfc4cb1d3061d5834066cb0a403c008599a70f6bc27b8d03106ea3ae91987278c5b143b015547224ab5e24185cd9b81665273e7b6e7cecd82ddbf8098002de94049737bc09828cf3036f31c3735c8b0e98eb704672f348c7f7c93cd1fb2ae905119ff54e0dff3542b0e9dd983dcea2cc5eea6cf303e74ec687af5c41b6fa38f5e203c7ec8e1238ef85831a214afef21060ea781ec68247b65c6916353cc8b73d1ae79354606af2a930709aa118da1636c274dd7e3774b884a79aa6b5711a538d33cf9c01c1c9b83bc6a1f55c91ccb23b05b1deb43a7decdaffefd2862f61366aa8449c69e33642f012f2bb208fa98eeda1f3346f076c8eeef19475e9be115423364f78f84105a8643d34d90cfbfdcd8cf872589a45dc7f54cf3134a36f4e495c23f9da8db15bccb708d4014f2ca512cb5d4f7c13e84300d5cff6eb39b202bab053bdb9674f0648609427d0f8402ddeac30f4fcd3ced3efc3b422d406c09b340bedc1571e1bfc3d44dc281634c5fe5e758e7395cfbe6d6c130fd17d92372d277c159b70000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kgncimportoptionsdlg.cpp b/kmymoney2/dialogs/kgncimportoptionsdlg.cpp
new file mode 100644
index 0000000..e11ff69
--- /dev/null
+++ b/kmymoney2/dialogs/kgncimportoptionsdlg.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+ kgncimportoptions.cpp
+ -------------------
+ copyright : (C) 2005 by Ace Jones
+ author : Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+#include <qapplication.h>
+#include <qcombobox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kapplication.h>
+#include <kurlrequester.h>
+#include <ktextbrowser.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kgncimportoptionsdlg.h"
+
+// dialog constructor
+KGncImportOptionsDlg::KGncImportOptionsDlg(QWidget *parent, const char *name)
+ : KGncImportOptionsDlgDecl(parent, name)
+{
+ buttonInvestGroup->setRadioButtonExclusive (true);
+ buttonInvestGroup->setButton (0);
+ checkFinanceQuote->setChecked(true);
+ checkSchedules->setChecked (false);
+ buildCodecList (); // build list of codecs and insert into combo box
+ checkDecode->setChecked (false);
+ comboDecode->setEnabled (false);
+ checkTxNotes->setChecked (false);
+ checkDebugGeneral->setChecked (false);
+ checkDebugXML->setChecked (false);
+ checkAnonymize->setChecked (false);
+
+ connect (checkDecode, SIGNAL(toggled(bool)), this, SLOT(slotDecodeOptionChanged(bool)));
+}
+
+KGncImportOptionsDlg::~KGncImportOptionsDlg()
+{
+}
+
+// enable the combo box for selection if required
+void KGncImportOptionsDlg::slotDecodeOptionChanged(bool isOn) {
+ if (isOn) {
+ comboDecode->setEnabled (true);
+ comboDecode->setCurrentItem (0);
+ } else {
+ comboDecode->setEnabled (false);
+ }
+}
+
+// build a list of known codecs and sort it so that the locale codec is first
+// try to get the others in some sort of order of likelihood
+void KGncImportOptionsDlg::buildCodecList () {
+
+ m_localeCodec = QTextCodec::codecForLocale();
+ m_codecList.setAutoDelete (true);
+ // retrieve all codec pointers
+ QTextCodec *codec;
+ unsigned int i;
+ for (i = 0; (codec = QTextCodec::codecForIndex(i)); i++) {
+ int rank;
+ if (codec == m_localeCodec) rank = 999; // ensure locale rank comes first
+ else rank = codec->heuristicNameMatch(m_localeCodec->name());
+
+ codecData *p = new codecData(rank, codec);
+ m_codecList.append (p);
+ }
+ m_codecList.sort();
+ for (i = 0; i < m_codecList.count(); i++) {
+ QString name (m_codecList.at(i)->second->name());
+ comboDecode->insertItem (name);
+ }
+}
+
+// this routine sorts the codec list on 1) rank descending 2) codec name ascending
+int codecDataList::compareItems (void *a, void *b) {
+ codecData *pa = reinterpret_cast<codecData *>(a);
+ codecData *pb = reinterpret_cast<codecData *>(b);
+
+ if (pa->first > pb->first) {
+ return (-1); // greater rank is treated as less-than so gets sorted first
+ } else { if (pb->first > pa->first)
+ return (1);
+ }
+ // ranks are equal, sort on name, case insensitive
+ QString sa(pa->second->name());
+ QString sb(pb->second->name());
+ if (sa.lower() > sb.lower()) {
+ return (1);
+ } else {
+ return (-1);
+ }
+}
+
+// return selected codec or 0
+QTextCodec* KGncImportOptionsDlg::decodeOption(void) {
+ if (!checkDecode->isChecked()) {
+ return (0);
+ } else {
+ return (m_codecList.at(comboDecode->currentItem())->second);
+ }
+}
+
+void KGncImportOptionsDlg::slotHelp(void)
+{
+ kapp->invokeHelp ("details.impexp.gncoptions");
+}
+
+#include "kgncimportoptionsdlg.moc"
diff --git a/kmymoney2/dialogs/kgncimportoptionsdlg.h b/kmymoney2/dialogs/kgncimportoptionsdlg.h
new file mode 100644
index 0000000..5ab6202
--- /dev/null
+++ b/kmymoney2/dialogs/kgncimportoptionsdlg.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ kgncimportoptions.h
+ -------------------
+ copyright : (C) 2005 by Ace Jones
+ author : Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KGNCIMPORTOPTIONSDLG_H
+#define KGNCIMPORTOPTIONSDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qtextcodec.h>
+#include <qptrlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../dialogs/kgncimportoptionsdlgdecl.h"
+
+typedef QPair<int, QTextCodec*> codecData;
+
+// class to sort codec list
+class codecDataList : public QPtrList<codecData> {
+ int compareItems (QPtrCollection::Item a, QPtrCollection::Item b);
+};
+
+class KGncImportOptionsDlg : public KGncImportOptionsDlgDecl
+{
+Q_OBJECT
+public:
+ KGncImportOptionsDlg(QWidget *parent = 0, const char *name = 0);
+ ~KGncImportOptionsDlg();
+
+ int investmentOption () const {return (buttonInvestGroup->selectedId());};
+ bool quoteOption() const {return (checkFinanceQuote->isChecked());};
+ bool scheduleOption () const {return (checkSchedules->isChecked());};
+ QTextCodec* decodeOption ();
+ bool txNotesOption () const {return (checkTxNotes->isChecked());};
+ bool generalDebugOption () const {return (checkDebugGeneral->isChecked());};
+ bool xmlDebugOption () const {return (checkDebugXML->isChecked());};
+ bool anonymizeOption () const {return (checkAnonymize->isChecked());};
+
+public slots:
+ void slotDecodeOptionChanged (bool);
+ void slotHelp();
+
+private:
+ void buildCodecList ();
+
+ QTextCodec* m_localeCodec;
+ codecDataList m_codecList;
+
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kgncimportoptionsdlgdecl.ui b/kmymoney2/dialogs/kgncimportoptionsdlgdecl.ui
new file mode 100644
index 0000000..e32197b
--- /dev/null
+++ b/kmymoney2/dialogs/kgncimportoptionsdlgdecl.ui
@@ -0,0 +1,383 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KGncImportOptionsDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KGncImportOptionsDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>526</width>
+ <height>638</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>GnuCash Import Options</string>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>9</y>
+ <width>442</width>
+ <height>636</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Use 'Help' for more information on these options</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonInvestGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Investment Handling</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioInvest1</cstring>
+ </property>
+ <property name="text">
+ <string>One investment account for each stock</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioInvest2</cstring>
+ </property>
+ <property name="text">
+ <string>One investment account for all stocks</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioInvest3</cstring>
+ </property>
+ <property name="text">
+ <string>Prompt for an investment account for each stock</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup5</cstring>
+ </property>
+ <property name="title">
+ <string>Online price quotes</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkFinanceQuote</cstring>
+ </property>
+ <property name="text">
+ <string>Use Finance::Quote for share price quotes</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Scheduled Transactions</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkSchedules</cstring>
+ </property>
+ <property name="text">
+ <string>Drop suspect scheduled transactions</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup4</cstring>
+ </property>
+ <property name="title">
+ <string>Decoding option</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkDecode</cstring>
+ </property>
+ <property name="text">
+ <string>Decode using</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>comboDecode</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup18</cstring>
+ </property>
+ <property name="title">
+ <string>Transaction Notes option</string>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkTxNotes</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>420</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Use transaction notes on non-split transactions</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup3</cstring>
+ </property>
+ <property name="title">
+ <string>Debug Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkDebugGeneral</cstring>
+ </property>
+ <property name="text">
+ <string>General debug data</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkDebugXML</cstring>
+ </property>
+ <property name="text">
+ <string>Display XML data</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkAnonymize</cstring>
+ </property>
+ <property name="text">
+ <string>Anonymize data</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>200</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KGncImportOptionsDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KGncImportOptionsDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>buttonHelp</sender>
+ <signal>clicked()</signal>
+ <receiver>KGncImportOptionsDlgDecl</receiver>
+ <slot>slotHelp()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">slotHelp()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kgncpricesourcedlg.cpp b/kmymoney2/dialogs/kgncpricesourcedlg.cpp
new file mode 100644
index 0000000..2246e01
--- /dev/null
+++ b/kmymoney2/dialogs/kgncpricesourcedlg.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+ kgncpricesourcedlg.cpp
+ -------------------
+ copyright : (C) 2005 by Ace Jones
+ author : Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qlayout.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kapplication.h>
+#include <kurlrequester.h>
+#include <ktextbrowser.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kgncpricesourcedlg.h"
+#include "../converter/webpricequote.h"
+
+KGncPriceSourceDlg::KGncPriceSourceDlg(QWidget *parent, const char *name)
+ : KGncPriceSourceDlgDecl(parent, name)
+{
+}
+KGncPriceSourceDlg::KGncPriceSourceDlg(const QString &stockName, const QString &gncSource){
+ // signals and slots connections
+ connect( buttonGroup5, SIGNAL( released(int) ), this, SLOT( buttonPressed(int) ) );
+ connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( slotHelp() ) );
+ // initialize data fields
+ textStockName->setText (i18n ("Investment: %1").arg(stockName));
+ textGncSource->setText (i18n ("Quote source: %1").arg(gncSource));
+ listKnownSource->insertStringList (WebPriceQuote::quoteSources());
+ lineUserSource->setText (gncSource);
+ checkAlwaysUse->setChecked(true);
+ buttonGroup5->setButton (0);
+ buttonPressed (0);
+ return;
+}
+
+KGncPriceSourceDlg::~KGncPriceSourceDlg()
+{
+}
+
+enum ButtonIds {NOSOURCE = 0, KMMSOURCE, USERSOURCE};
+
+void KGncPriceSourceDlg::buttonPressed (int buttonId) {
+ m_currentButton = buttonId;
+ switch (m_currentButton) {
+ case NOSOURCE:
+ listKnownSource->clearSelection();
+ listKnownSource->setEnabled (false);
+ lineUserSource->deselect();
+ lineUserSource->setEnabled (false);
+ break;
+ case KMMSOURCE:
+ lineUserSource->deselect ();
+ lineUserSource->setEnabled (false);
+ listKnownSource->setEnabled (true);
+ listKnownSource->setFocus();
+ listKnownSource->setSelected (0, true);
+ break;
+ case USERSOURCE:
+ listKnownSource->clearSelection();
+ listKnownSource->setEnabled (false);
+ lineUserSource->setEnabled (true);
+ lineUserSource->selectAll();
+ lineUserSource->setFocus ();
+ break;
+ }
+}
+
+QString KGncPriceSourceDlg::selectedSource() const {
+ QString s;
+ switch (m_currentButton) {
+ case NOSOURCE: s = ""; break;
+ case KMMSOURCE: s = listKnownSource->currentText(); break;
+ case USERSOURCE: s = lineUserSource->text(); break;
+ }
+ return (s);
+}
+
+void KGncPriceSourceDlg::slotHelp(void)
+{
+ kapp->invokeHelp ("details.impexp.gncquotes");
+}
+
+#include "kgncpricesourcedlg.moc"
+
diff --git a/kmymoney2/dialogs/kgncpricesourcedlg.h b/kmymoney2/dialogs/kgncpricesourcedlg.h
new file mode 100644
index 0000000..6351b02
--- /dev/null
+++ b/kmymoney2/dialogs/kgncpricesourcedlg.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ kgncpricesourcedlg.h
+ -------------------
+ copyright : (C) 2005 by Ace Jones
+ author : Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KGNCPRICESOURCEDLG_H
+#define KGNCPRICESOURCEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/kgncpricesourcedlgdecl.h"
+
+class KGncPriceSourceDlg : public KGncPriceSourceDlgDecl
+{
+ Q_OBJECT
+public:
+ KGncPriceSourceDlg(QWidget *parent = 0, const char *name = 0);
+ KGncPriceSourceDlg(const QString &stockName, const QString &gncSource);
+ ~KGncPriceSourceDlg();
+
+ QString selectedSource () const;
+ bool alwaysUse() const { return (checkAlwaysUse->isChecked()); }
+
+public slots:
+ void buttonPressed(int);
+ void slotHelp();
+
+private:
+ int m_currentButton;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kgncpricesourcedlgdecl.ui b/kmymoney2/dialogs/kgncpricesourcedlgdecl.ui
new file mode 100644
index 0000000..c781f81
--- /dev/null
+++ b/kmymoney2/dialogs/kgncpricesourcedlgdecl.ui
@@ -0,0 +1,248 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KGncPriceSourceDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KGncPriceSourceDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>619</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Online Quotes - Select price source</string>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>400</y>
+ <width>496</width>
+ <height>50</height>
+ </rect>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>91</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOK</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>171</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>1</y>
+ <width>525</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textStockName</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textGncSource</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>This price source is not known to KMyMoney. Please select an option below.</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup5</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>buttonNoSource</cstring>
+ </property>
+ <property name="text">
+ <string>Do not perform online quotes for this investment</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>buttonSelectSource</cstring>
+ </property>
+ <property name="text">
+ <string>Select a known KMyMoney source from the list below</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>listKnownSource</cstring>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>buttonUserSource</cstring>
+ </property>
+ <property name="text">
+ <string>Use the following name for the price source.
+(Click Help for further information.)</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>lineUserSource</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkAlwaysUse</cstring>
+ </property>
+ <property name="text">
+ <string>Always use this selection for this price source.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>370</height>
+ </size>
+ </property>
+ </spacer>
+ </widget>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOK</sender>
+ <signal>released()</signal>
+ <receiver>KGncPriceSourceDlgDecl</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kgpgkeyselectiondlg.cpp b/kmymoney2/dialogs/kgpgkeyselectiondlg.cpp
new file mode 100644
index 0000000..37ddcc5
--- /dev/null
+++ b/kmymoney2/dialogs/kgpgkeyselectiondlg.cpp
@@ -0,0 +1,149 @@
+/***************************************************************************
+ kgpgkeyselectiondlg.cpp
+ -------------------
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <keditlistbox.h>
+#include <kled.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kgpgkeyselectiondlg.h"
+#include <kmymoney/kgpgfile.h>
+
+KGpgKeySelectionDlg::KGpgKeySelectionDlg(QWidget *parent, const char *name) :
+ KDialogBase(parent, name, true, i18n("Select additional keys"), Ok | Cancel),
+ m_needCheckList(true),
+ m_listOk(false),
+ m_checkCount(0)
+{
+ QWidget* page = new QWidget(this);
+ setMainWidget(page);
+ QVBoxLayout* topLayout = new QVBoxLayout(page, 0, spacingHint());
+
+ m_listBox = new KEditListBox(page);
+ m_listBox->setTitle(i18n("User identification"));
+ m_listBox->setButtons( int( KEditListBox::Remove | KEditListBox::Add ) );
+ QWhatsThis::add( m_listBox, i18n( "Enter the id of the key you want to use for data encryption. This can either be an e-mail address or the hexadecimal key id. In case of the key id don't forget the leading 0x." ) );
+
+ topLayout->addWidget(m_listBox);
+
+ // add a LED for the availability of all keys
+ QHBoxLayout* ledBox = new QHBoxLayout(0, 0, 6, "ledBoxLayout");
+ m_keyLed = new KLed(page);
+ m_keyLed->setShape( KLed::Circular );
+ m_keyLed->setLook( KLed::Sunken );
+
+ ledBox->addWidget(m_keyLed);
+ ledBox->addWidget(new QLabel(i18n("Keys for all of the above user ids found"), page));
+ ledBox->addItem(new QSpacerItem( 50, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ));
+
+ topLayout->addLayout(ledBox);
+
+ connect(m_listBox, SIGNAL(changed()), this, SLOT(slotIdChanged()));
+ connect(m_listBox, SIGNAL(added(const QString&)), this, SLOT(slotKeyListChanged()));
+ connect(m_listBox, SIGNAL(removed(const QString&)), this, SLOT(slotKeyListChanged()));
+}
+
+void KGpgKeySelectionDlg::setKeys(const QStringList& list)
+{
+ m_listBox->clear();
+ m_listBox->insertStringList(list);
+ slotKeyListChanged();
+}
+
+#if 0
+void KGpgKeySelectionDlg::slotShowHelp(void)
+{
+ QString anchor = m_helpAnchor[m_criteriaTab->currentPage()];
+ if(anchor.isEmpty())
+ anchor = QString("details.search");
+
+ kapp->invokeHelp(anchor);
+}
+#endif
+
+void KGpgKeySelectionDlg::slotKeyListChanged(void)
+{
+ m_needCheckList = true;
+ slotIdChanged();
+}
+
+void KGpgKeySelectionDlg::slotIdChanged(void)
+{
+ // this looks a bit awkward. Here's why: KGPGFile::keyAvailable() starts
+ // an external task and processes UI events while it waits for the external
+ // process to finish. Thus, the first time we get here, the external process
+ // is started and the user may press a second key which calls this routine
+ // again.
+ //
+ // The second invocation is counted, but the check is not started until the
+ // first one finishes. Once the external process finishes, we check if we
+ // were called in the meantime and restart the check.
+ if(++m_checkCount == 1) {
+ while(1) {
+ // first we check the current edit field if filled
+ bool keysOk = true;
+ if(!m_listBox->currentText().isEmpty()) {
+ keysOk = KGPGFile::keyAvailable(m_listBox->currentText());
+ }
+
+ // if it is available, then scan the current list if we need to
+ if(keysOk) {
+ if(m_needCheckList) {
+ QStringList keys = m_listBox->items();
+ QStringList::const_iterator it_s;
+ for(it_s = keys.begin(); keysOk && it_s != keys.end(); ++it_s) {
+ if(!KGPGFile::keyAvailable(*it_s))
+ keysOk = false;
+ }
+ m_listOk = keysOk;
+ m_needCheckList = false;
+
+ } else {
+ keysOk = m_listOk;
+ }
+ }
+
+ // did we receive some more requests to check?
+ if(m_checkCount > 1) {
+ m_checkCount = 1;
+ continue;
+ }
+
+ m_keyLed->setState(static_cast<KLed::State>(keysOk && (m_listBox->items().count() != 0) ? KLed::On : KLed::Off));
+ enableButtonOK((m_listBox->items().count() == 0) || (m_keyLed->state() == KLed::On));
+ break;
+ }
+
+ --m_checkCount;
+ }
+}
+
+
+#include "kgpgkeyselectiondlg.moc"
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kgpgkeyselectiondlg.h b/kmymoney2/dialogs/kgpgkeyselectiondlg.h
new file mode 100644
index 0000000..4355478
--- /dev/null
+++ b/kmymoney2/dialogs/kgpgkeyselectiondlg.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ kgpgkeyselectiondlg.h
+ -------------------
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KGPGKEYSELECTIONDLG_H
+#define KGPGKEYSELECTIONDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdialogbase.h>
+class KEditListBox;
+class KLed;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ * @author Thomas Baumgart
+ */
+class KGpgKeySelectionDlg : public KDialogBase
+{
+ Q_OBJECT
+public:
+
+ KGpgKeySelectionDlg(QWidget *parent=0, const char *name=0);
+ virtual ~KGpgKeySelectionDlg() {}
+
+ /**
+ * preset the key list with the given key ids in @a list
+ */
+ void setKeys(const QStringList& list);
+
+ /**
+ * Returns the list of keys currently listed in the KEditListBox
+ */
+ const QStringList keys(void) const { return m_listBox->items(); }
+
+protected slots:
+ void slotIdChanged(void);
+ void slotKeyListChanged(void);
+
+private:
+ KEditListBox* m_listBox;
+ KLed* m_keyLed;
+ bool m_needCheckList;
+ bool m_listOk;
+ int m_checkCount;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kimportdlg.cpp b/kmymoney2/dialogs/kimportdlg.cpp
new file mode 100644
index 0000000..c9cc2d5
--- /dev/null
+++ b/kmymoney2/dialogs/kimportdlg.cpp
@@ -0,0 +1,228 @@
+/***************************************************************************
+ kimportdlg.cpp - description
+ -------------------
+ begin : Wed May 16 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qlineedit.h>
+#include <qtextstream.h>
+#include <qprogressbar.h>
+#include <qlabel.h>
+#include <qbuttongroup.h>
+#include <qpixmap.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kglobalsettings.h>
+#include <kpushbutton.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "kimportdlg.h"
+#include <kmymoney/mymoneyfile.h>
+#include "mymoneyqifprofileeditor.h"
+#include "../converter/mymoneyqifprofile.h"
+
+KImportDlg::KImportDlg(QWidget *parent, const char * name)
+ : KImportDlgDecl(parent, name, TRUE)
+{
+ // Set all the last used options
+ readConfig();
+
+ loadProfiles(true);
+
+ // load button icons
+ m_qbuttonCancel->setGuiItem(KStdGuiItem::cancel());
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem okButtenItem( i18n( "&Import" ),
+ QIconSet(il->loadIcon("fileimport", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Start operation"),
+ i18n("Use this to start the import operation"));
+ m_qbuttonOk->setGuiItem(okButtenItem);
+
+ KGuiItem browseButtenItem( i18n( "&Browse..." ),
+ QIconSet(il->loadIcon("fileopen", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Select filename"),
+ i18n("Use this to select a filename to export to"));
+ m_qbuttonBrowse->setGuiItem(browseButtenItem);
+
+ KGuiItem newButtenItem( i18n( "&New..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new profile"),
+ i18n("Use this to open the profile editor"));
+ m_profileEditorButton->setGuiItem(newButtenItem);
+
+ // connect the buttons to their functionality
+ connect(m_qbuttonBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowse() ) );
+ connect(m_qbuttonOk, SIGNAL(clicked()), this, SLOT(slotOkClicked()));
+ connect(m_qbuttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_profileEditorButton, SIGNAL(clicked()), this, SLOT(slotNewProfile()));
+
+ // connect the change signals to the check slot and perform initial check
+ connect(m_qlineeditFile, SIGNAL(textChanged(const QString&)), this,
+ SLOT(slotFileTextChanged(const QString&)));
+
+ // setup button enable status
+ slotFileTextChanged(m_qlineeditFile->text());
+}
+
+KImportDlg::~KImportDlg()
+{
+}
+
+void KImportDlg::slotBrowse()
+{
+ // determine what the browse prefix should be from the current profile
+
+ MyMoneyQifProfile tmpprofile;
+ tmpprofile.loadProfile("Profile-" + profile());
+
+ KFileDialog dialog(KGlobalSettings::documentPath(),
+ i18n("%1|Import files\n%2|All files (*.*)").arg(tmpprofile.filterFileType()).arg("*"),
+ this, i18n("Import File..."), true);
+ dialog.setMode(KFile::File | KFile::ExistingOnly);
+
+ if(dialog.exec() == QDialog::Accepted) {
+#if KDE_IS_VERSION(3,4,0)
+ m_qlineeditFile->setText(dialog.selectedURL().pathOrURL());
+#else
+ m_qlineeditFile->setText(dialog.selectedURL().prettyURL(0, KURL::StripFileProtocol));
+#endif
+ }
+}
+
+void KImportDlg::slotOkClicked()
+{
+ // Save the used options.
+ writeConfig();
+ // leave dialog directly
+ accept();
+}
+
+void KImportDlg::readConfig(void)
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("Last Use Settings");
+ m_qlineeditFile->setText(kconfig->readEntry("KImportDlg_LastFile"));
+}
+
+void KImportDlg::writeConfig(void)
+{
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("Last Use Settings");
+ kconfig->writeEntry("KImportDlg_LastFile", m_qlineeditFile->text());
+ kconfig->writeEntry("KImportDlg_LastProfile", m_profileComboBox->currentText());
+ kconfig->sync();
+}
+
+/** Make sure the text input is ok */
+void KImportDlg::slotFileTextChanged(const QString& text)
+{
+ if (!text.isEmpty() && KIO::NetAccess::exists(text, true, qApp->mainWidget())) {
+ // m_qcomboboxDateFormat->setEnabled(true);
+ m_qbuttonOk->setEnabled(true);
+ m_qlineeditFile->setText(text);
+ } else {
+ // m_qcomboboxDateFormat->setEnabled(false);
+ m_qbuttonOk->setEnabled(false);
+ }
+}
+
+void KImportDlg::slotNewProfile(void)
+{
+ MyMoneyQifProfileEditor* editor = new MyMoneyQifProfileEditor(true, this, "QIF Profile Editor");
+
+ if(editor->exec()) {
+ m_profileComboBox->setCurrentText(editor->selectedProfile());
+ loadProfiles();
+ }
+
+ delete editor;
+}
+
+void KImportDlg::slotSelectProfile(const QString& profile)
+{
+ m_profileComboBox->setCurrentText(profile);
+ loadProfiles();
+}
+
+void KImportDlg::loadProfiles(const bool selectLast)
+{
+ // Creating an editor object here makes sure that
+ // we have at least the default profile available
+ MyMoneyQifProfileEditor* edit = new MyMoneyQifProfileEditor(true, 0, 0);
+ edit->slotOk();
+ delete edit;
+
+ QString current = m_profileComboBox->currentText();
+
+ m_profileComboBox->clear();
+
+ QStringList list;
+ KConfig* config = KGlobal::config();
+ config->setGroup("Profiles");
+
+ list = config->readListEntry("profiles");
+ list.sort();
+ m_profileComboBox->insertStringList(list);
+
+ if(selectLast == true) {
+ config->setGroup("Last Use Settings");
+ current = config->readEntry("KImportDlg_LastProfile");
+ }
+
+ m_profileComboBox->setCurrentItem(0);
+ if(list.contains(current) > 0) {
+ m_profileComboBox->setCurrentText(current);
+ }
+}
+
+void KImportDlg::addCategories(QStringList& strList, const QString& id, const QString& leadIn) const
+{
+ MyMoneyFile *file = MyMoneyFile::instance();
+ QString name;
+
+ MyMoneyAccount account = file->account(id);
+
+ QStringList accList = account.accountList();
+ QStringList::ConstIterator it_a;
+
+ for(it_a = accList.begin(); it_a != accList.end(); ++it_a) {
+ account = file->account(*it_a);
+ strList << leadIn + account.name();
+ addCategories(strList, *it_a, leadIn + account.name() + MyMoneyFile::AccountSeperator);
+ }
+}
+
+
+#include "kimportdlg.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kimportdlg.h b/kmymoney2/dialogs/kimportdlg.h
new file mode 100644
index 0000000..06f1003
--- /dev/null
+++ b/kmymoney2/dialogs/kimportdlg.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ kimportdlg.h - description
+ -------------------
+ begin : Wed May 16 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KIMPORTDLG_H
+#define KIMPORTDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Headers
+
+#include <qstring.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kurl.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Headers
+
+#include "../dialogs/kimportdlgdecl.h"
+
+/**
+ * This class is used to import a qif file to an account.
+ * It relies upon the QIF file handling routines in MyMoneyAccount to do
+ * the actual writing of QIF files.
+ *
+ * It uses the global KConfig object to read and write the application
+ * settings.
+ *
+ * @see MyMoneyAccount
+ *
+ * @author Felix Rodriguez, Michael Edwardes 2000-2001
+ *
+ * @short A class to import a qif file to an account.
+**/
+class KImportDlg : public KImportDlgDecl
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Standard constructor
+ */
+ KImportDlg(QWidget *parent, const char *name = 0);
+
+ /** Standard destructor */
+ ~KImportDlg();
+
+ /**
+ */
+ const QString filename(void) const { return m_qlineeditFile->text(); };
+
+ /**
+ */
+ const QString profile(void) const { return m_profileComboBox->currentText(); };
+
+protected slots:
+ /** Called to let the user browse for a QIF file to import from. */
+ void slotBrowse();
+
+ /** Test whether to enable the buttons */
+ void slotFileTextChanged(const QString& text);
+
+ /**
+ * Called when the user needs a new profile
+ */
+ void slotNewProfile(void);
+
+ void slotOkClicked(void);
+
+ void slotSelectProfile(const QString& text);
+
+private:
+ /**
+ * This method loads the available profiles into
+ * the combo box. The parameter @p selectLast controls if
+ * the last profile used is preset or not. If preset is not
+ * selected, the current selection remains. If the currently selected
+ * text is not present in the list anymore, the first item will be
+ * selected.
+ *
+ * @param selectLast If true, the last used profile is selected. The
+ * default is false.
+ */
+ void loadProfiles(const bool selectLast = false);
+
+ /**
+ * This method is used to load an account hierarchy into a string list
+ *
+ * @param strList Reference to the string list to setup
+ * @param id Account id to add
+ * @param leadIn constant leadin to be added in front of the account name
+ */
+ void addCategories(QStringList& strList, const QString& id, const QString& leadIn) const;
+
+ void readConfig(void);
+ void writeConfig(void);
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kimportdlgdecl.ui b/kmymoney2/dialogs/kimportdlgdecl.ui
new file mode 100644
index 0000000..c915f12
--- /dev/null
+++ b/kmymoney2/dialogs/kimportdlgdecl.ui
@@ -0,0 +1,246 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KImportDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KImportDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>476</width>
+ <height>303</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>QIF Import</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="resizePolicy">
+ <enum>Manual</enum>
+ </property>
+ <property name="text">
+ <string>From this dialog you are able to import transactions from a Quicken&lt;b&gt;&amp;trade;&lt;/b&gt; compatible file, (known as a QIF file, because of the extension).&lt;p&gt;
+
+Please enter the path to the QIF file or select it by clicking on the Browse button. Once you have the file's path press the Import button and KMyMoney will import all the transactions, categories and payees it finds.</string>
+ </property>
+ <property name="wordWrap">
+ <enum>WidgetWidth</enum>
+ </property>
+ <property name="autoFormatting">
+ <set>AutoAll</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lblImportFile</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>QIF File to Import:</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_optionGroupBox</cstring>
+ </property>
+ <property name="title">
+ <string>Import options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Bank statement</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Other application</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_typeComboBox</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select &lt;b&gt;Bank statement&lt;/b&gt; turns on automatic category matching which is turned off in case of &lt;b&gt;Historic data&lt;/b&gt;. Use the latter if you import files from other Personal Finance Management software.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Source of QIF</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>QIF Profile</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_profileComboBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_profileEditorButton</cstring>
+ </property>
+ <property name="text">
+ <string>New...</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="KPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_qbuttonBrowse</cstring>
+ </property>
+ <property name="text">
+ <string>Browse...</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_qlineeditFile</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout90</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>411</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>Import</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kloadtemplatedlg.cpp b/kmymoney2/dialogs/kloadtemplatedlg.cpp
new file mode 100644
index 0000000..d765f8a
--- /dev/null
+++ b/kmymoney2/dialogs/kloadtemplatedlg.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ kloadtemplatedlg.cpp
+ -------------------
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kstdguiitem.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kloadtemplatedlg.h"
+#include "../widgets/kaccounttemplateselector.h"
+
+KLoadTemplateDlg::KLoadTemplateDlg(QWidget* parent, const char* name) :
+ KLoadTemplateDlgDecl(parent, name)
+{
+ buttonOk->setGuiItem(KStdGuiItem::ok());
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+ buttonHelp->setGuiItem(KStdGuiItem::help());
+
+ connect(buttonHelp, SIGNAL(clicked()), this, SLOT(slotHelp()));
+}
+
+QValueList<MyMoneyTemplate> KLoadTemplateDlg::templates(void) const
+{
+ return m_templateSelector->selectedTemplates();
+}
+
+void KLoadTemplateDlg::slotHelp(void)
+{
+}
+
+#include "kloadtemplatedlg.moc"
diff --git a/kmymoney2/dialogs/kloadtemplatedlg.h b/kmymoney2/dialogs/kloadtemplatedlg.h
new file mode 100644
index 0000000..44fdfee
--- /dev/null
+++ b/kmymoney2/dialogs/kloadtemplatedlg.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ kloadtemplatedlg.h
+ -------------------
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KLOADTEMPLATEDLG_H
+#define KLOADTEMPLATEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytemplate.h>
+#include "../dialogs/kloadtemplatedlgdecl.h"
+
+/// This dialog lets the user load more account templates
+class KLoadTemplateDlg : public KLoadTemplateDlgDecl
+{
+ Q_OBJECT
+
+ public:
+ KLoadTemplateDlg(QWidget *parent = 0, const char *name = 0);
+
+ QValueList<MyMoneyTemplate> templates(void) const;
+
+ private slots:
+ void slotHelp(void);
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kloadtemplatedlgdecl.ui b/kmymoney2/dialogs/kloadtemplatedlgdecl.ui
new file mode 100644
index 0000000..4790de9
--- /dev/null
+++ b/kmymoney2/dialogs/kloadtemplatedlgdecl.ui
@@ -0,0 +1,106 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KLoadTemplateDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KLoadTemplateDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>636</width>
+ <height>509</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>MyDialog</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KAccountTemplateSelector">
+ <property name="name">
+ <cstring>m_templateSelector</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>228</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KLoadTemplateDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KLoadTemplateDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kmergetransactionsdlg.cpp b/kmymoney2/dialogs/kmergetransactionsdlg.cpp
new file mode 100644
index 0000000..692c88f
--- /dev/null
+++ b/kmymoney2/dialogs/kmergetransactionsdlg.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ kmergetransactionsdlg.cpp
+ -------------------
+ begin : Sun Aug 20 2006
+ copyright : (C) 2006 by Ace Jones
+ email : <acejones@users.sf.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <kactivelabel.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmergetransactionsdlg.h"
+
+KMergeTransactionsDlg::KMergeTransactionsDlg(const MyMoneyAccount& account, QWidget* parent, const char* name) :
+ KSelectTransactionsDlg(account, parent, name)
+{
+
+ // setup descriptive texts
+ setCaption(i18n("Merge Transactions"));
+ m_description->setText(i18n("Are you sure you wish to merge these transactions?"));
+
+ // no selection possible
+ m_register->setSelectionMode(QTable::NoSelection);
+
+ // override default and enable ok button right away
+ buttonOk->setEnabled(true);
+}
+
+void KMergeTransactionsDlg::slotHelp(void)
+{
+ kapp->invokeHelp("details.ledgers.match");
+}
+
+#include "kmergetransactionsdlg.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kmergetransactionsdlg.h b/kmymoney2/dialogs/kmergetransactionsdlg.h
new file mode 100644
index 0000000..ebbfd82
--- /dev/null
+++ b/kmymoney2/dialogs/kmergetransactionsdlg.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ kmergetransactionsdlg.h
+ -------------------
+ begin : Sun Aug 20 2006
+ copyright : (C) 2006 by Ace Jones
+ email : <acejones@users.sf.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMERGETRANSACTIONSDLG_H
+#define KMERGETRANSACTIONSDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QResizeEvent;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/register.h>
+#include <kmymoney/mymoneyaccount.h>
+
+#include "../dialogs/kselecttransactionsdlg.h"
+
+class KMergeTransactionsDlg: public KSelectTransactionsDlg
+{
+ Q_OBJECT
+public:
+ KMergeTransactionsDlg(const MyMoneyAccount& account, QWidget* parent = 0, const char* name = 0);
+
+ bool eventFilter(QObject* , QEvent* ) { return false; }
+
+public slots:
+ void slotHelp();
+};
+
+#endif // KMERGETRANSACTIONSDLG_H
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kmymoneyfileinfodlg.cpp b/kmymoney2/dialogs/kmymoneyfileinfodlg.cpp
new file mode 100644
index 0000000..108c776
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneyfileinfodlg.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+ kmymoneyfileinfodlg.cpp - description
+ -------------------
+ begin : Sun Oct 9 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyfileinfodlg.h"
+#include <kmymoney/imymoneystorage.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyutils.h>
+
+KMyMoneyFileInfoDlg::KMyMoneyFileInfoDlg(QWidget *parent, const char *name )
+ : KMyMoneyFileInfoDlgDecl(parent, name)
+{
+ // Hide the unused buttons.
+ buttonCancel->hide();
+ buttonHelp->hide();
+
+ // Now fill the fields with data
+ IMyMoneyStorage* storage = MyMoneyFile::instance()->storage();
+
+ m_creationDate->setText(storage->creationDate().toString(Qt::ISODate));
+ m_lastModificationDate->setText(storage->lastModificationDate().toString(Qt::ISODate));
+ m_baseCurrency->setText(storage->value("kmm-baseCurrency"));
+
+ m_payeeCount->setText(QString("%1").arg(storage->payeeList().count()));
+ m_institutionCount->setText(QString("%1").arg(storage->institutionList().count()));
+
+ QValueList<MyMoneyAccount> a_list;
+ storage->accountList(a_list);
+ m_accountCount->setText(QString("%1").arg(a_list.count()));
+
+ QMap<MyMoneyAccount::accountTypeE, int> accountMap;
+ QMap<MyMoneyAccount::accountTypeE, int> accountMapClosed;
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ for(it_a = a_list.begin(); it_a != a_list.end(); ++it_a) {
+ accountMap[(*it_a).accountType()] = accountMap[(*it_a).accountType()] + 1;
+ accountMapClosed[(*it_a).accountType()] = accountMapClosed[(*it_a).accountType()] + 0;
+ if((*it_a).isClosed())
+ accountMapClosed[(*it_a).accountType()] = accountMapClosed[(*it_a).accountType()] + 1;
+ }
+
+ QMap<MyMoneyAccount::accountTypeE, int>::const_iterator it_m;
+ for(it_m = accountMap.begin(); it_m != accountMap.end(); ++it_m) {
+ new KListViewItem(m_accountView, KMyMoneyUtils::accountTypeToString(it_m.key()), QString("%1").arg(*it_m), QString("%1").arg(accountMapClosed[it_m.key()]));
+ }
+
+
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits(false);
+ m_transactionCount->setText(QString("%1").arg(storage->transactionList(filter).count()));
+ filter.setReportAllSplits(true);
+ m_splitCount->setText(QString("%1").arg(storage->transactionList(filter).count()));
+ m_scheduleCount->setText(QString("%1").arg(storage->scheduleList().count()));
+ MyMoneyPriceList list = storage->priceList();
+ MyMoneyPriceList::const_iterator it_p;
+ int pCount = 0;
+ for(it_p = list.begin(); it_p != list.end(); ++it_p)
+ pCount += (*it_p).count();
+ m_priceCount->setText(QString("%1").arg(pCount));
+}
+
+KMyMoneyFileInfoDlg::~KMyMoneyFileInfoDlg()
+{
+}
+
+#include "kmymoneyfileinfodlg.moc"
diff --git a/kmymoney2/dialogs/kmymoneyfileinfodlg.h b/kmymoney2/dialogs/kmymoneyfileinfodlg.h
new file mode 100644
index 0000000..9ba7f56
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneyfileinfodlg.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ kmymoneyfileinfodlg.h - description
+ -------------------
+ begin : Sun Oct 9 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYFILEINFODLG_H
+#define KMYMONEYFILEINFODLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/kmymoneyfileinfodlgdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KMyMoneyFileInfoDlg : public KMyMoneyFileInfoDlgDecl
+{
+ Q_OBJECT
+public:
+ KMyMoneyFileInfoDlg(QWidget *parent=0, const char *name=0);
+ virtual ~KMyMoneyFileInfoDlg();
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kmymoneyfileinfodlgdecl.ui b/kmymoney2/dialogs/kmymoneyfileinfodlgdecl.ui
new file mode 100644
index 0000000..fe2cd18
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneyfileinfodlgdecl.ui
@@ -0,0 +1,358 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KMyMoneyFileInfoDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KMyMoneyFileInfoDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>521</width>
+ <height>471</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>File Information</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_baseCurrency</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="9" column="1">
+ <property name="name">
+ <cstring>m_scheduleCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="KListView" row="6" column="0" rowspan="1" colspan="2">
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Total</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Closed</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_accountView</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Accounts/Categories</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="10" column="0">
+ <property name="name">
+ <cstring>textLabel19</cstring>
+ </property>
+ <property name="text">
+ <string>Prices</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Created on</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="10" column="1">
+ <property name="name">
+ <cstring>m_priceCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="9" column="0">
+ <property name="name">
+ <cstring>textLabel9</cstring>
+ </property>
+ <property name="text">
+ <string>Schedules</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="0">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Transactions</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="8" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Splits</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payeeCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_institutionCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Institutions</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_creationDate</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="1">
+ <property name="name">
+ <cstring>m_transactionCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>m_accountCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel10</cstring>
+ </property>
+ <property name="text">
+ <string>Payees</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Base currency</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Last modified on</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="8" column="1">
+ <property name="name">
+ <cstring>m_splitCount</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_lastModificationDate</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>120</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>2</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KMyMoneyFileInfoDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KMyMoneyFileInfoDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kmymoneypricedlg.cpp b/kmymoney2/dialogs/kmymoneypricedlg.cpp
new file mode 100644
index 0000000..cd8d66f
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneypricedlg.cpp
@@ -0,0 +1,258 @@
+/***************************************************************************
+ kmymoneypricedlg.cpp
+ -------------------
+ begin : Wed Nov 24 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneypricedlg.h"
+#include "kupdatestockpricedlg.h"
+#include "kcurrencycalculator.h"
+#include "../widgets/kmymoneypriceview.h"
+#include "kequitypriceupdatedlg.h"
+#include <kmymoney/kmymoneycurrencyselector.h>
+#include <kmymoney/mymoneyfile.h>
+
+#include "../kmymoneyglobalsettings.h"
+
+#define COMMODITY_COL 0
+#define CURRENCY_COL 1
+#define DATE_COL 2
+#define PRICE_COL 3
+#define SOURCE_COL 4
+
+KMyMoneyPriceDlg::KMyMoneyPriceDlg(QWidget* parent, const char *name) :
+ KMyMoneyPriceDlgDecl(parent, name)
+{
+ KIconLoader *il = KGlobal::iconLoader();
+ KGuiItem removeButtenItem( i18n( "&Delete" ),
+ QIconSet(il->loadIcon("delete", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Delete this entry"),
+ i18n("Remove this price item from the file"));
+ m_deleteButton->setGuiItem(removeButtenItem);
+
+ KGuiItem newButtenItem( i18n( "&New" ),
+ QIconSet(il->loadIcon("file_new", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Add a new entry"),
+ i18n("Create a new price entry."));
+ m_newButton->setGuiItem(newButtenItem);
+
+ KGuiItem editButtenItem( i18n( "&Edit" ),
+ QIconSet(il->loadIcon("edit", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Modify the selected entry"),
+ i18n("Change the details of selected price information."));
+ m_editButton->setGuiItem(editButtenItem);
+
+ KGuiItem okButtenItem( i18n("&Close" ),
+ QIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Close the dialog"),
+ i18n("Use this to close the dialog and return to the application."));
+ m_closeButton->setGuiItem(okButtenItem);
+
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_editButton, SIGNAL(clicked()), this, SLOT(slotEditPrice()));
+ connect(m_priceList, SIGNAL(editPrice()), this, SLOT(slotEditPrice()));
+ connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeletePrice()));
+ connect(m_priceList, SIGNAL(deletePrice()), this, SLOT(slotDeletePrice()));
+ connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewPrice()));
+ connect(m_priceList, SIGNAL(newPrice()), this, SLOT(slotNewPrice()));
+ connect(m_priceList, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotSelectPrice(QListViewItem*)));
+ connect(m_onlineQuoteButton, SIGNAL(clicked()), this, SLOT(slotOnlinePriceUpdate()));
+ connect(m_priceList, SIGNAL(onlinePriceUpdate()), this, SLOT(slotOnlinePriceUpdate()));
+
+ connect(m_showAllPrices, SIGNAL(toggled(bool)), this, SLOT(slotLoadWidgets()));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+
+ slotLoadWidgets();
+ slotSelectPrice(0);
+
+ // FIXME: for now, we don't have the logic to delete all prices in a given date range
+ m_deleteRangeButton->setEnabled(false);
+}
+
+KMyMoneyPriceDlg::~KMyMoneyPriceDlg()
+{
+}
+
+void KMyMoneyPriceDlg::slotLoadWidgets(void)
+{
+ m_priceList->clear();
+
+ MyMoneyPriceList list = MyMoneyFile::instance()->priceList();
+ MyMoneyPriceList::ConstIterator it_l;
+ for(it_l = list.begin(); it_l != list.end(); ++it_l) {
+ MyMoneyPriceEntries::ConstIterator it_e;
+ if(m_showAllPrices->isChecked()) {
+ for(it_e = (*it_l).begin(); it_e != (*it_l).end(); ++it_e) {
+ new KMyMoneyPriceItem(m_priceList, *it_e);
+ }
+ } else {
+ if((*it_l).count() > 0) {
+ it_e = (*it_l).end();
+ --it_e;
+ new KMyMoneyPriceItem(m_priceList, *it_e);
+ }
+ }
+ }
+}
+
+void KMyMoneyPriceDlg::slotSelectPrice(QListViewItem * item)
+{
+ m_currentItem = item;
+ m_editButton->setEnabled(item != 0);
+ m_deleteButton->setEnabled(item != 0);
+
+ // Modification of automatically added entries is not allowed
+ if(item) {
+ KMyMoneyPriceItem* priceitem = dynamic_cast<KMyMoneyPriceItem*>(item);
+ if(priceitem && (priceitem->price().source() == "KMyMoney")) {
+ m_editButton->setEnabled(false);
+ m_deleteButton->setEnabled(false);
+ }
+ }
+}
+
+void KMyMoneyPriceDlg::slotNewPrice(void)
+{
+ KUpdateStockPriceDlg dlg(this);
+ KMyMoneyPriceItem* item = dynamic_cast<KMyMoneyPriceItem*>(m_priceList->selectedItem());
+ if(item) {
+ MyMoneySecurity security;
+ security = MyMoneyFile::instance()->security(item->price().from());
+ dlg.m_security->setSecurity(security);
+ security = MyMoneyFile::instance()->security(item->price().to());
+ dlg.m_currency->setSecurity(security);
+ }
+
+ if(dlg.exec()) {
+ MyMoneyPrice price(dlg.m_security->security().id(), dlg.m_currency->security().id(), dlg.date(), MyMoneyMoney(1,1));
+ KMyMoneyPriceItem* p = new KMyMoneyPriceItem(m_priceList, price);
+ m_priceList->setSelected(p, true);
+ // If the user cancels the following operation, we delete the new item
+ // and re-select any previously selected one
+ if(slotEditPrice() == QDialog::Rejected) {
+ delete p;
+ if(item)
+ m_priceList->setSelected(item, true);
+ }
+ }
+}
+
+int KMyMoneyPriceDlg::slotEditPrice(void)
+{
+ int rc = QDialog::Rejected;
+ KMyMoneyPriceItem* item = dynamic_cast<KMyMoneyPriceItem*>(m_priceList->selectedItem());
+ if(item) {
+ MyMoneySecurity from(MyMoneyFile::instance()->security(item->price().from()));
+ MyMoneySecurity to(MyMoneyFile::instance()->security(item->price().to()));
+ signed64 fract = MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision());
+
+ KCurrencyCalculator calc(from,
+ to,
+ MyMoneyMoney(1,1),
+ item->price().rate(to.id()),
+ item->price().date(),
+ fract,
+ this, "currencyCalculator");
+ calc.setupPriceEditor();
+
+ rc = calc.exec();
+ }
+ return rc;
+}
+
+
+void KMyMoneyPriceDlg::slotDeletePrice(void)
+{
+ KMyMoneyPriceItem* item = dynamic_cast<KMyMoneyPriceItem*>(m_priceList->selectedItem());
+ if(item) {
+ if(KMessageBox::questionYesNo(this, i18n("Do you really want to delete the selected price entry?"), i18n("Delete price information"), KStdGuiItem::yes(), KStdGuiItem::no(), "DeletePrice") == KMessageBox::Yes) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->removePrice(item->price());
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ qDebug("Cannot delete price");
+ delete e;
+ }
+ }
+ }
+}
+
+void KMyMoneyPriceDlg::slotOnlinePriceUpdate(void)
+{
+ KMyMoneyPriceItem* item = dynamic_cast<KMyMoneyPriceItem*>(m_priceList->selectedItem());
+ if(item)
+ {
+ KEquityPriceUpdateDlg dlg(this, (item->text(COMMODITY_COL)+" "+item->text(CURRENCY_COL)).utf8());
+ if(dlg.exec() == QDialog::Accepted)
+ dlg.storePrices();
+ } else {
+ KEquityPriceUpdateDlg dlg(this);
+ if(dlg.exec() == QDialog::Accepted)
+ dlg.storePrices();
+ }
+}
+
+#if 0
+// This function is not needed. However, removing the KUpdateStockPriceDlg
+// instantiation below causes link failures:
+
+// This seems to be fixed, so I #if 0'ed it out. Let's see, if someone
+// complains and if not, we get rid of this whole block one day. (2007-06-22 ipwizard)
+//
+// kmymoney2/widgets/kmymoneypriceview.cpp:179: undefined reference to
+// `KUpdateStockPriceDlg::KUpdateStockPriceDlg[in-charge](QWidget*, char const*)'
+// kmymoney2/widgets/kmymoneypriceview.cpp:204: undefined reference to
+// `KUpdateStockPriceDlg::KUpdateStockPriceDlg[in-charge](QDate const&, QString const&, QWidget*, char const*)'
+void KEditEquityEntryDlg_useless(void)
+{
+ delete new KUpdateStockPriceDlg();
+}
+#endif
+
+// Make sure, that these definitions are only used within this file
+// this does not seem to be necessary, but when building RPMs the
+// build option 'final' is used and all CPP files are concatenated.
+// So it could well be, that in another CPP file these definitions
+// are also used.
+#undef COMMODITY_COL
+#undef CURRENCY_COL
+#undef DATE_COL
+#undef PRICE_COL
+#undef SOURCE_COL
+
+
+#include "kmymoneypricedlg.moc"
diff --git a/kmymoney2/dialogs/kmymoneypricedlg.h b/kmymoney2/dialogs/kmymoneypricedlg.h
new file mode 100644
index 0000000..c7e7c99
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneypricedlg.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ kmymoneypricedlg.h
+ -------------------
+ begin : Wed Nov 24 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYPRICEDLG_H
+#define KMYMONEYPRICEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneypricedlgdecl.h"
+#include "kmymoney/mymoneyprice.h"
+
+class KMyMoneyPriceDlg : public KMyMoneyPriceDlgDecl
+{
+ Q_OBJECT
+public:
+ KMyMoneyPriceDlg(QWidget* parent, const char *name);
+ ~KMyMoneyPriceDlg();
+
+protected slots:
+ void slotSelectPrice(QListViewItem* item);
+ void slotNewPrice(void);
+ void slotDeletePrice(void);
+ int slotEditPrice(void);
+ void slotLoadWidgets(void);
+ void slotOnlinePriceUpdate(void);
+
+private:
+ QListViewItem* m_currentItem;
+};
+
+#endif // KMYMONEYPRICEDLG_H
diff --git a/kmymoney2/dialogs/kmymoneypricedlgdecl.ui b/kmymoney2/dialogs/kmymoneypricedlgdecl.ui
new file mode 100644
index 0000000..27895e3
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneypricedlgdecl.ui
@@ -0,0 +1,220 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KMyMoneyPriceDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KMyMoneyPriceDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>806</width>
+ <height>440</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Price Editor</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneyPriceView">
+ <property name="name">
+ <cstring>m_priceList</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_showAllPrices</cstring>
+ </property>
+ <property name="text">
+ <string>Show all stored prices</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_newButton</cstring>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_editButton</cstring>
+ </property>
+ <property name="text">
+ <string>Modify</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteRangeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Delete Range...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>150</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_onlineQuoteButton</cstring>
+ </property>
+ <property name="text">
+ <string>Online Quotes</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>560</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KMyMoneyPriceView</class>
+ <header location="local">../widgets/kmymoneypriceview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="826">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154789cb59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a0901e2257b0000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>m_newButton</tabstop>
+ <tabstop>m_editButton</tabstop>
+ <tabstop>m_deleteButton</tabstop>
+ <tabstop>m_onlineQuoteButton</tabstop>
+ <tabstop>m_closeButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kmymoneysplittable.cpp b/kmymoney2/dialogs/kmymoneysplittable.cpp
new file mode 100644
index 0000000..5b5f1af
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneysplittable.cpp
@@ -0,0 +1,999 @@
+/***************************************************************************
+ kmymoneysplittable.cpp - description
+ -------------------
+ begin : Thu Jan 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kdecompat.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qglobal.h>
+#include <qpainter.h>
+#include <qcursor.h>
+#include <qapplication.h>
+#include <qtimer.h>
+#include <qlayout.h>
+#include <qeventloop.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kcompletionbox.h>
+#include <kpushbutton.h>
+#include <kpopupmenu.h>
+#include <kstdaccel.h>
+#include <kshortcut.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneysplittable.h"
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "../dialogs/kcurrencycalculator.h"
+
+#include "../mymoney/mymoneyutils.h"
+
+kMyMoneySplitTable::kMyMoneySplitTable(QWidget *parent, const char *name ) :
+ QTable(parent,name),
+ m_currentRow(0),
+ m_maxRows(0),
+ m_editMode(false),
+ m_amountWidth(80),
+ m_editCategory(0),
+ m_editMemo(0),
+ m_editAmount(0)
+{
+ // setup the transactions table
+ setNumRows(1);
+ setNumCols(3);
+ horizontalHeader()->setLabel(0, i18n("Category"));
+ horizontalHeader()->setLabel(1, i18n("Memo"));
+ horizontalHeader()->setLabel(2, i18n("Amount"));
+ setSelectionMode(QTable::NoSelection);
+ setLeftMargin(0);
+ verticalHeader()->hide();
+ setColumnStretchable(0, false);
+ setColumnStretchable(1, false);
+ setColumnStretchable(2, false);
+ horizontalHeader()->setResizeEnabled(false);
+ horizontalHeader()->setMovingEnabled(false);
+ horizontalHeader()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
+
+ setVScrollBarMode(QScrollView::AlwaysOn);
+ // never show a horizontal scroll bar
+ setHScrollBarMode(QScrollView::AlwaysOff);
+
+ // setup the context menu
+ m_contextMenu = new KPopupMenu(this);
+ KIconLoader *il = KGlobal::iconLoader();
+ m_contextMenu->insertTitle(il->loadIcon("transaction", KIcon::MainToolbar), i18n("Split Options"));
+ m_contextMenu->insertItem(il->loadIcon("edit", KIcon::Small), i18n("Edit..."), this, SLOT(slotStartEdit()));
+ m_contextMenuDuplicate = m_contextMenu->insertItem(il->loadIcon("editcopy", KIcon::Small), i18n("Duplicate"), this, SLOT(slotDuplicateSplit()));
+ m_contextMenuDelete = m_contextMenu->insertItem(il->loadIcon("delete", KIcon::Small),
+ i18n("Delete ..."),
+ this, SLOT(slotDeleteSplit()));
+
+ connect(this, SIGNAL(clicked(int, int, int, const QPoint&)),
+ this, SLOT(slotSetFocus(int, int, int, const QPoint&)));
+
+ connect(this, SIGNAL(transactionChanged(const MyMoneyTransaction&)),
+ this, SLOT(slotUpdateData(const MyMoneyTransaction&)));
+}
+
+kMyMoneySplitTable::~kMyMoneySplitTable()
+{
+}
+
+void kMyMoneySplitTable::setup(const QMap<QString, MyMoneyMoney>& priceInfo)
+{
+ m_priceInfo = priceInfo;
+}
+
+const QColor kMyMoneySplitTable::rowBackgroundColor(const int row) const
+{
+ return (row % 2) ? KMyMoneyGlobalSettings::listColor() : KMyMoneyGlobalSettings::listBGColor();
+}
+
+void kMyMoneySplitTable::paintCell(QPainter *p, int row, int col, const QRect& r, bool /*selected*/)
+{
+ QColorGroup g = colorGroup();
+ QColor textColor;
+
+ g.setColor(QColorGroup::Base, rowBackgroundColor(row));
+
+ p->setFont(KMyMoneyGlobalSettings::listCellFont());
+
+ QString firsttext = text(row, col);
+ QString qstringCategory;
+ QString qstringMemo;
+
+ int intPos = firsttext.find("|");
+ if(intPos > -1)
+ {
+ qstringCategory = firsttext.left(intPos);
+ qstringMemo = firsttext.mid(intPos + 1);
+ }
+
+ QRect rr = r;
+ QRect rr2 = r;
+ rr.setX(0);
+ rr.setY(0);
+ rr.setWidth(columnWidth(col));
+ rr.setHeight(rowHeight(row));
+
+ rr2.setX(2);
+ rr2.setY(0);
+ rr2.setWidth(columnWidth(col)-4);
+ rr2.setHeight(rowHeight(row));
+
+
+ if(row == m_currentRow) {
+ QBrush backgroundBrush(g.highlight());
+ textColor = g.highlightedText();
+ p->fillRect(rr,backgroundBrush);
+
+ } else {
+ QBrush backgroundBrush(g.base());
+ textColor = g.text();
+ p->fillRect(rr,backgroundBrush);
+ }
+
+ if (KMyMoneyGlobalSettings::showGrid()) {
+ p->setPen(KMyMoneyGlobalSettings::listGridColor());
+ if(col != 0)
+ p->drawLine(rr.x(), 0, rr.x(), rr.height()-1); // left frame
+ p->drawLine(rr.x(), rr.y(), rr.width(), 0); // bottom frame
+ p->setPen(textColor);
+ }
+
+ switch (col) {
+ case 0: // category
+ case 1: // memo
+ p->drawText(rr2, Qt::AlignLeft | Qt::AlignVCenter, text(row, col));
+ break;
+
+ case 2: // amount
+ p->drawText(rr2, Qt::AlignRight | Qt::AlignVCenter,firsttext);
+ break;
+ }
+}
+
+/** Override the QTable member function to avoid display of focus */
+void kMyMoneySplitTable::paintFocus(QPainter * /* p */, const QRect & /*cr*/)
+{
+}
+
+void kMyMoneySplitTable::columnWidthChanged(int col)
+{
+ for (int i=0; i<numRows(); i++)
+ updateCell(i, col);
+}
+
+/** Override the QTable member function to avoid confusion with our own functionality */
+void kMyMoneySplitTable::endEdit(int /*row*/, int /*col*/, bool /*accept*/, bool /*replace*/ )
+{
+}
+
+bool kMyMoneySplitTable::eventFilter(QObject *o, QEvent *e)
+{
+ // MYMONEYTRACER(tracer);
+ QKeyEvent *k = static_cast<QKeyEvent *> (e);
+ bool rc = false;
+ int row = currentRow();
+ int lines = visibleHeight()/rowHeight(0);
+ QWidget* w;
+
+ if(e->type() == QEvent::KeyPress && !isEditMode()) {
+ rc = true;
+ switch(k->key()) {
+ case Qt::Key_Up:
+ if(row)
+ slotSetFocus(row-1);
+ break;
+
+ case Qt::Key_Down:
+ if(row < static_cast<int> (m_transaction.splits().count()-1))
+ slotSetFocus(row+1);
+ break;
+
+ case Qt::Key_Home:
+ slotSetFocus(0);
+ break;
+
+ case Qt::Key_End:
+ slotSetFocus(m_transaction.splits().count()-1);
+ break;
+
+ case Qt::Key_PageUp:
+ if(lines) {
+ while(lines-- > 0 && row)
+ row--;
+ slotSetFocus(row);
+ }
+ break;
+
+ case Qt::Key_PageDown:
+ if(row < static_cast<int> (m_transaction.splits().count()-1)) {
+ while(lines-- > 0 && row < static_cast<int> (m_transaction.splits().count()-1))
+ row++;
+ slotSetFocus(row);
+ }
+ break;
+
+ case Qt::Key_Delete:
+ slotDeleteSplit();
+ break;
+
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if(row < static_cast<int> (m_transaction.splits().count()-1)
+ && KMyMoneyGlobalSettings::enterMovesBetweenFields()) {
+ slotStartEdit();
+ } else
+ emit returnPressed();
+ break;
+
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+
+ case Qt::Key_F2:
+ slotStartEdit();
+ break;
+
+ default:
+ rc = true;
+ KShortcut copySplit(i18n("Duplicate split", "CTRL+c"));
+ KShortcut newSplit(QKeySequence(Qt::CTRL | Qt::Key_Insert));
+ if(copySplit.contains(KKey(k))) {
+ slotDuplicateSplit();
+
+ } else if(newSplit.contains(KKey(k))) {
+ slotSetFocus(m_transaction.splits().count()-1);
+ slotStartEdit();
+
+ } else if ( k->text()[ 0 ].isPrint() ) {
+ w = slotStartEdit();
+ // make sure, the widget receives the key again
+ QApplication::sendEvent(w, e);
+ }
+ break;
+ }
+
+ } else if(e->type() == QEvent::KeyPress && isEditMode()) {
+ bool terminate = true;
+ rc = true;
+ switch(k->key()) {
+ // suppress the F2 functionality to start editing in inline edit mode
+ case Qt::Key_F2:
+ // suppress the cursor movement in inline edit mode
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ break;
+
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ // we cannot call the slot directly, as it destroys the caller of
+ // this method :-( So we let the event handler take care of calling
+ // the respective slot using a timeout. For a KLineEdit derived object
+ // it could be, that at this point the user selected a value from
+ // a completion list. In this case, we close the completion list and
+ // do not end editing of the transaction.
+ if(o->inherits("KLineEdit")) {
+ KLineEdit* le = dynamic_cast<KLineEdit*> (o);
+ KCompletionBox* box = le->completionBox(false);
+ if(box && box->isVisible()) {
+ terminate = false;
+ le->completionBox(false)->hide();
+ }
+ }
+
+ // in case we have the 'enter moves focus between fields', we need to simulate
+ // a TAB key when the object 'o' points to the category or memo field.
+ if(KMyMoneyGlobalSettings::enterMovesBetweenFields()) {
+ if(o == m_editCategory->lineEdit() || o == m_editMemo) {
+ terminate = false;
+ QKeyEvent evt(e->type(),
+ Key_Tab, 0, k->state(), QString::null,
+ k->isAutoRepeat(), k->count());
+
+ QApplication::sendEvent( o, &evt );
+ }
+ }
+
+ if(terminate) {
+ QTimer::singleShot(0, this, SLOT(slotEndEditKeyboard()));
+ }
+ break;
+
+ case Qt::Key_Escape:
+ // we cannot call the slot directly, as it destroys the caller of
+ // this method :-( So we let the event handler take care of calling
+ // the respective slot using a timeout.
+ QTimer::singleShot(0, this, SLOT(slotCancelEdit()));
+ break;
+
+ default:
+ rc = false;
+ break;
+ }
+ } else if(e->type() == QEvent::KeyRelease && !isEditMode()) {
+ // for some reason, we only see a KeyRelease event of the Menu key
+ // here. In other locations (e.g. Register::eventFilter()) we see
+ // a KeyPress event. Strange. (ipwizard - 2008-05-10)
+ switch(k->key()) {
+ case Qt::Key_Menu:
+ // if the very last entry is selected, the delete
+ // operation is not available otherwise it is
+ m_contextMenu->setItemEnabled(m_contextMenuDelete,
+ row < static_cast<int> (m_transaction.splits().count()-1));
+ m_contextMenu->setItemEnabled(m_contextMenuDuplicate,
+ row < static_cast<int> (m_transaction.splits().count()-1));
+
+ m_contextMenu->exec(QCursor::pos());
+ rc = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // if the event has not been processed here, forward it to
+ // the base class implementation if it's not a key event
+ if(rc == false) {
+ if(e->type() != QEvent::KeyPress
+ && e->type() != QEvent::KeyRelease) {
+ rc = QTable::eventFilter(o, e);
+ }
+ }
+
+ return rc;
+}
+
+void kMyMoneySplitTable::slotSetFocus(int realrow, int /* col */, int button, const QPoint& /* point */)
+{
+ MYMONEYTRACER(tracer);
+ int row = realrow;
+
+ // adjust row to used area
+ if(row > static_cast<int> (m_transaction.splits().count()-1))
+ row = m_transaction.splits().count()-1;
+ if(row < 0)
+ row = 0;
+
+ // make sure the row will be on the screen
+ ensureCellVisible(row, 0);
+
+ if(button == Qt::LeftButton) { // left mouse button
+ if(isEditMode()) { // in edit mode?
+ if(KMyMoneyGlobalSettings::focusChangeIsEnter())
+ slotEndEdit();
+ else
+ slotCancelEdit();
+ }
+ if(row != static_cast<int> (currentRow())) {
+ // setup new current row and update visible selection
+ setCurrentCell(row, 0);
+ slotUpdateData(m_transaction);
+ }
+ } else if(button == Qt::RightButton) {
+ // context menu is only available when cursor is on
+ // an existing transaction or the first line after this area
+ if(row == realrow) {
+ // setup new current row and update visible selection
+ setCurrentCell(row, 0);
+ slotUpdateData(m_transaction);
+
+ // if the very last entry is selected, the delete
+ // operation is not available otherwise it is
+ m_contextMenu->setItemEnabled(m_contextMenuDelete,
+ row < static_cast<int> (m_transaction.splits().count()-1));
+ m_contextMenu->setItemEnabled(m_contextMenuDuplicate,
+ row < static_cast<int> (m_transaction.splits().count()-1));
+
+ m_contextMenu->exec(QCursor::pos());
+ }
+ }
+}
+
+void kMyMoneySplitTable::contentsMousePressEvent( QMouseEvent* e )
+{
+ slotSetFocus( rowAt(e->pos().y()), columnAt(e->pos().x()), e->button(), e->pos() );
+}
+
+/* turn off QTable behaviour */
+void kMyMoneySplitTable::contentsMouseReleaseEvent( QMouseEvent* /* e */ )
+{
+}
+
+void kMyMoneySplitTable::contentsMouseDoubleClickEvent( QMouseEvent *e )
+{
+ MYMONEYTRACER(tracer);
+
+ int col = columnAt(e->pos().x());
+ slotSetFocus( rowAt(e->pos().y()), col, e->button(), e->pos() );
+ slotStartEdit();
+
+ KLineEdit* editWidget = 0;
+ switch(col) {
+ case 1:
+ editWidget = m_editMemo;
+ break;
+
+ case 2:
+ editWidget = dynamic_cast<KLineEdit*> (m_editAmount->focusWidget());
+ break;
+
+ default:
+ break;
+ }
+ if(editWidget) {
+ editWidget->setFocus();
+ editWidget->selectAll();
+ // we need to call setFocus on the edit widget from the
+ // main loop again to get the keyboard focus to the widget also
+ QTimer::singleShot(0, editWidget, SLOT(setFocus()));
+ }
+}
+
+void kMyMoneySplitTable::setCurrentCell(int row, int /* col */)
+{
+ MYMONEYTRACER(tracer);
+
+ if(row > m_maxRows)
+ row = m_maxRows;
+ m_currentRow = row;
+ QTable::setCurrentCell(row, 0);
+ QValueList<MyMoneySplit> list = getSplits(m_transaction);
+ if(row < static_cast<int>(list.count()))
+ m_split = list[row];
+ else
+ m_split = MyMoneySplit();
+}
+
+void kMyMoneySplitTable::setNumRows(int irows)
+{
+ QTable::setNumRows(irows);
+
+ // determine row height according to the edit widgets
+ // we use the category widget as the base
+ QFontMetrics fm( KMyMoneyGlobalSettings::listCellFont() );
+ int height = fm.lineSpacing()+6;
+#if 0
+ // recalculate row height hint
+ KMyMoneyCategory cat;
+ height = QMAX(cat.sizeHint().height(), height);
+#endif
+
+ verticalHeader()->setUpdatesEnabled(false);
+
+ for(int i = 0; i < irows; ++i)
+ verticalHeader()->resizeSection(i, height);
+
+ verticalHeader()->setUpdatesEnabled(true);
+
+ // add or remove scrollbars as required
+ updateScrollBars();
+}
+
+void kMyMoneySplitTable::setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s, const MyMoneyAccount& acc)
+{
+ MYMONEYTRACER(tracer);
+ m_transaction = t;
+ m_account = acc;
+ m_hiddenSplit = s;
+ setCurrentCell(0, 0);
+ slotUpdateData(m_transaction);
+}
+
+const QValueList<MyMoneySplit> kMyMoneySplitTable::getSplits(const MyMoneyTransaction& t) const
+{
+ QValueList<MyMoneySplit> list;
+ QValueList<MyMoneySplit>::Iterator it;
+
+ // get list of splits
+ list = t.splits();
+
+ // and ignore the one that should be hidden
+
+ for(it = list.begin(); it != list.end(); ++it) {
+ if((*it).id() == m_hiddenSplit.id()) {
+ list.remove(it);
+ break;
+ }
+ }
+ return list;
+}
+
+void kMyMoneySplitTable::slotUpdateData(const MyMoneyTransaction& t)
+{
+ MYMONEYTRACER(tracer);
+ unsigned long rowCount=0;
+
+ QValueList<MyMoneySplit> list = getSplits(t);
+ updateTransactionTableSize();
+
+ // fill the part that is used by transactions
+ QValueList<MyMoneySplit>::Iterator it;
+ kMyMoneyEdit* valfield = new kMyMoneyEdit();
+ for(it = list.begin(); it != list.end(); ++it) {
+ QString colText;
+ MyMoneyMoney value = (*it).value();
+ if(!(*it).accountId().isEmpty()) {
+ try {
+ colText = MyMoneyFile::instance()->accountToCategory((*it).accountId());
+ } catch(MyMoneyException *e) {
+ qDebug("Unexpected exception in kMyMoneySplitTable::slotUpdateData()");
+ delete e;
+ }
+ }
+ QString amountTxt = value.formatMoney(m_account.fraction());
+ if(value == MyMoneyMoney::autoCalc) {
+ amountTxt = i18n("will be calculated");
+ }
+
+ if(colText.isEmpty() && (*it).memo().isEmpty() && value.isZero())
+ amountTxt = QString();
+
+ unsigned width = fontMetrics().width(amountTxt);
+ valfield->setMinimumWidth(width);
+ width = valfield->minimumSizeHint().width();
+
+ if(width > m_amountWidth)
+ m_amountWidth = width;
+
+ setText(rowCount, 0, colText);
+ setText(rowCount, 1, (*it).memo());
+ setText(rowCount, 2, amountTxt);
+
+ rowCount++;
+ }
+ delete valfield;
+
+ // now clean out the remainder of the table
+ while(rowCount < static_cast<unsigned long> (numRows())) {
+ setText(rowCount, 0, "");
+ setText(rowCount, 1, "");
+ setText(rowCount, 2, "");
+ ++rowCount;
+ }
+}
+
+void kMyMoneySplitTable::updateTransactionTableSize(void)
+{
+ // get current size of transactions table
+ int rowHeight = cellGeometry(0, 0).height();
+
+ // add half a row to the height to avoid unnecessary toggling when
+ // changing the number of rows
+ int tableHeight = (height() + rowHeight/2);
+ int splitCount = m_transaction.splits().count()-1;
+
+ if(splitCount < 0)
+ splitCount = 0;
+
+ // see if we need some extra lines to fill the current size with the grid
+ int numExtraLines = (tableHeight / rowHeight) - splitCount;
+ if(numExtraLines < 2)
+ numExtraLines = 2;
+
+ setNumRows(splitCount + numExtraLines);
+ // setMaxRows(splitCount);
+ m_maxRows = splitCount;
+}
+
+void kMyMoneySplitTable::resizeEvent(QResizeEvent* /* ev */)
+{
+ int w = visibleWidth() - m_amountWidth;
+
+ // resize the columns
+ setColumnWidth(0, w/2);
+ setColumnWidth(1, w/2);
+ setColumnWidth(2, m_amountWidth);
+
+ updateTransactionTableSize();
+}
+
+void kMyMoneySplitTable::slotDuplicateSplit(void)
+{
+ MYMONEYTRACER(tracer);
+ QValueList<MyMoneySplit> list = getSplits(m_transaction);
+ if(m_currentRow < static_cast<int> (list.count())) {
+ MyMoneySplit split = list[m_currentRow];
+ split.clearId();
+ try {
+ m_transaction.addSplit(split);
+ emit transactionChanged(m_transaction);
+ } catch(MyMoneyException *e) {
+ qDebug("Cannot duplicate split: %s", e->what().latin1());
+ delete e;
+ }
+ }
+}
+
+void kMyMoneySplitTable::slotDeleteSplit(void)
+{
+ MYMONEYTRACER(tracer);
+ QValueList<MyMoneySplit> list = getSplits(m_transaction);
+ if(m_currentRow < static_cast<int> (list.count())) {
+ if(KMessageBox::warningContinueCancel (this,
+ i18n("You are about to delete the selected split. "
+ "Do you really want to continue?"),
+ i18n("KMyMoney"),
+ i18n("Continue")
+ ) == KMessageBox::Continue) {
+ try {
+ m_transaction.removeSplit(list[m_currentRow]);
+ // if we removed the last split, select the previous
+ if(m_currentRow && m_currentRow == static_cast<int>(list.count())-1)
+ setCurrentCell(m_currentRow-1, 0);
+ else
+ setCurrentCell(m_currentRow, 0);
+ emit transactionChanged(m_transaction);
+ } catch(MyMoneyException *e) {
+ qDebug("Cannot remove split: %s", e->what().latin1());
+ delete e;
+ }
+ }
+ }
+}
+
+QWidget* kMyMoneySplitTable::slotStartEdit(void)
+{
+ MYMONEYTRACER(tracer);
+ return createEditWidgets();
+}
+
+void kMyMoneySplitTable::slotEndEdit(void)
+{
+ endEdit(false);
+}
+
+void kMyMoneySplitTable::slotEndEditKeyboard(void)
+{
+ endEdit(true);
+}
+
+void kMyMoneySplitTable::endEdit(bool keyBoardDriven)
+{
+ // Don't proceed, if we're not in edit mode
+ if(!m_editCategory)
+ return;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MYMONEYTRACER(tracer);
+ MyMoneySplit s1 = m_split;
+
+ if (m_editCategory->selectedItem().isEmpty()) {
+ KMessageBox::information(this, i18n("You need to assign a category to this split before it can be entered."), i18n("Enter split"), "EnterSplitWithEmptyCategory");
+ m_editCategory->setFocus();
+ return;
+ }
+
+ bool needUpdate = false;
+ if(m_editCategory->selectedItem() != m_split.accountId()) {
+ s1.setAccountId(m_editCategory->selectedItem());
+ needUpdate = true;
+ }
+ if(m_editMemo->text() != m_split.memo()) {
+ s1.setMemo(m_editMemo->text());
+ needUpdate = true;
+ }
+ if(m_editAmount->value() != m_split.value()) {
+ s1.setValue(m_editAmount->value());
+ needUpdate = true;
+ }
+
+ if(needUpdate) {
+ if(!s1.value().isZero()) {
+ MyMoneyAccount cat = file->account(s1.accountId());
+ if(cat.currencyId() != m_transaction.commodity()) {
+
+ MyMoneySecurity fromCurrency, toCurrency;
+ MyMoneyMoney fromValue, toValue;
+ fromCurrency = file->security(m_transaction.commodity());
+ toCurrency = file->security(cat.currencyId());
+
+ // determine the fraction required for this category
+ int fract = toCurrency.smallestAccountFraction();
+ if(cat.accountType() == MyMoneyAccount::Cash)
+ fract = toCurrency.smallestCashFraction();
+
+ // display only positive values to the user
+ fromValue = s1.value().abs();
+
+ // if we had a price info in the beginning, we use it here
+ if(m_priceInfo.find(cat.currencyId()) != m_priceInfo.end()) {
+ toValue = (fromValue * m_priceInfo[cat.currencyId()]).convert(fract);
+ }
+
+ // if the shares are still 0, we need to change that
+ if(toValue.isZero()) {
+ MyMoneyPrice price = MyMoneyFile::instance()->price(fromCurrency.id(), toCurrency.id());
+ // if the price is valid calculate the shares. If it is invalid
+ // assume a conversion rate of 1.0
+ if(price.isValid()) {
+ toValue = (price.rate(toCurrency.id()) * fromValue).convert(fract);
+ } else {
+ toValue = fromValue;
+ }
+ }
+
+ // now present all that to the user
+ KCurrencyCalculator calc(fromCurrency,
+ toCurrency,
+ fromValue,
+ toValue,
+ m_transaction.postDate(),
+ fract,
+ this, "currencyCalculator");
+
+ if(calc.exec() == QDialog::Rejected) {
+ return;
+ } else {
+ s1.setShares((s1.value() * calc.price()).convert(fract));
+ }
+
+ } else {
+ s1.setShares(s1.value());
+ }
+ } else
+ s1.setShares(s1.value());
+
+ m_split = s1;
+ try {
+ if(m_split.id().isEmpty()) {
+ m_transaction.addSplit(m_split);
+ } else {
+ m_transaction.modifySplit(m_split);
+ }
+ emit transactionChanged(m_transaction);
+ } catch(MyMoneyException *e) {
+ qDebug("Cannot add/modify split: %s", e->what().latin1());
+ delete e;
+ }
+ }
+ this->setFocus();
+ destroyEditWidgets();
+ slotSetFocus(currentRow()+1);
+
+ // if we still have more splits, we start editing right away
+ // in case we have selected 'enter moves betweeen fields'
+ if(keyBoardDriven
+ && currentRow() < static_cast<int> (m_transaction.splits().count()-1)
+ && KMyMoneyGlobalSettings::enterMovesBetweenFields()) {
+ slotStartEdit();
+ }
+
+}
+
+void kMyMoneySplitTable::slotCancelEdit(void)
+{
+ MYMONEYTRACER(tracer);
+ if(isEditMode()) {
+ destroyEditWidgets();
+ this->setFocus();
+ }
+}
+
+bool kMyMoneySplitTable::isEditMode(void) const
+{
+ return m_editMode;
+}
+
+void kMyMoneySplitTable::destroyEditWidgets(void)
+{
+ MYMONEYTRACER(tracer);
+
+ disconnect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadEditWidgets()));
+
+ clearCellWidget(m_currentRow, 0);
+ clearCellWidget(m_currentRow, 1);
+ clearCellWidget(m_currentRow, 2);
+ clearCellWidget(m_currentRow+1, 0);
+ m_editMode = false;
+
+ QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 100);
+}
+
+QWidget* kMyMoneySplitTable::createEditWidgets(void)
+{
+ MYMONEYTRACER(tracer);
+
+ QFont cellFont = KMyMoneyGlobalSettings::listCellFont();
+ m_tabOrderWidgets.clear();
+
+ // create the widgets
+ m_editAmount = new kMyMoneyEdit(0);
+ m_editAmount->setFont(cellFont);
+ m_editAmount->setResetButtonVisible(false);
+
+ m_editCategory = new KMyMoneyCategory();
+ m_editCategory->setHint(i18n("Category"));
+ m_editCategory->setFont(cellFont);
+ connect(m_editCategory, SIGNAL(createItem(const QString&, QString&)), this, SIGNAL(createCategory(const QString&, QString&)));
+ connect(m_editCategory, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+
+ m_editMemo = new kMyMoneyLineEdit(0, 0, false, AlignLeft|AlignVCenter);
+ m_editMemo->setHint(i18n("Memo"));
+ m_editMemo->setFont(cellFont);
+
+ // create buttons for the mouse users
+ KIconLoader *il = KGlobal::iconLoader();
+ m_registerButtonFrame = new QFrame(this, "buttonFrame");
+ QPalette palette = m_registerButtonFrame->palette();
+ palette.setColor(QColorGroup::Background, rowBackgroundColor(m_currentRow+1) );
+ m_registerButtonFrame->setPalette(palette);
+
+ QHBoxLayout* l = new QHBoxLayout(m_registerButtonFrame);
+ m_registerEnterButton = new KPushButton(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall), QString(), m_registerButtonFrame, "EnterButton");
+
+ m_registerCancelButton = new KPushButton(il->loadIcon("button_cancel", KIcon::Small, KIcon::SizeSmall), QString(), m_registerButtonFrame, "CancelButton");
+
+ l->addWidget(m_registerEnterButton);
+ l->addWidget(m_registerCancelButton);
+ l->addStretch(2);
+
+ connect(m_registerEnterButton, SIGNAL(clicked()), this, SLOT(slotEndEdit()));
+ connect(m_registerCancelButton, SIGNAL(clicked()), this, SLOT(slotCancelEdit()));
+
+ // setup tab order
+ addToTabOrder(m_editCategory);
+ addToTabOrder(m_editMemo);
+ addToTabOrder(m_editAmount);
+ addToTabOrder(m_registerEnterButton);
+ addToTabOrder(m_registerCancelButton);
+
+ if(!m_split.accountId().isEmpty()) {
+ m_editCategory->setSelectedItem(m_split.accountId());
+ } else {
+ // check if the transaction is balanced or not. If not,
+ // assign the remainder to the amount.
+ MyMoneyMoney diff;
+ QValueList<MyMoneySplit> list = m_transaction.splits();
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if(!(*it_s).accountId().isEmpty())
+ diff += (*it_s).value();
+ }
+ m_split.setValue(-diff);
+ }
+
+ m_editMemo->loadText(m_split.memo());
+ // don't allow automatically calculated values to be modified
+ if(m_split.value() == MyMoneyMoney::autoCalc) {
+ m_editAmount->setEnabled(false);
+ m_editAmount->loadText("will be calculated");
+ } else
+ m_editAmount->setValue(m_split.value());
+
+ setCellWidget(m_currentRow, 0, m_editCategory);
+ setCellWidget(m_currentRow, 1, m_editMemo);
+ setCellWidget(m_currentRow, 2, m_editAmount);
+ setCellWidget(m_currentRow+1, 0, m_registerButtonFrame);
+
+ // load e.g. the category widget with the account list
+ slotLoadEditWidgets();
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadEditWidgets()));
+
+ // setup the keyboard filter for all widgets
+ for(QWidget* w = m_tabOrderWidgets.first(); w; w = m_tabOrderWidgets.next()) {
+ w->installEventFilter(this);
+ }
+
+ m_editCategory->setFocus();
+ m_editCategory->lineEdit()->selectAll();
+ m_editMode = true;
+
+ return m_editCategory->lineEdit();
+}
+
+void kMyMoneySplitTable::slotLoadEditWidgets(void)
+{
+ // reload category widget
+ QString categoryId = m_editCategory->selectedItem();
+
+ AccountSet aSet;
+ aSet.addAccountGroup(MyMoneyAccount::Asset);
+ aSet.addAccountGroup(MyMoneyAccount::Liability);
+ aSet.addAccountGroup(MyMoneyAccount::Income);
+ aSet.addAccountGroup(MyMoneyAccount::Expense);
+ if(KMyMoneyGlobalSettings::expertMode())
+ aSet.addAccountGroup(MyMoneyAccount::Equity);
+
+ // remove the accounts with invalid types at this point
+ aSet.removeAccountType(MyMoneyAccount::CertificateDep);
+ aSet.removeAccountType(MyMoneyAccount::Investment);
+ aSet.removeAccountType(MyMoneyAccount::Stock);
+ aSet.removeAccountType(MyMoneyAccount::MoneyMarket);
+
+ aSet.load(m_editCategory->selector());
+
+ // if an account is specified then remove it from the widget so that the user
+ // cannot create a transfer with from and to account being the same account
+ if(!m_account.id().isEmpty())
+ m_editCategory->selector()->removeItem(m_account.id());
+
+ if(!categoryId.isEmpty())
+ m_editCategory->setSelectedItem(categoryId);
+
+}
+
+void kMyMoneySplitTable::addToTabOrder(QWidget* w)
+{
+ if(w) {
+ while(w->focusProxy())
+ w = w->focusProxy();
+ m_tabOrderWidgets.append(w);
+ }
+}
+
+bool kMyMoneySplitTable::focusNextPrevChild(bool next)
+{
+ MYMONEYTRACER(tracer);
+ bool rc = false;
+
+ if(m_editCategory) {
+ QWidget *w = 0;
+ QWidget *currentWidget;
+
+ m_tabOrderWidgets.find(qApp->focusWidget());
+ currentWidget = m_tabOrderWidgets.current();
+ w = next ? m_tabOrderWidgets.next() : m_tabOrderWidgets.prev();
+
+ do {
+ if(!w) {
+ w = next ? m_tabOrderWidgets.first() : m_tabOrderWidgets.last();
+ }
+
+ if(w != currentWidget
+ && ((w->focusPolicy() & TabFocus) == TabFocus)
+ && w->isVisible() && w->isEnabled()) {
+ w->setFocus();
+ rc = true;
+ break;
+ }
+ w = next ? m_tabOrderWidgets.next() : m_tabOrderWidgets.prev();
+ } while(w != currentWidget);
+
+ } else
+ rc = QTable::focusNextPrevChild(next);
+
+ return rc;
+}
+
+
+
+#include "kmymoneysplittable.moc"
diff --git a/kmymoney2/dialogs/kmymoneysplittable.h b/kmymoney2/dialogs/kmymoneysplittable.h
new file mode 100644
index 0000000..023660f
--- /dev/null
+++ b/kmymoney2/dialogs/kmymoneysplittable.h
@@ -0,0 +1,264 @@
+/***************************************************************************
+ kmymoneysplittable.h - description
+ -------------------
+ begin : Thu Jan 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYSPLITTABLE_H
+#define KMYMONEYSPLITTABLE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qtable.h>
+#include <qwidgetlist.h>
+#include <qguardedptr.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KPopupMenu;
+class KPushButton;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneytransaction.h"
+#include "../mymoney/mymoneyaccount.h"
+
+class KMyMoneyCategory;
+class kMyMoneyLineEdit;
+class kMyMoneyEdit;
+
+/**
+ * @author Thomas Baumgart
+ */
+class kMyMoneySplitTable : public QTable
+{
+ Q_OBJECT
+public:
+ kMyMoneySplitTable(QWidget *parent=0, const char *name=0);
+ virtual ~kMyMoneySplitTable();
+
+ void paintCell(QPainter *p, int row, int col, const QRect& r, bool /*selected*/);
+ void paintFocus(QPainter *p, const QRect &cr);
+
+ /**
+ * This method is used to load the widget with the information about
+ * the transaction @p t. The split referencing the account @p acc is
+ * not shown in the widget.
+ *
+ * @param t reference to transaction to be shown/modified
+ * @param s reference to split that is to be hidden
+ * @param acc reference to account
+ */
+ void setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s, const MyMoneyAccount& acc);
+
+ /**
+ * This method is used to retrieve the transaction from the widget.
+ */
+ const MyMoneyTransaction& transaction(void) const { return m_transaction; }
+
+ /**
+ * Returns a list of MyMoneySplit objects. It contains all but the one
+ * referencing the account passed in setTransaction().
+ *
+ * @param t reference to transaction
+ * @return list of splits
+ */
+ const QValueList<MyMoneySplit> getSplits(const MyMoneyTransaction& t) const;
+
+ void setup(const QMap<QString, MyMoneyMoney>& priceInfo);
+
+protected:
+ void contentsMousePressEvent( QMouseEvent* e );
+ void contentsMouseReleaseEvent( QMouseEvent* e );
+ void contentsMouseDoubleClickEvent( QMouseEvent* e );
+ bool eventFilter(QObject *o, QEvent *e);
+ void endEdit(int row, int col, bool accept, bool replace );
+
+ void resizeEvent(QResizeEvent*);
+ QWidget* createEditWidgets(void);
+ void destroyEditWidgets(void);
+
+ /**
+ * This method handles the focus of the keyboard. When in edit mode
+ * (m_editCategory widget is visible) the keyboard focus is handled
+ * according to the widgets that are referenced in m_tabOrderWidgets.
+ * If not in edit mode, the base class functionality is provided.
+ *
+ * @param next true if forward-tab, false if backward-tab was
+ * pressed by the user
+ */
+ virtual bool focusNextPrevChild(bool next);
+ void addToTabOrder(QWidget* w);
+
+ /**
+ * convenience function for setCurrentCell(int row, int col)
+ */
+ void setCurrentCell(int row) { setCurrentCell(row, 0); }
+
+ void updateTransactionTableSize(void);
+
+ /**
+ * This method returns the current state of the inline editing mode
+ *
+ * @return true if inline edit mode is on, false otherwise
+ */
+ bool isEditMode(void) const;
+
+ /**
+ * This method retuns the background color for a given @p row.
+ *
+ * @param row the row in question
+ * @return the color as QColor object
+ */
+ const QColor rowBackgroundColor(const int row) const;
+
+ void endEdit(bool keyboardDriven);
+
+public slots:
+ /** No descriptions */
+ virtual void setCurrentCell(int row, int col);
+
+ virtual void setNumRows(int r);
+
+ QWidget* slotStartEdit(void);
+ void slotEndEdit(void);
+ void slotEndEditKeyboard(void);
+ void slotDeleteSplit(void);
+ void slotCancelEdit(void);
+ void slotDuplicateSplit(void);
+
+protected slots:
+ virtual void columnWidthChanged(int col);
+
+ /// move the focus to the selected @p row.
+ void slotSetFocus(int row, int col = 0, int button = Qt::LeftButton, const QPoint & mousePos = QPoint(0, 0));
+
+ /**
+ * Calling this slot refills the widget with the data
+ * passed in the argument @p t.
+ *
+ * @param t reference to transaction data
+ */
+ void slotUpdateData(const MyMoneyTransaction& t);
+
+ void slotLoadEditWidgets(void);
+
+signals:
+ /**
+ * This signal is emitted whenever the return key is pressed
+ * and the widget is not in edit mode.
+ */
+ void escapePressed(void);
+
+ /**
+ * This signal is emitted whenever the return key is pressed
+ * and the widget is not in edit mode.
+ */
+ void returnPressed(void);
+
+ /**
+ * This signal is emitted whenever the transaction data has been changed
+ *
+ * @param t modified transaction data
+ */
+ void transactionChanged(const MyMoneyTransaction& t);
+
+ /**
+ * This signal is sent out, when a new category needs to be created
+ * @sa KMyMoneyCombo::createItem()
+ *
+ * @param txt The name of the category to be created
+ * @param id A connected slot should store the id of the created object in this variable
+ */
+ void createCategory(const QString& txt, QString& id);
+
+ /**
+ * Signal is emitted, if any of the widgets enters (@a state equals @a true)
+ * or leaves (@a state equals @a false) object creation mode.
+ *
+ * @param state Enter (@a true) or leave (@a false) object creation
+ */
+ void objectCreation(bool state);
+
+private:
+ /// the currently selected row (will be printed as selected)
+ int m_currentRow;
+
+ /// the number of rows filled with data
+ int m_maxRows;
+
+ /// indication if inline editing mode is on or not
+ bool m_editMode;
+
+ MyMoneyTransaction m_transaction;
+ MyMoneyAccount m_account;
+ MyMoneySplit m_split;
+ MyMoneySplit m_hiddenSplit;
+
+ unsigned m_amountWidth;
+
+ /**
+ * This member keeps a pointer to the context menu
+ */
+ KPopupMenu* m_contextMenu;
+
+ /// keeps the id of the delete entry in the context menu
+ int m_contextMenuDelete;
+
+ /// keeps the id of the duplicate entry in the context menu
+ int m_contextMenuDuplicate;
+
+ /**
+ * This member contains a pointer to the input widget for the category.
+ * The widget will be created and destroyed dynamically in createInputWidgets()
+ * and destroyInputWidgets().
+ */
+ QGuardedPtr<KMyMoneyCategory> m_editCategory;
+
+ /**
+ * This member contains a pointer to the input widget for the memo.
+ * The widget will be created and destroyed dynamically in createInputWidgets()
+ * and destroyInputWidgets().
+ */
+ QGuardedPtr<kMyMoneyLineEdit> m_editMemo;
+
+ /**
+ * This member contains a pointer to the input widget for the amount.
+ * The widget will be created and destroyed dynamically in createInputWidgets()
+ * and destroyInputWidgets().
+ */
+ QGuardedPtr<kMyMoneyEdit> m_editAmount;
+
+ /**
+ * This member keeps the tab order for the above widgets
+ */
+ QWidgetList m_tabOrderWidgets;
+
+ QGuardedPtr<QFrame> m_registerButtonFrame;
+ QGuardedPtr<KPushButton> m_registerEnterButton;
+ QGuardedPtr<KPushButton> m_registerCancelButton;
+
+ QMap<QString, MyMoneyMoney> m_priceInfo;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/knewaccountdlg.cpp b/kmymoney2/dialogs/knewaccountdlg.cpp
new file mode 100644
index 0000000..f941f2e
--- /dev/null
+++ b/kmymoney2/dialogs/knewaccountdlg.cpp
@@ -0,0 +1,1209 @@
+/***************************************************************************
+ knewaccountdlg.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ 2004 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qheader.h>
+#include <qtooltip.h>
+#include <qcheckbox.h>
+#include <qtimer.h>
+#include <qtabwidget.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qtabwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kmessagebox.h>
+#include <kcombobox.h>
+#include <klistview.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+#include <kled.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "knewaccountdlg.h"
+
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/mymoneyexception.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/kguiutils.h>
+#include <kmymoney/kmymoneycombo.h>
+
+#include "../widgets/kmymoneycurrencyselector.h"
+#include "../widgets/kmymoneyaccountselector.h"
+
+#include "../mymoney/mymoneyexception.h"
+#include "../mymoney/mymoneykeyvaluecontainer.h"
+#include "../dialogs/knewbankdlg.h"
+#include "../views/kmymoneyfile.h"
+#include "../kmymoneyutils.h"
+
+#include "../reports/kreportchartview.h"
+#include "../reports/pivottable.h"
+
+// in KOffice version < 1.5 KDCHART_PROPSET_NORMAL_DATA was a static const
+// but in 1.5 this has been changed into a #define'd value. So we have to
+// make sure, we use the right one.
+#ifndef KDCHART_PROPSET_NORMAL_DATA
+#define KMM_KDCHART_PROPSET_NORMAL_DATA KDChartParams::KDCHART_PROPSET_NORMAL_DATA
+#else
+#define KMM_KDCHART_PROPSET_NORMAL_DATA KDCHART_PROPSET_NORMAL_DATA
+#endif
+
+KNewAccountDlg::KNewAccountDlg(const MyMoneyAccount& account, bool isEditing, bool categoryEditor, QWidget *parent, const char *name, const QString& title)
+ : KNewAccountDlgDecl(parent,name,true),
+ m_account(account),
+ m_bSelectedParentAccount(false),
+ m_categoryEditor(categoryEditor),
+ m_isEditing(isEditing)
+{
+ QString columnName = ( (categoryEditor) ? i18n("Categories") : i18n("Accounts") );
+
+ m_qlistviewParentAccounts->setRootIsDecorated(true);
+ m_qlistviewParentAccounts->setAllColumnsShowFocus(true);
+ m_qlistviewParentAccounts->setSectionHeader(columnName);
+ m_qlistviewParentAccounts->setMultiSelection(false);
+ m_qlistviewParentAccounts->header()->setResizeEnabled(true);
+ m_qlistviewParentAccounts->setColumnWidthMode(0, QListView::Maximum);
+ m_qlistviewParentAccounts->setEnabled(false);
+ // never show the horizontal scroll bar
+ m_qlistviewParentAccounts->setHScrollBarMode(QScrollView::AlwaysOff);
+
+ m_subAccountLabel->setText(i18n("Is a sub account"));
+
+ m_qlistviewParentAccounts->header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
+
+ accountNameEdit->setText(account.name());
+ descriptionEdit->setText(account.description());
+
+ typeCombo->setEnabled(true);
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ // load the price mode combo
+ m_priceMode->insertItem(i18n("default price mode", "<default>"), 0);
+ m_priceMode->insertItem(i18n("Price per share"), 1);
+ m_priceMode->insertItem(i18n("Total for all shares"), 2);
+
+ int priceMode = 0;
+ if(m_account.accountType() == MyMoneyAccount::Investment) {
+ m_priceMode->setEnabled(true);
+ if(!m_account.value("priceMode").isEmpty())
+ priceMode = m_account.value("priceMode").toInt();
+ }
+ m_priceMode->setCurrentItem(priceMode);
+
+ bool haveMinBalance = false;
+ bool haveMaxCredit = false;
+ if (categoryEditor)
+ {
+ // get rid of the tabs that are not used for categories
+ QWidget* tab = m_tab->page(m_tab->indexOf(m_institutionTab));
+ if(tab)
+ m_tab->removePage(tab);
+ tab = m_tab->page(m_tab->indexOf(m_limitsTab));
+ if(tab)
+ m_tab->removePage(tab);
+
+ //m_qlistviewParentAccounts->setEnabled(true);
+ startDateEdit->setEnabled(false);
+ accountNoEdit->setEnabled(false);
+
+ m_institutionBox->hide();
+ m_qcheckboxNoVat->hide();
+
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Income));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Expense));
+
+ // Hardcoded but acceptable
+ switch (account.accountType())
+ {
+ case MyMoneyAccount::Income:
+ typeCombo->setCurrentItem(0);
+ break;
+
+ case MyMoneyAccount::Expense:
+ default:
+ typeCombo->setCurrentItem(1);
+ break;
+ }
+ m_currency->setEnabled(true);
+ if (m_isEditing)
+ {
+ typeCombo->setEnabled(false);
+ m_currency->setDisabled(MyMoneyFile::instance()->isReferenced(m_account));
+ }
+ m_qcheckboxPreferred->hide();
+
+ m_qcheckboxTax->setChecked(account.value("Tax") == "Yes");
+ loadVatAccounts();
+ }
+ else
+ {
+ // get rid of the tabs that are not used for accounts
+ QWidget* taxtab = m_tab->page(m_tab->indexOf(m_taxTab));
+ if (taxtab) {
+ if(m_account.isAssetLiability()) {
+ m_vatCategory->setText(i18n( "VAT account"));
+ m_vatAssignmentFrame->hide();
+ m_qcheckboxTax->setChecked(account.value("Tax") == "Yes");
+ } else {
+ m_tab->removePage(taxtab);
+ }
+ }
+
+ switch(m_account.accountType()) {
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ haveMinBalance = true;
+ break;
+
+ case MyMoneyAccount::Checkings:
+ haveMinBalance = true;
+ haveMaxCredit = true;
+ break;
+
+ case MyMoneyAccount::CreditCard:
+ haveMaxCredit = true;
+ break;
+
+ default:
+ // no limit available, so we might get rid of the tab
+ QWidget* tab = m_tab->page(m_tab->indexOf(m_limitsTab));
+ if(tab)
+ m_tab->removePage(tab);
+ // don't try to hide the widgets we just wiped
+ // in the next step
+ haveMaxCredit = haveMinBalance = true;
+ break;
+ }
+
+ if(!haveMaxCredit) {
+ m_maxCreditLabel->setEnabled(false);
+ m_maxCreditLabel->hide();
+ m_maxCreditEarlyEdit->hide();
+ m_maxCreditAbsoluteEdit->hide();
+ }
+ if(!haveMinBalance) {
+ m_minBalanceLabel->setEnabled(false);
+ m_minBalanceLabel->hide();
+ m_minBalanceEarlyEdit->hide();
+ m_minBalanceAbsoluteEdit->hide();
+ }
+
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Checkings));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Savings));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Cash));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::CreditCard));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Loan));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Investment));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Asset));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Liability));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Stock));
+/*
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::CertificateDep));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::MoneyMarket));
+ typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Currency));
+*/
+
+ // Hardcoded but acceptable
+ switch (account.accountType())
+ {
+ default:
+ case MyMoneyAccount::Checkings:
+ typeCombo->setCurrentItem(0);
+ break;
+ case MyMoneyAccount::Savings:
+ typeCombo->setCurrentItem(1);
+ break;
+ case MyMoneyAccount::Cash:
+ typeCombo->setCurrentItem(2);
+ break;
+ case MyMoneyAccount::CreditCard:
+ typeCombo->setCurrentItem(3);
+ break;
+ case MyMoneyAccount::Loan:
+ typeCombo->setCurrentItem(4);
+ break;
+ case MyMoneyAccount::Investment:
+ typeCombo->setCurrentItem(5);
+ break;
+ case MyMoneyAccount::Asset:
+ typeCombo->setCurrentItem(6);
+ break;
+ case MyMoneyAccount::Liability:
+ typeCombo->setCurrentItem(7);
+ break;
+ case MyMoneyAccount::Stock:
+ m_institutionBox->hide();
+ typeCombo->setCurrentItem(8);
+ break;
+/*
+ case MyMoneyAccount::CertificateDep:
+ typeCombo->setCurrentItem(5);
+ break;
+ case MyMoneyAccount::MoneyMarket:
+ typeCombo->setCurrentItem(7);
+ break;
+ case MyMoneyAccount::Currency:
+ typeCombo->setCurrentItem(8);
+ break;
+*/
+ }
+
+ if(!m_account.openingDate().isValid())
+ m_account.setOpeningDate(QDate::currentDate());
+
+ startDateEdit->setDate(m_account.openingDate());
+ accountNoEdit->setText(account.number());
+ m_qcheckboxPreferred->setChecked(account.value("PreferredAccount") == "Yes");
+ m_qcheckboxNoVat->setChecked(account.value("NoVat") == "Yes");
+ loadKVP("iban", ibanEdit);
+ loadKVP("minBalanceAbsolute", m_minBalanceAbsoluteEdit);
+ loadKVP("minBalanceEarly", m_minBalanceEarlyEdit);
+ loadKVP("maxCreditAbsolute", m_maxCreditAbsoluteEdit);
+ loadKVP("maxCreditEarly", m_maxCreditEarlyEdit);
+ // reverse the sign for display purposes
+ if(!m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty())
+ m_maxCreditAbsoluteEdit->setValue(m_maxCreditAbsoluteEdit->value()*MyMoneyMoney(-1,1));
+ if(!m_maxCreditEarlyEdit->lineedit()->text().isEmpty())
+ m_maxCreditEarlyEdit->setValue(m_maxCreditEarlyEdit->value()*MyMoneyMoney(-1,1));
+ loadKVP("lastNumberUsed", m_lastCheckNumberUsed);
+
+
+ // we do not allow to change the account type once an account
+ // was created. Same applies to currency if it is referenced.
+ if (m_isEditing)
+ {
+ typeCombo->setEnabled(false);
+ m_currency->setDisabled(MyMoneyFile::instance()->isReferenced(m_account));
+ }
+ if(m_account.isInvest()) {
+ typeCombo->setEnabled(false);
+ m_qcheckboxPreferred->hide();
+ m_currencyText->hide();
+ m_currency->hide();
+ } else {
+ // use the old field and override a possible new value
+ if(!MyMoneyMoney(account.value("minimumBalance")).isZero()) {
+ m_minBalanceAbsoluteEdit->setValue(MyMoneyMoney(account.value("minimumBalance")));
+ }
+ }
+
+// m_qcheckboxTax->hide(); TODO should only be visible for VAT category/account
+ }
+
+ m_currency->setSecurity(file->currency(account.currencyId()));
+
+ // Load the institutions
+ // then the accounts
+ QString institutionName;
+
+ try
+ {
+ if (m_isEditing && !account.institutionId().isEmpty())
+ institutionName = file->institution(account.institutionId()).name();
+ else
+ institutionName = QString();
+ }
+ catch (MyMoneyException *e)
+ {
+ qDebug("exception in init for account dialog: %s", e->what().latin1());
+ delete e;
+ }
+
+ initParentWidget(account.parentAccountId(), account.id());
+ if(m_account.isInvest())
+ m_qlistviewParentAccounts->setEnabled(false);
+
+ if (!categoryEditor)
+ slotLoadInstitutions(institutionName);
+
+ accountNameEdit->setFocus();
+
+ if (title)
+ setCaption(title);
+
+ // load button icons
+ KIconLoader* il = KGlobal::iconLoader();
+ cancelButton->setGuiItem(KStdGuiItem::cancel());
+ createButton->setGuiItem(KStdGuiItem::ok());
+
+ connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
+ connect(createButton, SIGNAL(clicked()), this, SLOT(okClicked()));
+ connect(m_qlistviewParentAccounts, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotSelectionChanged(QListViewItem*)));
+ connect(m_qbuttonNew, SIGNAL(clicked()), this, SLOT(slotNewClicked()));
+ connect(typeCombo, SIGNAL(activated(const QString&)),
+ this, SLOT(slotAccountTypeChanged(const QString&)));
+
+ connect(accountNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckFinished()));
+
+ connect(m_vatCategory, SIGNAL(toggled(bool)), this, SLOT(slotVatChanged(bool)));
+ connect(m_vatAssignment, SIGNAL(toggled(bool)), this, SLOT(slotVatAssignmentChanged(bool)));
+ connect(m_vatCategory, SIGNAL(toggled(bool)), this, SLOT(slotCheckFinished()));
+ connect(m_vatAssignment, SIGNAL(toggled(bool)), this, SLOT(slotCheckFinished()));
+ connect(m_vatRate, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckFinished()));
+ connect(m_vatAccount, SIGNAL(stateChanged()), this, SLOT(slotCheckFinished()));
+
+ connect(m_minBalanceEarlyEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMinBalanceAbsoluteEdit(const QString&)));
+ connect(m_minBalanceAbsoluteEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMinBalanceEarlyEdit(const QString&)));
+ connect(m_maxCreditEarlyEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMaxCreditAbsoluteEdit(const QString&)));
+ connect(m_maxCreditAbsoluteEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMaxCreditEarlyEdit(const QString&)));
+
+ connect(m_qcomboboxInstitutions, SIGNAL(activated(const QString&)), this, SLOT(slotLoadInstitutions(const QString&)));
+
+ m_vatCategory->setChecked(false);
+ m_vatAssignment->setChecked(false);
+
+ // make sure our account does not have an id and no parent assigned
+ // and certainly no children in case we create a new account
+ if(!m_isEditing) {
+ m_account.clearId();
+ m_account.setParentAccountId(QString());
+ QStringList::ConstIterator it;
+ while((it = m_account.accountList().begin()) != m_account.accountList().end())
+ m_account.removeAccountId(*it);
+
+ if(m_parentItem == 0) {
+ // force loading of initial parent
+ m_account.setAccountType(MyMoneyAccount::UnknownAccountType);
+ MyMoneyAccount::_accountTypeE type = account.accountType();
+ if(type == MyMoneyAccount::UnknownAccountType)
+ type = MyMoneyAccount::Checkings;
+ slotAccountTypeChanged(KMyMoneyUtils::accountTypeToString(type));
+ }
+ } else {
+ if(!m_account.value("VatRate").isEmpty()) {
+ m_vatCategory->setChecked(true);
+ m_vatRate->setValue(MyMoneyMoney(m_account.value("VatRate"))*MyMoneyMoney(100,1));
+ } else {
+ if(!m_account.value("VatAccount").isEmpty()) {
+ QString accId = m_account.value("VatAccount").latin1();
+ try {
+ // make sure account exists
+ MyMoneyFile::instance()->account(accId);
+ m_vatAssignment->setChecked(true);
+ m_vatAccount->setSelected(accId);
+ m_grossAmount->setChecked(true);
+ if(m_account.value("VatAmount") == "Net")
+ m_netAmount->setChecked(true);
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+ }
+ }
+ slotVatChanged(m_vatCategory->isChecked());
+ slotVatAssignmentChanged(m_vatAssignment->isChecked());
+ slotCheckFinished();
+
+ kMandatoryFieldGroup* requiredFields = new kMandatoryFieldGroup (this);
+ requiredFields->setOkButton(createButton); // button to be enabled when all fields present
+ requiredFields->add(accountNameEdit);
+
+ // using a timeout is the only way, I got the 'ensureItemVisible'
+ // working when creating the dialog. I assume, this
+ // has something to do with the delayed update of the display somehow.
+ QTimer::singleShot(50, this, SLOT(timerDone()));
+}
+
+void KNewAccountDlg::timerDone(void)
+{
+ if(m_accountItem) m_qlistviewParentAccounts->ensureItemVisible(m_accountItem);
+ if(m_parentItem) m_qlistviewParentAccounts->ensureItemVisible(m_parentItem);
+ // KNewAccountDlgDecl::resizeEvent(0);
+ m_qlistviewParentAccounts->setColumnWidth(m_qlistviewParentAccounts->nameColumn(), m_qlistviewParentAccounts->visibleWidth());
+ m_qlistviewParentAccounts->repaintContents(false);
+}
+
+void KNewAccountDlg::setOpeningBalance(const MyMoneyMoney& balance)
+{
+ m_openingBalanceEdit->setValue(balance);
+}
+
+void KNewAccountDlg::setOpeningBalanceShown(bool shown)
+{
+ m_openingBalanceEdit->setShown(shown);
+}
+
+void KNewAccountDlg::okClicked()
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString accountNameText = accountNameEdit->text();
+ if (accountNameText.isEmpty())
+ {
+ KMessageBox::error(this, i18n("You have not specified a name.\nPlease fill in this field."));
+ accountNameEdit->setFocus();
+ return;
+ }
+
+ MyMoneyAccount parent = parentAccount();
+ if (parent.name().length() == 0)
+ {
+ KMessageBox::error(this, i18n("Please select a parent account."));
+ return;
+ }
+
+ if (!m_categoryEditor)
+ {
+ QString institutionNameText = m_qcomboboxInstitutions->currentText();
+ if (institutionNameText != i18n("<No Institution>"))
+ {
+ try
+ {
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyInstitution> list = file->institutionList();
+ QValueList<MyMoneyInstitution>::ConstIterator institutionIterator;
+ for (institutionIterator = list.begin(); institutionIterator != list.end(); ++institutionIterator)
+ {
+ if ((*institutionIterator).name() == institutionNameText)
+ m_account.setInstitutionId((*institutionIterator).id());
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ qDebug("Exception in account institution set: %s", e->what().latin1());
+ delete e;
+ }
+ }
+ else
+ {
+ m_account.setInstitutionId(QString());
+ }
+ }
+
+ m_account.setName(accountNameText);
+ m_account.setNumber(accountNoEdit->text());
+ storeKVP("iban", ibanEdit);
+ storeKVP("minBalanceAbsolute", m_minBalanceAbsoluteEdit);
+ storeKVP("minBalanceEarly", m_minBalanceEarlyEdit);
+
+ // the figures for credit line with reversed sign
+ if(!m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty())
+ m_maxCreditAbsoluteEdit->setValue(m_maxCreditAbsoluteEdit->value()*MyMoneyMoney(-1,1));
+ if(!m_maxCreditEarlyEdit->lineedit()->text().isEmpty())
+ m_maxCreditEarlyEdit->setValue(m_maxCreditEarlyEdit->value()*MyMoneyMoney(-1,1));
+ storeKVP("maxCreditAbsolute", m_maxCreditAbsoluteEdit);
+ storeKVP("maxCreditEarly", m_maxCreditEarlyEdit);
+ if(!m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty())
+ m_maxCreditAbsoluteEdit->setValue(m_maxCreditAbsoluteEdit->value()*MyMoneyMoney(-1,1));
+ if(!m_maxCreditEarlyEdit->lineedit()->text().isEmpty())
+ m_maxCreditEarlyEdit->setValue(m_maxCreditEarlyEdit->value()*MyMoneyMoney(-1,1));
+
+ storeKVP("lastNumberUsed", m_lastCheckNumberUsed);
+ // delete a previous version of the minimumbalance information
+ storeKVP("minimumBalance", QString(), QString());
+
+ MyMoneyAccount::accountTypeE acctype;
+ if (!m_categoryEditor)
+ {
+ acctype = KMyMoneyUtils::stringToAccountType(typeCombo->currentText());
+ // If it's a loan, check if the parent is asset or liability. In
+ // case of asset, we change the account type to be AssetLoan
+ if(acctype == MyMoneyAccount::Loan
+ && parent.accountGroup() == MyMoneyAccount::Asset)
+ acctype = MyMoneyAccount::AssetLoan;
+
+#if 0
+ // we do allow the same name for different accounts, so
+ // we don't need this check anymore.
+ if(!file->nameToAccount(accountNameText).isEmpty()
+ && (file->nameToAccount(accountNameText) != m_account.id())) {
+ KMessageBox::error(this, QString("<qt>")+i18n("An account named <b>%1</b> already exists. You cannot create a second account with the same name.").arg(accountNameText)+QString("</qt>"));
+ return;
+ }
+#endif
+ }
+ else
+ {
+ acctype = parent.accountGroup();
+ QString newName;
+ if(!MyMoneyFile::instance()->isStandardAccount(parent.id())) {
+ newName = MyMoneyFile::instance()->accountToCategory(parent.id()) + MyMoneyFile::AccountSeperator;
+ }
+ newName += accountNameText;
+ if(!file->categoryToAccount(newName, acctype).isEmpty()
+ && (file->categoryToAccount(newName, acctype) != m_account.id())) {
+ KMessageBox::error(this, QString("<qt>")+i18n("A category named <b>%1</b> already exists. You cannot create a second category with the same name.").arg(newName)+QString("</qt>"));
+ return;
+ }
+ }
+ m_account.setAccountType(acctype);
+
+ m_account.setDescription(descriptionEdit->text());
+
+ if (!m_categoryEditor)
+ {
+ m_account.setOpeningDate(startDateEdit->date());
+ m_account.setCurrencyId(m_currency->security().id());
+
+ if(m_qcheckboxPreferred->isChecked())
+ m_account.setValue("PreferredAccount", "Yes");
+ else
+ m_account.deletePair("PreferredAccount");
+ if(m_qcheckboxNoVat->isChecked())
+ m_account.setValue("NoVat", "Yes");
+ else
+ m_account.deletePair("NoVat");
+
+ if(m_minBalanceAbsoluteEdit->isVisible()) {
+ m_account.setValue("minimumBalance", m_minBalanceAbsoluteEdit->value().toString());
+ }
+ }
+ else
+ {
+ if(KMyMoneyGlobalSettings::hideUnusedCategory() && !m_isEditing) {
+ KMessageBox::information(this, i18n("You have selected to suppress the display of unused categories in the KMyMoney configuration dialog. The category you just created will therefore only be shown if it is used. Otherwise, it will be hidden in the accounts/categories view."), i18n("Hidden categories"), "NewHiddenCategory");
+ }
+ }
+
+ if ( m_qcheckboxTax->isChecked())
+ m_account.setValue("Tax", "Yes");
+ else
+ m_account.deletePair("Tax");
+
+ m_account.deletePair("VatAccount");
+ m_account.deletePair("VatAmount");
+ m_account.deletePair("VatRate");
+
+ if(m_vatCategory->isChecked()) {
+ m_account.setValue("VatRate", (m_vatRate->value().abs() / MyMoneyMoney(100,1)).toString());
+ } else {
+ if(m_vatAssignment->isChecked()) {
+ m_account.setValue("VatAccount", m_vatAccount->selectedItems().first());
+ if(m_netAmount->isChecked())
+ m_account.setValue("VatAmount", "Net");
+ }
+ }
+
+ accept();
+}
+
+void KNewAccountDlg::loadKVP(const QString& key, kMyMoneyEdit* widget)
+{
+ if(!widget)
+ return;
+
+ if(m_account.value(key).isEmpty()) {
+ widget->clearText();
+ } else {
+ widget->setValue(MyMoneyMoney(m_account.value(key)));
+ }
+}
+
+void KNewAccountDlg::loadKVP(const QString& key, KLineEdit* widget)
+{
+ if(!widget)
+ return;
+
+ widget->setText(m_account.value(key));
+}
+
+void KNewAccountDlg::storeKVP(const QString& key, const QString& text, const QString& value)
+{
+ if(text.isEmpty())
+ m_account.deletePair(key);
+ else
+ m_account.setValue(key, value);
+}
+
+void KNewAccountDlg::storeKVP(const QString& key, kMyMoneyEdit* widget)
+{
+ storeKVP(key, widget->lineedit()->text(), widget->text());
+}
+
+void KNewAccountDlg::storeKVP(const QString& key, KLineEdit* widget)
+{
+ storeKVP(key, widget->text(), widget->text());
+}
+
+const MyMoneyAccount& KNewAccountDlg::account(void)
+{
+ // assign the right currency to the account
+ m_account.setCurrencyId(m_currency->security().id());
+
+ // and the price mode
+ switch(m_priceMode->currentItem()) {
+ case 0:
+ m_account.deletePair("priceMode");
+ break;
+ case 1:
+ case 2:
+ m_account.setValue("priceMode", QString("%1").arg(m_priceMode->currentItem()));
+ break;
+ }
+
+ return m_account;
+}
+
+const MyMoneyAccount& KNewAccountDlg::parentAccount(void)
+{
+ if (!m_bSelectedParentAccount)
+ {
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ switch (m_account.accountGroup())
+ {
+ case MyMoneyAccount::Asset:
+ m_parentAccount = file->asset();
+ break;
+ case MyMoneyAccount::Liability:
+ m_parentAccount = file->liability();
+ break;
+ case MyMoneyAccount::Income:
+ m_parentAccount = file->income();
+ break;
+ case MyMoneyAccount::Expense:
+ m_parentAccount = file->expense();
+ break;
+ case MyMoneyAccount::Equity:
+ m_parentAccount = file->equity();
+ break;
+ default:
+ qDebug("Seems we have an account that hasn't been mapped to the top five");
+ if(m_categoryEditor)
+ m_parentAccount = file->income();
+ else
+ m_parentAccount = file->asset();
+ }
+ }
+ return m_parentAccount;
+}
+
+void KNewAccountDlg::initParentWidget(QString parentId, const QString& accountId)
+{
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ MyMoneyAccount liabilityAccount = file->liability();
+ MyMoneyAccount assetAccount = file->asset();
+ MyMoneyAccount expenseAccount = file->expense();
+ MyMoneyAccount incomeAccount = file->income();
+ MyMoneyAccount equityAccount = file->equity();
+
+ m_parentItem = 0;
+ m_accountItem = 0;
+
+ // Determine the parent account
+ try
+ {
+ m_parentAccount = file->account(parentId);
+ }
+ catch (MyMoneyException *e)
+ {
+ m_bSelectedParentAccount = false;
+ m_parentAccount = MyMoneyAccount();
+ if(m_account.accountType() != MyMoneyAccount::UnknownAccountType) {
+ parentAccount();
+ parentId = m_parentAccount.id();
+ }
+ delete e;
+ }
+ m_bSelectedParentAccount = true;
+
+ // extract the account type from the combo box
+ MyMoneyAccount::accountTypeE type;
+ MyMoneyAccount::accountTypeE groupType;
+ type = KMyMoneyUtils::stringToAccountType(typeCombo->currentText());
+ groupType = MyMoneyAccount::accountGroup(type);
+
+ m_qlistviewParentAccounts->clear();
+
+ // Now scan all 4 account roots to load the list and mark the parent
+ try
+ {
+ if (!m_categoryEditor)
+ {
+ if(groupType == MyMoneyAccount::Asset || type == MyMoneyAccount::Loan) {
+ // Asset
+ KMyMoneyAccountTreeBaseItem *assetTopLevelAccount = new KMyMoneyAccountTreeItem(m_qlistviewParentAccounts, assetAccount);
+
+ if(m_parentAccount.id().isEmpty()) {
+ m_parentAccount = assetAccount;
+ parentId = m_parentAccount.id();
+ }
+
+ if (parentId == assetAccount.id())
+ m_parentItem = assetTopLevelAccount;
+
+ assetTopLevelAccount->setOpen(true);
+
+ for ( QStringList::ConstIterator it = assetAccount.accountList().begin();
+ it != assetAccount.accountList().end();
+ ++it )
+ {
+ MyMoneyAccount acc = file->account(*it);
+ if(acc.isClosed())
+ continue;
+
+ KMyMoneyAccountTreeBaseItem *accountItem = new KMyMoneyAccountTreeItem(assetTopLevelAccount, acc);
+
+ if(parentId == acc.id()) {
+ m_parentItem = accountItem;
+ } else if(accountId == acc.id()) {
+ if(m_isEditing)
+ accountItem->setSelectable(false);
+ m_accountItem = accountItem;
+ }
+
+ QStringList subAccounts = acc.accountList();
+ if (subAccounts.count() >= 1)
+ {
+ showSubAccounts(subAccounts, accountItem, parentId, acc.id());
+ }
+ }
+ }
+
+ if(groupType == MyMoneyAccount::Liability) {
+ // Liability
+ KMyMoneyAccountTreeBaseItem *liabilityTopLevelAccount = new KMyMoneyAccountTreeItem(m_qlistviewParentAccounts, liabilityAccount);
+
+ if(m_parentAccount.id().isEmpty()) {
+ m_parentAccount = liabilityAccount;
+ parentId = m_parentAccount.id();
+ }
+
+ if (parentId == liabilityAccount.id())
+ m_parentItem = liabilityTopLevelAccount;
+
+ liabilityTopLevelAccount->setOpen(true);
+
+ for ( QStringList::ConstIterator it = liabilityAccount.accountList().begin();
+ it != liabilityAccount.accountList().end();
+ ++it )
+ {
+ MyMoneyAccount acc = file->account(*it);
+ if(acc.isClosed())
+ continue;
+
+ KMyMoneyAccountTreeBaseItem *accountItem = new KMyMoneyAccountTreeItem(liabilityTopLevelAccount, acc);
+
+ if(parentId == acc.id()) {
+ m_parentItem = accountItem;
+ } else if(accountId == acc.id()) {
+ if(m_isEditing)
+ accountItem->setSelectable(false);
+ m_accountItem = accountItem;
+ }
+
+ QStringList subAccounts = acc.accountList();
+ if (subAccounts.count() >= 1)
+ {
+ showSubAccounts(subAccounts, accountItem, parentId, acc.id());
+ }
+ }
+ }
+ }
+ else
+ {
+ if(groupType == MyMoneyAccount::Income) {
+ // Income
+ KMyMoneyAccountTreeBaseItem *incomeTopLevelAccount = new KMyMoneyAccountTreeItem(m_qlistviewParentAccounts,
+ incomeAccount);
+
+ if(m_parentAccount.id().isEmpty()) {
+ m_parentAccount = incomeAccount;
+ parentId = m_parentAccount.id();
+ }
+
+ if (parentId == incomeAccount.id())
+ m_parentItem = incomeTopLevelAccount;
+
+ incomeTopLevelAccount->setOpen(true);
+
+ for ( QStringList::ConstIterator it = incomeAccount.accountList().begin();
+ it != incomeAccount.accountList().end();
+ ++it )
+ {
+ KMyMoneyAccountTreeBaseItem *accountItem = new KMyMoneyAccountTreeItem(incomeTopLevelAccount,
+ file->account(*it));
+
+ QString id = file->account(*it).id();
+ if(parentId == id) {
+ m_parentItem = accountItem;
+ } else if(accountId == id) {
+ if(m_isEditing)
+ accountItem->setSelectable(false);
+ m_accountItem = accountItem;
+ }
+
+ QStringList subAccounts = file->account(*it).accountList();
+ if (subAccounts.count() >= 1)
+ {
+ showSubAccounts(subAccounts, accountItem, parentId, accountId);
+ }
+ }
+ }
+
+ if(groupType == MyMoneyAccount::Expense) {
+ // Expense
+ KMyMoneyAccountTreeBaseItem *expenseTopLevelAccount = new KMyMoneyAccountTreeItem(m_qlistviewParentAccounts,
+ expenseAccount);
+
+ if(m_parentAccount.id().isEmpty()) {
+ m_parentAccount = expenseAccount;
+ parentId = m_parentAccount.id();
+ }
+
+ if (parentId == expenseAccount.id())
+ m_parentItem = expenseTopLevelAccount;
+
+ expenseTopLevelAccount->setOpen(true);
+
+ for ( QStringList::ConstIterator it = expenseAccount.accountList().begin();
+ it != expenseAccount.accountList().end();
+ ++it )
+ {
+ KMyMoneyAccountTreeBaseItem *accountItem = new KMyMoneyAccountTreeItem(expenseTopLevelAccount,
+ file->account(*it));
+
+ QString id = file->account(*it).id();
+ if(parentId == id) {
+ m_parentItem = accountItem;
+ } else if(accountId == id) {
+ if(m_isEditing)
+ accountItem->setSelectable(false);
+ m_accountItem = accountItem;
+ }
+
+ QStringList subAccounts = file->account(*it).accountList();
+ if (subAccounts.count() >= 1)
+ {
+ showSubAccounts(subAccounts, accountItem, parentId, accountId);
+ }
+ }
+ }
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ qDebug("Exception in assets account refresh: %s", e->what().latin1());
+ delete e;
+ }
+
+ m_qlistviewParentAccounts->setColumnWidth(0, m_qlistviewParentAccounts->width());
+
+ if (m_parentItem)
+ {
+ m_subAccountLabel->setText(i18n("Is a sub account of %1").arg(m_parentAccount.name()));
+ m_parentItem->setOpen(true);
+ m_qlistviewParentAccounts->setSelected(m_parentItem, true);
+ }
+
+ m_qlistviewParentAccounts->setEnabled(true);
+}
+
+void KNewAccountDlg::showSubAccounts(QStringList accounts, KMyMoneyAccountTreeBaseItem *parentItem,
+ const QString& parentId, const QString& accountId)
+{
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ for ( QStringList::ConstIterator it = accounts.begin(); it != accounts.end(); ++it )
+ {
+ KMyMoneyAccountTreeBaseItem *accountItem = new KMyMoneyAccountTreeItem(parentItem,
+ file->account(*it));
+
+ QString id = file->account(*it).id();
+ if(parentId == id) {
+ m_parentItem = accountItem;
+ } else if(accountId == id) {
+ if(m_isEditing)
+ accountItem->setSelectable(false);
+ m_accountItem = accountItem;
+ }
+
+ QStringList subAccounts = file->account(*it).accountList();
+ if (subAccounts.count() >= 1)
+ {
+ showSubAccounts(subAccounts, accountItem, parentId, accountId);
+ }
+ }
+}
+
+void KNewAccountDlg::resizeEvent(QResizeEvent* e)
+{
+ m_qlistviewParentAccounts->setColumnWidth(0, m_qlistviewParentAccounts->width());
+
+ // call base class resizeEvent()
+ KNewAccountDlgDecl::resizeEvent(e);
+}
+
+void KNewAccountDlg::slotSelectionChanged(QListViewItem *item)
+{
+ KMyMoneyAccountTreeBaseItem *accountItem = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(item);
+ try
+ {
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ //qDebug("Selected account id: %s", accountItem->accountID().data());
+ m_parentAccount = file->account(accountItem->id());
+ m_subAccountLabel->setText(i18n("Is a sub account of %1").arg(m_parentAccount.name()));
+ if(m_qlistviewParentAccounts->isEnabled()) {
+ m_bSelectedParentAccount = true;
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ qDebug("This shouldn't happen! : %s", e->what().latin1());
+ delete e;
+ }
+}
+
+void KNewAccountDlg::loadVatAccounts(void)
+{
+ QValueList<MyMoneyAccount> list;
+ MyMoneyFile::instance()->accountList(list);
+ QValueList<MyMoneyAccount>::Iterator it;
+ QStringList loadListExpense;
+ QStringList loadListIncome;
+ QStringList loadListAsset;
+ QStringList loadListLiability;
+ for(it = list.begin(); it != list.end(); ++it) {
+ if(!(*it).value("VatRate").isEmpty()) {
+ if((*it).accountType() == MyMoneyAccount::Expense)
+ loadListExpense += (*it).id();
+ else if((*it).accountType() == MyMoneyAccount::Income)
+ loadListIncome += (*it).id();
+ else if((*it).accountType() == MyMoneyAccount::Asset)
+ loadListAsset += (*it).id();
+ else if((*it).accountType() == MyMoneyAccount::Liability)
+ loadListLiability += (*it).id();
+ }
+ }
+ AccountSet vatSet;
+ if(!loadListAsset.isEmpty())
+ vatSet.load(m_vatAccount, i18n("Asset"), loadListAsset, true);
+ if(!loadListLiability.isEmpty())
+ vatSet.load(m_vatAccount, i18n("Liability"), loadListLiability, false);
+ if(!loadListIncome.isEmpty())
+ vatSet.load(m_vatAccount, i18n("Income"), loadListIncome, false);
+ if(!loadListExpense.isEmpty())
+ vatSet.load(m_vatAccount, i18n("Expense"), loadListExpense, false);
+}
+
+void KNewAccountDlg::slotLoadInstitutions(const QString& name)
+{
+ int id=-1, counter=0;
+ m_qcomboboxInstitutions->clear();
+ QString bic;
+ // Are we forcing the user to use institutions?
+ m_qcomboboxInstitutions->insertItem(i18n("<No Institution>"));
+ m_bicValue->setText(" ");
+ ibanEdit->setEnabled(false);
+ accountNoEdit->setEnabled(false);
+ try
+ {
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyInstitution> list = file->institutionList();
+ QValueList<MyMoneyInstitution>::ConstIterator institutionIterator;
+ for (institutionIterator = list.begin(), counter=1; institutionIterator != list.end(); ++institutionIterator, counter++)
+ {
+ if ((*institutionIterator).name() == name) {
+ id = counter;
+ ibanEdit->setEnabled(true);
+ accountNoEdit->setEnabled(true);
+ m_bicValue->setText((*institutionIterator).value("bic"));
+ }
+ m_qcomboboxInstitutions->insertItem((*institutionIterator).name());
+ }
+
+ if (id != -1)
+ {
+ m_qcomboboxInstitutions->setCurrentItem(id);
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ qDebug("Exception in institution load: %s", e->what().latin1());
+ delete e;
+ }
+}
+
+void KNewAccountDlg::slotNewClicked()
+{
+ MyMoneyInstitution institution;
+
+ KNewBankDlg dlg(institution, this);
+ if (dlg.exec())
+ {
+ MyMoneyFileTransaction ft;
+ try
+ {
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ institution = dlg.institution();
+ file->addInstitution(institution);
+ ft.commit();
+ slotLoadInstitutions(institution.name());
+ }
+ catch (MyMoneyException *e)
+ {
+ delete e;
+ KMessageBox::information(this, i18n("Cannot add institution"));
+ }
+ }
+}
+
+void KNewAccountDlg::slotAccountTypeChanged(const QString& typeStr)
+{
+ MyMoneyAccount::accountTypeE type;
+ MyMoneyAccount::accountTypeE oldType;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ type = KMyMoneyUtils::stringToAccountType(typeStr);
+ try {
+ oldType = m_account.accountType();
+ if(oldType != type) {
+ QString parentId;
+ switch(MyMoneyAccount::accountGroup(type)) {
+ case MyMoneyAccount::Asset:
+ parentId = file->asset().id();
+ break;
+ case MyMoneyAccount::Liability:
+ parentId = file->liability().id();
+ break;
+ case MyMoneyAccount::Expense:
+ parentId = file->expense().id();
+ break;
+ case MyMoneyAccount::Income:
+ parentId = file->income().id();
+ break;
+ default:
+ qWarning("Unknown account group in KNewAccountDlg::slotAccountTypeChanged()");
+ break;
+ }
+ initParentWidget(parentId, QString());
+ m_account.setAccountType(type);
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ qWarning("Unexpected exception in KNewAccountDlg::slotAccountTypeChanged()");
+ }
+}
+
+void KNewAccountDlg::slotCheckFinished(void)
+{
+ bool showButton = true;
+
+ if(accountNameEdit->text().length() == 0) {
+ showButton = false;
+ }
+
+ if(m_vatCategory->isChecked() && m_vatRate->value() <= MyMoneyMoney(0)) {
+ showButton = false;
+ } else {
+ if(m_vatAssignment->isChecked() && m_vatAccount->selectedItems().isEmpty())
+ showButton = false;
+ }
+ createButton->setEnabled(showButton);
+}
+
+void KNewAccountDlg::slotVatChanged(bool state)
+{
+ if(state) {
+ m_vatCategoryFrame->show();
+ m_vatAssignmentFrame->hide();
+ } else {
+ m_vatCategoryFrame->hide();
+ if(!m_account.isAssetLiability()) {
+ m_vatAssignmentFrame->show();
+ }
+ }
+}
+
+void KNewAccountDlg::slotVatAssignmentChanged(bool state)
+{
+ m_vatAccount->setEnabled(state);
+ m_amountGroup->setEnabled(state);
+}
+
+void KNewAccountDlg::adjustEditWidgets(kMyMoneyEdit* dst, kMyMoneyEdit* src, char mode, int corr)
+{
+ MyMoneyMoney factor(corr, 1);
+ if(m_account.accountGroup() == MyMoneyAccount::Asset)
+ factor = -factor;
+
+ switch(mode) {
+ case '<':
+ if(src->value()*factor < dst->value()*factor)
+ dst->setValue(src->value());
+ break;
+
+ case '>':
+ if(src->value()*factor > dst->value()*factor)
+ dst->setValue(src->value());
+ break;
+ }
+}
+
+void KNewAccountDlg::slotAdjustMinBalanceAbsoluteEdit(const QString&)
+{
+ adjustEditWidgets(m_minBalanceAbsoluteEdit, m_minBalanceEarlyEdit, '<', -1);
+}
+
+void KNewAccountDlg::slotAdjustMinBalanceEarlyEdit(const QString&)
+{
+ adjustEditWidgets(m_minBalanceEarlyEdit, m_minBalanceAbsoluteEdit, '>', -1);
+}
+
+void KNewAccountDlg::slotAdjustMaxCreditAbsoluteEdit(const QString&)
+{
+ adjustEditWidgets(m_maxCreditAbsoluteEdit, m_maxCreditEarlyEdit, '>', 1);
+}
+
+void KNewAccountDlg::slotAdjustMaxCreditEarlyEdit(const QString&)
+{
+ adjustEditWidgets(m_maxCreditEarlyEdit, m_maxCreditAbsoluteEdit, '<', 1);
+}
+
+void KNewAccountDlg::addTab(QWidget* w, const QString& name)
+{
+ if(w) {
+ w->reparent(m_tab, QPoint(0,0));
+ m_tab->addTab(w, name);
+ }
+}
+
+
+#include "knewaccountdlg.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/knewaccountdlg.h b/kmymoney2/dialogs/knewaccountdlg.h
new file mode 100644
index 0000000..ee09158
--- /dev/null
+++ b/kmymoney2/dialogs/knewaccountdlg.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ knewaccountdlg.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWACCOUNTDLG_H
+#define KNEWACCOUNTDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#ifdef HAVE_KDCHART
+#include <KDChartWidget.h>
+#include <KDChartTable.h>
+#include <KDChartParams.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/kmymoneyedit.h>
+
+#include "../dialogs/knewaccountdlgdecl.h"
+class KMyMoneyAccountTreeBaseItem;
+namespace reports {
+ class KReportChartView;
+};
+
+/**
+ * This dialog lets you create/edit an account.
+ */
+class KNewAccountDlg : public KNewAccountDlgDecl
+{
+ Q_OBJECT
+
+private:
+ MyMoneyAccount m_account;
+ MyMoneyAccount m_parentAccount;
+ bool m_bSelectedParentAccount;
+
+ KMyMoneyAccountTreeBaseItem *m_parentItem;
+ KMyMoneyAccountTreeBaseItem *m_accountItem;
+ bool m_categoryEditor;
+ bool m_isEditing;
+
+ int m_idPropFutureValue;
+ int m_idPropLastValue;
+ int m_idPropMaxCredit;
+ int m_idPropMinBalance;
+
+ void initParentWidget(QString parentId, const QString& accountId);
+ void showSubAccounts(QStringList accounts, KMyMoneyAccountTreeBaseItem *parentItem, const QString& parentId, const QString& accountId);
+ void loadVatAccounts(void);
+ void storeKVP(const QString& key, kMyMoneyEdit* widget);
+ void storeKVP(const QString& key, KLineEdit* widget);
+ void storeKVP(const QString& key, const QString& text, const QString& value);
+ void loadKVP(const QString& key, kMyMoneyEdit* widget);
+ void loadKVP(const QString& key, KLineEdit* widget);
+
+public:
+ /**
+ * This is the constructor of the dialog. The parameters define the environment
+ * in which the dialog will be used. Depending on the environment, certain rules
+ * apply and will be handled by the dialog.
+ *
+ * @param account The original data to be used to create the account. In case
+ * of @p isEditing is false, the account id, the parent account id
+ * and the list of all child accounts will be cleared.
+ * @param isEditing If @p false, rules for new account creation apply.
+ * If @p true, rules for account editing apply
+ * @param categoryEditor If @p false, rules for asset/liability accounts apply.
+ * If @p true, rules for income/expense account apply.
+ * @param parent Pointer to parent object (passed to QDialog). Default is 0.
+ * @param name Name of the object (passed to QDialog). Default is 0.
+ * @param title Caption of the object (passed to QDialog). Default is empty string.
+ */
+ KNewAccountDlg(const MyMoneyAccount& account, bool isEditing, bool categoryEditor, QWidget *parent=0, const char *name=0, const QString& title=QString::null);
+
+ /**
+ * This method returns the edited account object.
+ */
+ const MyMoneyAccount& account(void);
+
+ /**
+ * This method returns the parent account of the edited account object.
+ */
+ const MyMoneyAccount& parentAccount(void);
+
+ void setOpeningBalance(const MyMoneyMoney& balance);
+
+ const MyMoneyMoney openingBalance(void) const { return m_openingBalanceEdit->value(); };
+
+ void setOpeningBalanceShown(bool shown);
+
+ /**
+ * This method adds an additional tab pointed to with @a w to the tab widget.
+ * This tab is usually defined by a plugin (eg. online banking). If @a w is
+ * zero, this is a NOP. @a name is used as the text to be placed on the tab.
+ */
+ void addTab(QWidget* w, const QString& name);
+
+protected:
+ void resizeEvent(QResizeEvent* e);
+ void displayOnlineBankingStatus(void);
+ void adjustEditWidgets(kMyMoneyEdit* dst, kMyMoneyEdit* src, char mode, int corr);
+
+protected slots:
+ void okClicked();
+ void slotSelectionChanged(QListViewItem *item);
+ void slotAccountTypeChanged(const QString& type);
+ void slotVatChanged(bool);
+ void slotVatAssignmentChanged(bool);
+ void slotNewClicked(void);
+ void slotCheckFinished(void);
+ void slotLoadInstitutions(const QString&);
+ void slotAdjustMinBalanceAbsoluteEdit(const QString&);
+ void slotAdjustMinBalanceEarlyEdit(const QString&);
+ void slotAdjustMaxCreditAbsoluteEdit(const QString&);
+ void slotAdjustMaxCreditEarlyEdit(const QString&);
+
+private slots:
+ void timerDone(void);
+
+};
+
+#endif
+
diff --git a/kmymoney2/dialogs/knewaccountdlgdecl.ui b/kmymoney2/dialogs/knewaccountdlgdecl.ui
new file mode 100644
index 0000000..6f6357e
--- /dev/null
+++ b/kmymoney2/dialogs/knewaccountdlgdecl.ui
@@ -0,0 +1,1044 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KNewAccountDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kNewAccountDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>670</width>
+ <height>518</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Account Dialog</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_tab</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_generalTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>60</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>MShape</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>MShadow</enum>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>accountNameEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Opening information</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KMyMoneySecuritySelector" row="1" column="1">
+ <property name="name">
+ <cstring>m_currency</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_currencyText</cstring>
+ </property>
+ <property name="text">
+ <string>Currency:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>typeCombo</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>MShape</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>MShadow</enum>
+ </property>
+ <property name="text">
+ <string>Date:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="0" column="3">
+ <property name="name">
+ <cstring>startDateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Balance:</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="3">
+ <property name="name">
+ <cstring>m_openingBalanceEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>m_lastCheckNumberUsed</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Last check number:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Notes:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QTextEdit" row="1" column="1">
+ <property name="name">
+ <cstring>descriptionEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>m_qcheckboxNoVat</cstring>
+ </property>
+ <property name="text">
+ <string>No auto-VAT-assignment</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>Price entry</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo">
+ <property name="name">
+ <cstring>m_priceMode</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_qcheckboxPreferred</cstring>
+ </property>
+ <property name="text">
+ <string>Preferred Account</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_institutionTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Institution</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_institutionBox</cstring>
+ </property>
+ <property name="title">
+ <string>Institution</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>m_qcomboboxInstitutions</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_qbuttonNew</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>New...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>accountNoEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>60</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Number:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>BIC</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>ibanEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>IBAN</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_bicValue</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_hiearchyTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Hierarchy</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_subAccountLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Subaccount</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyAccountTreeBase">
+ <header location="global">../widgets/kmymoneyaccounttreebase.h</header>
+ <property name="name">
+ <cstring>m_qlistviewParentAccounts</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_limitsTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Limits</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>This page allows to setup certain limits. KMyMoney will warn you when the account balance reaches a limit.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="2">
+ <property name="name">
+ <cstring>m_minBalanceAbsoluteEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Absolute limit</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>m_maxCreditLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Maximum credit limit</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="3" column="1">
+ <property name="name">
+ <cstring>m_maxCreditEarlyEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="3" column="2">
+ <property name="name">
+ <cstring>m_maxCreditAbsoluteEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_minBalanceEarlyEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>m_minBalanceLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum balance</string>
+ </property>
+ </widget>
+ <widget class="Line" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Early warning</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_taxTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Tax</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>VAT details</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout34</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_vatCategory</cstring>
+ </property>
+ <property name="text">
+ <string>VAT category</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_vatCategoryFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>VAT percentage</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout33</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_vatRate</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer17</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_vatAssignmentFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_vatAssignment</cstring>
+ </property>
+ <property name="text">
+ <string>Enable auto VAT assignment</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_vatAccount</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_amountGroup</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>Amount entered</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_grossAmount</cstring>
+ </property>
+ <property name="text">
+ <string>Gross amount</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_netAmount</cstring>
+ </property>
+ <property name="text">
+ <string>Net amount</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_qcheckboxTax</cstring>
+ </property>
+ <property name="text">
+ <string>Include on Tax Reports</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout29</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>422</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>createButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyAccountSelector</class>
+ <header location="global">../widgets/kmymoneyaccountselector.h</header>
+ <sizehint>
+ <width>80</width>
+ <height>80</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>kMyMoneyAccountTreeBase</class>
+ <header location="global">../widgets/kmymoneyaccounttreebase.h</header>
+ <sizehint>
+ <width>80</width>
+ <height>80</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1110">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000041d49444154388d8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d09a6c508138cb8c13d647141163de49043bca9f1628eb9294810f24f88c15b728b07617358888785d980427290b4a8d00b19a8821da8228cf42316ac87eed9247ac95c9aeaeef9eaabdffb5ebf85f178ccfcf7f5b79fec07a7280a08a008f25ceb7c29e5da573716e65a0be3f198ef6f5ededff9b9e1b34faf90882092a1ea21428b9220ffbf46054055b19386ba6970ae6665b5e0d2c5eb0b066067bbe1f21757c88f5504eff0c192189081303a5582b16854fccce2fe041f00cdd0a8103b874556405476b62d972ec2c2b90ff3fd8df5cb946549d80b34aea15ccaa94625450e2d0e558b460b7371a734b5e027251a155545678ab62d7eea90b4c504078908c107acb354cb251b1f8f08b1c18631aabbb4d18211404804f22545863561d2f060fb34aa8a18d0086204e72c46a32292e1a796f278c1da7a859d8da9a737506db04d0a24103d8949480b214d3bbee952a05c1d536f9d2684160c744f048311543d459eb1b65ee1754cedae13a64abd5d6127053c9d0281f22d4f75c6a2118a5c09272d7ab740638bf4ef2dd2174032d0d8d04c6fe19c32bedd8bc65e342aa3f785e2784bfd6bc1bd9db24b05505616a4edd67d5a8c1801a03a9962754c504bf34b8986acfb9be91cac7d54315a15541b36b134f74bd2dc53940115a5381e087bc25c6f71be831a8baa234cc1ee3eeb74ed83116beb2b8849d108a3730e8ce27e2bfb82419a7b407ac7c222fd0e6280a8078ce64e47ef54ac9d5be9aaae0162e0de568a44a18d3df90845d919c4f01463406340a44f40efb43a99b371618488e2670d1a2d7ee6f1d3be39342104e937ed85fb86599c33e9ee0be9a004946259d8b858909880d59aa00daa0d3280b5f39e34074c4b3a5434029a76a9e9f5cc0163b5c80024158a1cfc4cb1d3061d5834066cb0a403c008599a70f6bc27b8d03106ea3ae91987278c5b143b015547224ab5e24185cd9b81665273e7b6e7cecd82ddbf8098002de94049737bc09828cf3036f31c3735c8b0e98eb704672f348c7f7c93cd1fb2ae905119ff54e0dff3542b0e9dd983dcea2cc5eea6cf303e74ec687af5c41b6fa38f5e203c7ec8e1238ef85831a214afef21060ea781ec68247b65c6916353cc8b73d1ae79354606af2a930709aa118da1636c274dd7e3774b884a79aa6b5711a538d33cf9c01c1c9b83bc6a1f55c91ccb23b05b1deb43a7decdaffefd2862f61366aa8449c69e33642f012f2bb208fa98eeda1f3346f076c8eeef19475e9be115423364f78f84105a8643d34d90cfbfdcd8cf872589a45dc7f54cf3134a36f4e495c23f9da8db15bccb708d4014f2ca512cb5d4f7c13e84300d5cff6eb39b202bab053bdb9674f0648609427d0f8402ddeac30f4fcd3ced3efc3b422d406c09b340bedc1571e1bfc3d44dc281634c5fe5e758e7395cfbe6d6c130fd17d92372d277c159b70000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>m_tab</tabstop>
+ <tabstop>accountNameEdit</tabstop>
+ <tabstop>typeCombo</tabstop>
+ <tabstop>startDateEdit</tabstop>
+ <tabstop>m_currency</tabstop>
+ <tabstop>m_openingBalanceEdit</tabstop>
+ <tabstop>m_lastCheckNumberUsed</tabstop>
+ <tabstop>descriptionEdit</tabstop>
+ <tabstop>m_qcheckboxPreferred</tabstop>
+ <tabstop>m_qcheckboxNoVat</tabstop>
+ <tabstop>m_qcomboboxInstitutions</tabstop>
+ <tabstop>m_qbuttonNew</tabstop>
+ <tabstop>ibanEdit</tabstop>
+ <tabstop>accountNoEdit</tabstop>
+ <tabstop>m_qlistviewParentAccounts</tabstop>
+ <tabstop>kActiveLabel1</tabstop>
+ <tabstop>m_minBalanceEarlyEdit</tabstop>
+ <tabstop>m_minBalanceAbsoluteEdit</tabstop>
+ <tabstop>m_maxCreditEarlyEdit</tabstop>
+ <tabstop>m_maxCreditAbsoluteEdit</tabstop>
+ <tabstop>m_vatCategory</tabstop>
+ <tabstop>m_vatRate</tabstop>
+ <tabstop>m_vatAssignment</tabstop>
+ <tabstop>m_grossAmount</tabstop>
+ <tabstop>m_qcheckboxTax</tabstop>
+ <tabstop>createButton</tabstop>
+ <tabstop>cancelButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/knewbankdlg.cpp b/kmymoney2/dialogs/knewbankdlg.cpp
new file mode 100644
index 0000000..f1c4e3f
--- /dev/null
+++ b/kmymoney2/dialogs/knewbankdlg.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+ knewbankdlg.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qpixmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kguiitem.h>
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/kguiutils.h>
+
+#include "knewbankdlg.h"
+
+KNewBankDlg::KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent, const char *name)
+ : KNewBankDlgDecl(parent,name,true), m_institution(institution)
+{
+ okBtn->setGuiItem(KStdGuiItem::ok());
+ cancelBtn->setGuiItem(KStdGuiItem::cancel());
+
+ nameEdit->setFocus();
+ nameEdit->setText(institution.name());
+ cityEdit->setText(institution.city());
+ streetEdit->setText(institution.street());
+ postcodeEdit->setText(institution.postcode());
+ telephoneEdit->setText(institution.telephone());
+ bicEdit->setText(institution.value("bic"));
+ sortCodeEdit->setText(institution.sortcode());
+
+ connect(okBtn, SIGNAL(clicked()), SLOT(okClicked()));
+ connect(cancelBtn, SIGNAL(clicked()), SLOT(reject()));
+ connect(nameEdit, SIGNAL(textChanged ( const QString & )), SLOT(institutionNameChanged( const QString &)));
+ institutionNameChanged( nameEdit->text());
+
+ kMandatoryFieldGroup* requiredFields = new kMandatoryFieldGroup (this);
+ requiredFields->setOkButton(okBtn); // button to be enabled when all fields present
+ requiredFields->add(nameEdit);
+}
+
+void KNewBankDlg::institutionNameChanged( const QString &_text)
+{
+ okBtn->setEnabled( !_text.isEmpty() );
+}
+
+KNewBankDlg::~KNewBankDlg()
+{
+}
+
+void KNewBankDlg::okClicked()
+{
+ if (nameEdit->text().isEmpty()) {
+ KMessageBox::information(this, i18n("The institution name field is empty. Please enter the name."), i18n("Adding New Institution"));
+ nameEdit->setFocus();
+ return;
+ }
+
+ m_institution.setName(nameEdit->text());
+ m_institution.setTown(cityEdit->text());
+ m_institution.setStreet(streetEdit->text());
+ m_institution.setPostcode(postcodeEdit->text());
+ m_institution.setTelephone(telephoneEdit->text());
+ m_institution.setValue("bic", bicEdit->text());
+ m_institution.setSortcode(sortCodeEdit->text());
+
+ accept();
+}
+
+const MyMoneyInstitution& KNewBankDlg::institution(void)
+{
+ return m_institution;
+}
+
+
+#include "knewbankdlg.moc"
diff --git a/kmymoney2/dialogs/knewbankdlg.h b/kmymoney2/dialogs/knewbankdlg.h
new file mode 100644
index 0000000..f829a4c
--- /dev/null
+++ b/kmymoney2/dialogs/knewbankdlg.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ knewbankdlg.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWBANKDLG_H
+#define KNEWBANKDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdialog.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneyinstitution.h"
+#include "../mymoney/mymoneykeyvaluecontainer.h"
+
+#include "../dialogs/knewbankdlgdecl.h"
+
+/// This dialog lets the user create or edit an institution
+class KNewBankDlg : public KNewBankDlgDecl
+{
+ Q_OBJECT
+
+public:
+ KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent = 0, const char *name = 0);
+ ~KNewBankDlg();
+ const MyMoneyInstitution& institution(void);
+
+protected slots:
+ void okClicked();
+ void institutionNameChanged( const QString &);
+
+private:
+ MyMoneyInstitution m_institution;
+
+};
+
+#endif
diff --git a/kmymoney2/dialogs/knewbankdlgdecl.ui b/kmymoney2/dialogs/knewbankdlgdecl.ui
new file mode 100644
index 0000000..e6d4f52
--- /dev/null
+++ b/kmymoney2/dialogs/knewbankdlgdecl.ui
@@ -0,0 +1,268 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KNewBankDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kNewBankDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>631</width>
+ <height>344</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Institution Dialog</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Institution Details</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>nameEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>City:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>cityEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Street:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>streetEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Postal Code:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>postcodeEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Telephone/Fax:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>telephoneEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Routing Number:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="5" column="1">
+ <property name="name">
+ <cstring>sortCodeEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>BIC</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="6" column="1">
+ <property name="name">
+ <cstring>bicEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer30</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout51</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>449</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/knewbudgetdlg.cpp b/kmymoney2/dialogs/knewbudgetdlg.cpp
new file mode 100644
index 0000000..5971e54
--- /dev/null
+++ b/kmymoney2/dialogs/knewbudgetdlg.cpp
@@ -0,0 +1,83 @@
+/***************************************************************************
+ knewbudgetdlg.cpp
+ -------------------
+ begin : Wed Jan 18 2006
+ copyright : (C) 2000-2004 by Darren Gould
+ email : darren_gould@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "knewbudgetdlg.h"
+
+const int KNewBudgetDlg::m_icFutureYears = 5;
+const int KNewBudgetDlg::m_icPastYears = 2;
+
+KNewBudgetDlg::KNewBudgetDlg(QWidget* parent, const char *name) :
+ KNewBudgetDlgDecl(parent, name)
+{
+ QStringList slYear;
+ QDate dToday = QDate::currentDate();
+ int iYear = dToday.year();
+
+ for (int i=0; i<=m_icFutureYears; i++)
+ m_cbYear->insertItem( QString::number(iYear++) );
+
+ iYear = dToday.year();
+ for (int i=0; i<=m_icFutureYears; i++)
+ m_cbYear->insertItem( QString::number(--iYear) );
+}
+
+KNewBudgetDlg::~KNewBudgetDlg()
+{
+}
+
+void KNewBudgetDlg::m_pbCancel_clicked()
+{
+ reject();
+}
+
+void KNewBudgetDlg::m_pbOk_clicked()
+{
+ // force focus change to update all data
+ m_pbOk->setFocus();
+
+ if (m_leBudgetName->displayText().isEmpty())
+ {
+ KMessageBox::information(this, i18n("Please specify a budget name"));
+ m_leBudgetName->setFocus();
+ return;
+ }
+
+ m_year = m_cbYear->currentText();
+ m_name = m_leBudgetName->displayText();
+
+ accept();
+}
+
+
+#include "knewbudgetdlg.moc"
diff --git a/kmymoney2/dialogs/knewbudgetdlg.h b/kmymoney2/dialogs/knewbudgetdlg.h
new file mode 100644
index 0000000..db63e11
--- /dev/null
+++ b/kmymoney2/dialogs/knewbudgetdlg.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ knewbudgetdlg.h
+ -------------------
+ begin : Wed Jan 18 2006
+ copyright : (C) 2000-2004 by Darren Gould
+ email : darren_gould@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWBUDGETDLG_H
+#define KNEWBUDGETDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <qdatetime.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/knewbudgetdlgdecl.h"
+
+class KNewBudgetDlg : public KNewBudgetDlgDecl
+{
+ Q_OBJECT
+public:
+ KNewBudgetDlg(QWidget* parent, const char *name);
+ ~KNewBudgetDlg();
+
+ QString& getYear() {return m_year;};
+ QString& getName() {return m_name;};
+
+public slots:
+ virtual void m_pbCancel_clicked();
+ virtual void m_pbOk_clicked();
+
+private:
+ // the combobox should look m_icNextYears into the future
+ static const int m_icFutureYears;
+ static const int m_icPastYears;
+
+ QString m_year;
+ QString m_name;
+};
+
+#endif // KNEWBUDGETDLG_H
diff --git a/kmymoney2/dialogs/knewbudgetdlgdecl.ui b/kmymoney2/dialogs/knewbudgetdlgdecl.ui
new file mode 100644
index 0000000..7066a56
--- /dev/null
+++ b/kmymoney2/dialogs/knewbudgetdlgdecl.ui
@@ -0,0 +1,175 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KNewBudgetDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KNewBudgetDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>283</width>
+ <height>116</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Budget</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Year</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_leBudgetName</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>m_cbYear</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="currentItem">
+ <number>0</number>
+ </property>
+ <property name="sizeLimit">
+ <number>15</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pbOk</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pbCancel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>m_pbOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KNewBudgetDlgDecl</receiver>
+ <slot>m_pbOk_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pbCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KNewBudgetDlgDecl</receiver>
+ <slot>m_pbCancel_clicked()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">knewbudgetdlgdecl.ui.h</include>
+</includes>
+<slots>
+ <slot>m_pbOk_clicked()</slot>
+ <slot>m_pbCancel_clicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+
+
+
+
+</UI>
diff --git a/kmymoney2/dialogs/knewequityentrydecl.ui b/kmymoney2/dialogs/knewequityentrydecl.ui
new file mode 100644
index 0000000..affd116
--- /dev/null
+++ b/kmymoney2/dialogs/knewequityentrydecl.ui
@@ -0,0 +1,236 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kNewEquityEntryDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kNewEquityEntryDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>417</width>
+ <height>208</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Equity</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lblEquityName</cstring>
+ </property>
+ <property name="text">
+ <string>Equity Name:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblType</cstring>
+ </property>
+ <property name="text">
+ <string>Investment Type:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>edtMarketSymbol</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Trading Symbol of the stock or mutual fund, not required.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Trading Symbol of the stock or mutual fund, not required.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="1">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>1 /</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>edtFraction</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblSymbol</cstring>
+ </property>
+ <property name="text">
+ <string>Market Symbol:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Smallest fraction:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Stock</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mutual Fund</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Bond</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>cmbInvestmentType</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>edtEquityName</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Name of the company, or mutual fund.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Name of the company, or mutual fund.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>81</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnOK</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyEdit</class>
+ <header location="local">../widgets/kmymoneyedit.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>1</hordata>
+ <verdata>1</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="256">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c749444154789cad55db1184200c4c180bb005eab1cd6b8112b40d4bf1bee2486ef3006fbf1c93ece605f07eece4e1a4ed42ff2b35f6e2961132e46309941952ed8f628a761a21f56217cb20b04a45fe276d97f8ffb422431ad96e62a4ee057a83131bcc38431a6d057f8eb5cb36438afcb5cded719614011e9088308374c61aa9adb0e0651b5552b4b29efaacb099312ad5da5b2d50a93124463b2adf516fbb8cbd1354a9b1b667c8a787674144f9f982bcb93635ba8cb3fd1b2616f251013403fee763fabce8bff0aa6c989d7e67440000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>edtEquityName</tabstop>
+ <tabstop>edtMarketSymbol</tabstop>
+ <tabstop>cmbInvestmentType</tabstop>
+ <tabstop>btnOK</tabstop>
+ <tabstop>btnCancel</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/knewequityentrydlg.cpp b/kmymoney2/dialogs/knewequityentrydlg.cpp
new file mode 100644
index 0000000..86a1ab8
--- /dev/null
+++ b/kmymoney2/dialogs/knewequityentrydlg.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ knewequityentrydlg.cpp - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "knewequityentrydlg.h"
+#include "../widgets/kmymoneyedit.h"
+#include "../mymoney/mymoneymoney.h"
+
+KNewEquityEntryDlg::KNewEquityEntryDlg(QWidget *parent, const char *name)
+ : kNewEquityEntryDecl(parent, name, TRUE)
+{
+ edtFraction->setCalculatorButtonVisible(false);
+ edtFraction->setPrecision(0);
+ edtFraction->loadText("100");
+
+ connect(btnOK, SIGNAL(clicked()), this, SLOT(onOKClicked()));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+ connect(edtFraction, SIGNAL(textChanged(const QString&)), this, SLOT(slotDataChanged()));
+ connect(edtMarketSymbol, SIGNAL(textChanged(const QString&)), this, SLOT(slotDataChanged()));
+ connect(edtEquityName, SIGNAL(textChanged(const QString&)), this, SLOT(slotDataChanged()));
+
+ // add icons to buttons
+ btnOK->setGuiItem(KStdGuiItem::ok());
+ btnCancel->setGuiItem(KStdGuiItem::cancel());
+
+ slotDataChanged();
+
+ edtEquityName->setFocus();
+}
+
+KNewEquityEntryDlg::~KNewEquityEntryDlg()
+{
+}
+
+/** No descriptions */
+void KNewEquityEntryDlg::onOKClicked()
+{
+ m_strSymbolName = edtMarketSymbol->text();
+ m_strName = edtEquityName->text();
+ m_fraction = edtFraction->value().abs();
+ accept();
+}
+
+void KNewEquityEntryDlg::setSymbolName(const QString& str)
+{
+ m_strSymbolName = str;
+ edtMarketSymbol->setText(m_strSymbolName);
+}
+
+void KNewEquityEntryDlg::setName(const QString& str)
+{
+ m_strName = str;
+ edtEquityName->setText(m_strName);
+}
+
+void KNewEquityEntryDlg::slotDataChanged(void)
+{
+ bool okEnabled = true;
+
+ if(!edtFraction->value().isPositive()
+ || edtMarketSymbol->text().isEmpty()
+ || edtEquityName->text().isEmpty())
+ okEnabled = false;
+
+ btnOK->setEnabled(okEnabled);
+}
+
+#include "knewequityentrydlg.moc"
diff --git a/kmymoney2/dialogs/knewequityentrydlg.h b/kmymoney2/dialogs/knewequityentrydlg.h
new file mode 100644
index 0000000..25605c6
--- /dev/null
+++ b/kmymoney2/dialogs/knewequityentrydlg.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ knewequityentrydlg.h - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWEQUITYENTRY_H
+#define KNEWEQUITYENTRY_H
+
+#include <qdialog.h>
+#include <klocale.h>
+
+#include "../dialogs/knewequityentrydecl.h"
+
+/**
+ *
+ * Dialog to allow user to enter all data for a stock or mutual fund investment type.
+ *
+ * @author Kevin Tambascio
+ *
+ */
+
+class KNewEquityEntryDlg : public kNewEquityEntryDecl
+{
+ Q_OBJECT
+public:
+ KNewEquityEntryDlg(QWidget *parent = NULL, const char *name = NULL);
+ virtual ~KNewEquityEntryDlg();
+
+ void setSymbolName(const QString& str);
+ QString symbolName(void) const { return m_strSymbolName; }
+
+ void setName(const QString& str);
+ QString name(void) const { return m_strName; }
+
+ int fraction(void) const { return m_fraction; }
+
+protected slots:
+ void onOKClicked(void);
+ void slotDataChanged(void);
+
+private:
+ QString m_strSymbolName;
+ QString m_strName;
+ int m_fraction;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/knewfiledlg.cpp b/kmymoney2/dialogs/knewfiledlg.cpp
new file mode 100644
index 0000000..2ea043f
--- /dev/null
+++ b/kmymoney2/dialogs/knewfiledlg.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+ knewfiledlg.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kstdguiitem.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+
+#if KDE_IS_VERSION(3,1,90)
+#include <kabc/addressee.h>
+#include <kabc/stdaddressbook.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "knewfiledlg.h"
+
+KNewFileDlg::KNewFileDlg(QWidget *parent, const char *name, const QString& title)
+ : KNewFileDlgDecl(parent,name,true)
+{
+ init(title);
+}
+
+KNewFileDlg::KNewFileDlg(QString userName, QString userStreet,
+ QString userTown, QString userCounty, QString userPostcode, QString userTelephone,
+ QString userEmail, QWidget *parent, const char *name, const QString& title)
+ : KNewFileDlgDecl(parent,name,true)
+{
+ userNameEdit->setText(userName);
+ streetEdit->setText(userStreet);
+ townEdit->setText(userTown);
+ countyEdit->setText(userCounty);
+ postcodeEdit->setText(userPostcode);
+ telephoneEdit->setText(userTelephone);
+ emailEdit->setText(userEmail);
+
+ init(title);
+}
+
+void KNewFileDlg::init(const QString& title)
+{
+ bool showLoadButton = false;
+ okBtn->setGuiItem(KStdGuiItem::ok());
+ cancelBtn->setGuiItem(KStdGuiItem::cancel());
+
+ if (!title.isEmpty())
+ setCaption(title);
+
+#if KDE_IS_VERSION( 3, 1, 90 )
+ KABC::StdAddressBook *ab = static_cast<KABC::StdAddressBook*>
+ ( KABC::StdAddressBook::self() );
+ if ( ab && !ab->whoAmI().isEmpty() )
+ showLoadButton = true;
+#endif
+
+ if(!showLoadButton)
+ kabcBtn->hide();
+
+ userNameEdit->setFocus();
+
+ connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(okBtn, SIGNAL(clicked()), this, SLOT(okClicked()));
+ connect(kabcBtn, SIGNAL(clicked()), this, SLOT(loadFromKABC()));
+}
+
+KNewFileDlg::~KNewFileDlg(){
+}
+
+void KNewFileDlg::okClicked()
+{
+ userNameText = userNameEdit->text();
+ userStreetText = streetEdit->text();
+ userTownText = townEdit->text();
+ userCountyText = countyEdit->text();
+ userPostcodeText = postcodeEdit->text();
+ userTelephoneText = telephoneEdit->text();
+ userEmailText = emailEdit->text();
+
+ accept();
+}
+
+void KNewFileDlg::loadFromKABC(void)
+{
+#if KDE_IS_VERSION( 3, 1, 90 )
+ KABC::StdAddressBook *ab = static_cast<KABC::StdAddressBook*>
+ ( KABC::StdAddressBook::self() );
+ if ( !ab )
+ return;
+
+ KABC::Addressee addr = ab->whoAmI();
+ if ( addr.isEmpty() ) {
+ KMessageBox::sorry(this, i18n("Unable to load data, because no contact has been associated with the owner of the standard addressbook."), i18n("Addressbook import"));
+ return;
+ }
+
+ userNameEdit->setText( addr.formattedName() );
+ emailEdit->setText( addr.preferredEmail() );
+
+ KABC::PhoneNumber phone = addr.phoneNumber( KABC::PhoneNumber::Home );
+ telephoneEdit->setText( phone.number() );
+
+ KABC::Address a = addr.address( KABC::Address::Home );
+ countyEdit->setText( a.country() + " / " + a.region() );
+ postcodeEdit->setText( a.postalCode() );
+ townEdit->setText( a.locality() );
+ streetEdit->setText( a.street() );
+#endif
+}
+
+#include "knewfiledlg.moc"
diff --git a/kmymoney2/dialogs/knewfiledlg.h b/kmymoney2/dialogs/knewfiledlg.h
new file mode 100644
index 0000000..706a139
--- /dev/null
+++ b/kmymoney2/dialogs/knewfiledlg.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ knewfiledlg.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWFILEDLG_H
+#define KNEWFILEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qdialog.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../dialogs/knewfiledlgdecl.h"
+
+// This dialog lets the user create/edit a file.
+// Use the second constructor to edit a file.
+class KNewFileDlg : public KNewFileDlgDecl {
+ Q_OBJECT
+public:
+ KNewFileDlg(QWidget *parent=0, const char *name=0, const QString& title=QString());
+ KNewFileDlg(QString userName, QString userStreet,
+ QString userTown, QString userCounty, QString userPostcode, QString userTelephone,
+ QString userEmail, QWidget *parent=0, const char *name=0, const QString& title=QString());
+ ~KNewFileDlg();
+
+ KPushButton* cancelButton(void) { return cancelBtn; };
+
+public:
+ QString userNameText;
+ QString userStreetText;
+ QString userTownText;
+ QString userCountyText;
+ QString userPostcodeText;
+ QString userTelephoneText;
+ QString userEmailText;
+
+protected:
+ /// helper method for constructors
+ void init(const QString& title);
+
+protected slots:
+ void okClicked();
+ void loadFromKABC(void);
+};
+
+#endif
diff --git a/kmymoney2/dialogs/knewfiledlgdecl.ui b/kmymoney2/dialogs/knewfiledlgdecl.ui
new file mode 100644
index 0000000..9097a74
--- /dev/null
+++ b/kmymoney2/dialogs/knewfiledlgdecl.ui
@@ -0,0 +1,328 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KNewFileDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kNewFileDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>546</width>
+ <height>448</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New File Dialog</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Use this dialog to enter personal information about yourself.
+
+All information is optional and is provided to personalize
+your KMyMoney file.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>County/State:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>userNameEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>countyEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>townEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Street:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>streetEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Email:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Your name:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Telephone:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Town:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="6" column="1">
+ <property name="name">
+ <cstring>emailEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Postal Code:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="5" column="1">
+ <property name="name">
+ <cstring>telephoneEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>postcodeEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout22</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kabcBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Load from Addressbook</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>305</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>360</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>userNameEdit</tabstop>
+ <tabstop>streetEdit</tabstop>
+ <tabstop>townEdit</tabstop>
+ <tabstop>countyEdit</tabstop>
+ <tabstop>postcodeEdit</tabstop>
+ <tabstop>telephoneEdit</tabstop>
+ <tabstop>emailEdit</tabstop>
+ <tabstop>kabcBtn</tabstop>
+ <tabstop>okBtn</tabstop>
+ <tabstop>cancelBtn</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/knewinvestmentwizard.cpp b/kmymoney2/dialogs/knewinvestmentwizard.cpp
new file mode 100644
index 0000000..d0c9046
--- /dev/null
+++ b/kmymoney2/dialogs/knewinvestmentwizard.cpp
@@ -0,0 +1,314 @@
+/***************************************************************************
+ knewinvestmentwizard - description
+ -------------------
+ begin : Sat Dec 4 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : kmymoney2-developer@lists.sourceforge.net
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <kcombobox.h>
+#include <kurlrequester.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "knewinvestmentwizard.h"
+
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneycombo.h>
+#include "../widgets/kmymoneycurrencyselector.h"
+#include "../converter/webpricequote.h"
+#include "../kmymoneyutils.h"
+
+KNewInvestmentWizard::KNewInvestmentWizard( QWidget *parent, const char *name ) :
+ KNewInvestmentWizardDecl( parent, name )
+{
+ init1();
+ slotCheckPage(QString());
+
+ m_investmentSymbol->setFocus();
+ connect(m_investmentSymbol, SIGNAL(lineChanged(const QString&)), this, SLOT(slotCheckForExistingSymbol(const QString&)));
+}
+
+KNewInvestmentWizard::KNewInvestmentWizard( const MyMoneyAccount& acc, QWidget *parent, const char *name ) :
+ KNewInvestmentWizardDecl( parent, name ),
+ m_account(acc)
+{
+ setCaption(i18n("Investment detail wizard"));
+ init1();
+
+ // load the widgets with the data
+ setName(m_account.name());
+ m_security = MyMoneyFile::instance()->security(m_account.currencyId());
+
+ init2();
+
+ int priceMode = 0;
+ if(!m_account.value("priceMode").isEmpty())
+ priceMode = m_account.value("priceMode").toInt();
+ m_priceMode->setCurrentItem(priceMode);
+
+}
+
+KNewInvestmentWizard::KNewInvestmentWizard( const MyMoneySecurity& security, QWidget *parent, const char *name ) :
+ KNewInvestmentWizardDecl( parent, name ),
+ m_security(security)
+{
+ setCaption(i18n("Security detail wizard"));
+ init1();
+ m_createAccount = false;
+
+ // load the widgets with the data
+ setName(security.name());
+
+ init2();
+
+ // no chance to change the price mode here
+ m_priceMode->setCurrentItem(0);
+ m_priceMode->setEnabled(false);
+}
+
+void KNewInvestmentWizard::init1(void)
+{
+ m_onlineSourceCombo->insertStringList( WebPriceQuote::quoteSources() );
+
+ m_onlineFactor->setValue(MyMoneyMoney(1,1));
+ m_onlineFactor->setPrecision(4);
+
+ m_fraction->setPrecision(0);
+ m_fraction->setValue(MyMoneyMoney(100, 1));
+ kMyMoneyMoneyValidator* fractionValidator = new kMyMoneyMoneyValidator(1, 100000, 0, this);
+ m_fraction->setValidator(fractionValidator);
+
+ // load the price mode combo
+ m_priceMode->insertItem(i18n("default price mode", "<default>"), 0);
+ m_priceMode->insertItem(i18n("Price per share"), 1);
+ m_priceMode->insertItem(i18n("Total for all shares"), 2);
+
+ // load the widget with the available currencies
+ m_tradingCurrencyEdit->update(QString());
+
+ connect(helpButton(),SIGNAL(clicked()), this, SLOT(slotHelp(void)));
+ connect(m_investmentName, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPage(void)));
+ connect(m_investmentSymbol, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPage(void)));
+ connect(m_fraction, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPage(void)));
+ connect(m_investmentIdentification, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPage(void)));
+ connect(m_onlineFactor, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPage(void)));
+ connect(m_onlineSourceCombo, SIGNAL(activated(const QString&)), this, SLOT(slotCheckPage(const QString&)));
+ connect(m_useFinanceQuote, SIGNAL(toggled(bool)), this, SLOT(slotSourceChanged(bool)));
+
+ m_createAccount = true;
+
+ // Update label in case of edit
+ if(!m_account.id().isEmpty()) {
+ m_introLabel->setText(i18n("This wizard allows you to modify the selected investment."));
+ }
+ if(!m_security.id().isEmpty()) {
+ m_introLabel->setText(i18n("This wizard allows you to modify the selected security."));
+ }
+
+
+}
+
+void KNewInvestmentWizard::init2(void)
+{
+ MyMoneySecurity tradingCurrency = MyMoneyFile::instance()->currency(m_security.tradingCurrency());
+ m_investmentSymbol->setText(m_security.tradingSymbol());
+ m_tradingMarket->setCurrentText(m_security.tradingMarket());
+ m_fraction->setValue(MyMoneyMoney(m_security.smallestAccountFraction(), 1));
+ m_tradingCurrencyEdit->setSecurity(tradingCurrency);
+ if (m_security.value("kmm-online-quote-system") == "Finance::Quote") {
+ FinanceQuoteProcess p;
+ m_useFinanceQuote->setChecked(true);
+ m_onlineSourceCombo->setCurrentText(p.niceName(m_security.value("kmm-online-source")));
+ } else {
+ m_onlineSourceCombo->setCurrentText(m_security.value("kmm-online-source"));
+ }
+ if(!m_security.value("kmm-online-factor").isEmpty())
+ m_onlineFactor->setValue(MyMoneyMoney(m_security.value("kmm-online-factor")));
+ m_investmentIdentification->setText(m_security.value("kmm-security-id"));
+ m_securityType->setCurrentText(KMyMoneyUtils::securityTypeToString(m_security.securityType()));
+
+ slotCheckPage(m_security.value("kmm-online-source"));
+}
+
+KNewInvestmentWizard::~KNewInvestmentWizard()
+{
+}
+
+void KNewInvestmentWizard::setName(const QString& name)
+{
+ m_investmentName->setText(name);
+}
+
+void KNewInvestmentWizard::next(void)
+{
+ KNewInvestmentWizardDecl::next();
+ slotCheckPage();
+}
+
+void KNewInvestmentWizard::slotCheckForExistingSymbol(const QString& symbol)
+{
+ if(m_investmentName->text().isEmpty()) {
+ QValueList<MyMoneySecurity> list = MyMoneyFile::instance()->securityList();
+ QValueList<MyMoneySecurity>::const_iterator it_s;
+ MyMoneySecurity::eSECURITYTYPE type = KMyMoneyUtils::stringToSecurity(m_securityType->currentText());
+
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if((*it_s).securityType() == type
+ && (*it_s).tradingSymbol() == m_investmentSymbol->text()) {
+ m_security = MyMoneySecurity();
+ if(KMessageBox::questionYesNo(this, i18n("The selected symbol is already on file. Do you want to reuse the existing security?"), i18n("Security found")) == KMessageBox::Yes) {
+ m_security = *it_s;
+ init2();
+ m_investmentName->loadText(m_security.name());
+ }
+ break;
+ }
+ }
+ }
+}
+
+void KNewInvestmentWizard::slotSourceChanged(bool useFQ)
+{
+ m_onlineSourceCombo->clear();
+ m_onlineSourceCombo->insertItem(QString(), 0);
+ if (useFQ) {
+ m_onlineSourceCombo->insertStringList( WebPriceQuote::quoteSources( WebPriceQuote::FinanceQuote ) );
+ } else {
+ m_onlineSourceCombo->insertStringList( WebPriceQuote::quoteSources() );
+ }
+}
+
+void KNewInvestmentWizard::slotCheckPage(const QString& txt)
+{
+ m_onlineFactor->setEnabled(!txt.isEmpty());
+}
+
+void KNewInvestmentWizard::slotCheckPage(void)
+{
+ if(currentPage() == m_investmentDetailsPage) {
+ setNextEnabled(m_investmentDetailsPage, false);
+ if(m_investmentName->text().length() > 0
+ && m_investmentSymbol->text().length() > 0
+ && !m_fraction->value().isZero()
+ ) {
+ setNextEnabled(m_investmentDetailsPage, true);
+ }
+ } else if(currentPage() == m_onlineUpdatePage) {
+ setFinishEnabled(m_onlineUpdatePage, true);
+ if(m_onlineFactor->isEnabled() && m_onlineFactor->value().isZero())
+ setFinishEnabled(m_onlineUpdatePage, false);
+ }
+}
+
+void KNewInvestmentWizard::slotHelp(void)
+{
+ kapp->invokeHelp("details.investments.newinvestmentwizard");
+}
+
+void KNewInvestmentWizard::createObjects(const QString& parentId)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneySecurity> list = MyMoneyFile::instance()->securityList();
+ QValueList<MyMoneySecurity>::ConstIterator it;
+
+ MyMoneySecurity::eSECURITYTYPE type = KMyMoneyUtils::stringToSecurity(m_securityType->currentText());
+ MyMoneyFileTransaction ft;
+ try {
+ // update all relevant attributes only, if we create a stock
+ // account and the security is unknown or we modifiy the security
+ MyMoneySecurity newSecurity(m_security);
+ newSecurity.setName(m_investmentName->text());
+ newSecurity.setTradingSymbol(m_investmentSymbol->text());
+ newSecurity.setTradingMarket(m_tradingMarket->currentText());
+ newSecurity.setSmallestAccountFraction(m_fraction->value());
+ newSecurity.setTradingCurrency(m_tradingCurrencyEdit->security().id());
+ newSecurity.setSecurityType(type);
+ newSecurity.deletePair("kmm-online-source");
+ newSecurity.deletePair("kmm-online-quote-system");
+ newSecurity.deletePair("kmm-online-factor");
+ newSecurity.deletePair("kmm-security-id");
+
+ if(!m_onlineSourceCombo->currentText().isEmpty()) {
+ if (m_useFinanceQuote->isChecked()) {
+ FinanceQuoteProcess p;
+ newSecurity.setValue("kmm-online-quote-system", "Finance::Quote");
+ newSecurity.setValue("kmm-online-source", p.crypticName(m_onlineSourceCombo->currentText()));
+ }else{
+ newSecurity.setValue("kmm-online-source", m_onlineSourceCombo->currentText());
+ }
+ }
+ if(m_onlineFactor->isEnabled() && (m_onlineFactor->value() != MyMoneyMoney(1,1)))
+ newSecurity.setValue("kmm-online-factor", m_onlineFactor->value().toString());
+ if(!m_investmentIdentification->text().isEmpty())
+ newSecurity.setValue("kmm-security-id", m_investmentIdentification->text());
+
+ if(m_security.id().isEmpty() || newSecurity != m_security) {
+ m_security = newSecurity;
+
+ // add or update it
+ if(m_security.id().isEmpty()) {
+ file->addSecurity(m_security);
+ } else {
+ file->modifySecurity(m_security);
+ }
+ }
+
+ if(m_createAccount) {
+ // now that the security exists, we can add the account to store it
+ m_account.setName(m_investmentName->text());
+ if(m_account.accountType() == MyMoneyAccount::UnknownAccountType)
+ m_account.setAccountType(MyMoneyAccount::Stock);
+
+ m_account.setCurrencyId(m_security.id());
+ switch(m_priceMode->currentItem()) {
+ case 0:
+ m_account.deletePair("priceMode");
+ break;
+ case 1:
+ case 2:
+ m_account.setValue("priceMode", QString("%1").arg(m_priceMode->currentItem()));
+ break;
+ }
+
+ if(m_account.id().isEmpty()) {
+ MyMoneyAccount parent = file->account(parentId);
+ file->addAccount(m_account, parent);
+ } else
+ file->modifyAccount(m_account);
+ }
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to create all objects for the investment"), QString("%1 caugt in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+}
+
+#include "knewinvestmentwizard.moc"
diff --git a/kmymoney2/dialogs/knewinvestmentwizard.h b/kmymoney2/dialogs/knewinvestmentwizard.h
new file mode 100644
index 0000000..7540521
--- /dev/null
+++ b/kmymoney2/dialogs/knewinvestmentwizard.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ knewinvestmentwizard - description
+ -------------------
+ begin : Sat Dec 4 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWINVESTMENTWIZARD_H
+#define KNEWINVESTMENTWIZARD_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/knewinvestmentwizarddecl.h"
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneysecurity.h>
+
+/**
+ * This class contains the implementation of the new investment wizard.
+ *
+ * @author Thomas Baumgart
+ */
+class KNewInvestmentWizard : public KNewInvestmentWizardDecl
+{
+ Q_OBJECT
+public:
+ /**
+ * Use this constructor for the creation of a new investment
+ */
+ KNewInvestmentWizard( QWidget *parent = 0, const char *name = 0 );
+
+ /**
+ * Use this constructor for the modification of an existing investment
+ */
+ KNewInvestmentWizard( const MyMoneyAccount& acc, QWidget *parent = 0, const char *name = 0 );
+
+ /**
+ * Use this constructor for the modification of an existing security
+ */
+ KNewInvestmentWizard( const MyMoneySecurity& sec, QWidget *parent = 0, const char *name = 0 );
+
+ ~KNewInvestmentWizard();
+
+ /**
+ * This method sets the name in the name widget.
+ */
+ void setName(const QString& name);
+
+ /**
+ * Depending on the constructor used, this method either
+ * creates all necessary objects for the investment or updates
+ * them.
+ *
+ * @param parentId id of parent account for the investment
+ */
+ void createObjects(const QString& parentId);
+
+ const MyMoneyAccount& account(void) const { return m_account; }
+
+protected slots:
+ void next(void);
+ void slotCheckPage(void);
+ void slotCheckPage(const QString&);
+ void slotCheckForExistingSymbol(const QString&);
+ void slotSourceChanged(bool);
+ void slotHelp(void);
+
+private:
+ void init1(void);
+ void init2(void);
+
+private:
+ MyMoneyAccount m_account;
+ MyMoneySecurity m_security;
+ bool m_createAccount;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/knewinvestmentwizarddecl.ui b/kmymoney2/dialogs/knewinvestmentwizarddecl.ui
new file mode 100644
index 0000000..a6e9241
--- /dev/null
+++ b/kmymoney2/dialogs/knewinvestmentwizarddecl.ui
@@ -0,0 +1,591 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KNewInvestmentWizardDecl</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>KNewInvestmentWizardDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>584</width>
+ <height>385</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Investment wizard</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_investmentTypePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Investment Type</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_introLabel</cstring>
+ </property>
+ <property name="text">
+ <string>This wizard allows you to create a new investment.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>The first step in this process requires to select the type of investment. The following steps collect more details about the investment from you.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Type of investment</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>Stock</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mutual Fund</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Bond</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_securityType</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_investmentDetailsPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Investment details</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Enter the details below and click &lt;b&gt;Next&lt;/b&gt; to continue entering the online update details.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_investmentName</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="1">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>1 /</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_fraction</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>textLabel2_5</cstring>
+ </property>
+ <property name="text">
+ <string>Price entry</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Fraction</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Trading Currency</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Full name</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo" row="6" column="1">
+ <property name="name">
+ <cstring>m_priceMode</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>AMEX</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>EUREX</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>FUND</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>NASDAQ</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>NYSE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>XETRA</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_tradingMarket</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Trading symbol</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Identification</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneySecuritySelector" row="5" column="1">
+ <property name="name">
+ <cstring>m_tradingCurrencyEdit</cstring>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_investmentSymbol</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the ticker symbol (e.g. RHAT).</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_investmentIdentification</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the CUSIP/ISIN/WKN identification number here</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Trading market</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_onlineUpdatePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Online Update</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Select an online source and click &lt;b&gt;Finish&lt;/b&gt; to store the investment data. If you don't want to use online updates, just leave the data as is.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout25</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>Use Finance::Quote</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_useFinanceQuote</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Online Source</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string></string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_onlineSourceCombo</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>180</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout22</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_6</cstring>
+ </property>
+ <property name="text">
+ <string>Factor</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_onlineFactor</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer29</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>371</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer30</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>181</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyLineEdit</class>
+ <header location="local">../widgets/kmymoneylineedit.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1110">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000041d49444154388d8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d09a6c508138cb8c13d647141163de49043bca9f1628eb9294810f24f88c15b728b07617358888785d980427290b4a8d00b19a8821da8228cf42316ac87eed9247ac95c9aeaeef9eaabdffb5ebf85f178ccfcf7f5b79fec07a7280a08a008f25ceb7c29e5da573716e65a0be3f198ef6f5ededff9b9e1b34faf90882092a1ea21428b9220ffbf46054055b19386ba6970ae6665b5e0d2c5eb0b066067bbe1f21757c88f5504eff0c192189081303a5582b16854fccce2fe041f00cdd0a8103b874556405476b62d972ec2c2b90ff3fd8df5cb946549d80b34aea15ccaa94625450e2d0e558b460b7371a734b5e027251a155545678ab62d7eea90b4c504078908c107acb354cb251b1f8f08b1c18631aabbb4d18211404804f22545863561d2f060fb34aa8a18d0086204e72c46a32292e1a796f278c1da7a859d8da9a737506db04d0a24103d8949480b214d3bbee952a05c1d536f9d2684160c744f048311543d459eb1b65ee1754cedae13a64abd5d6127053c9d0281f22d4f75c6a2118a5c09272d7ab740638bf4ef2dd2174032d0d8d04c6fe19c32bedd8bc65e342aa3f785e2784bfd6bc1bd9db24b05505616a4edd67d5a8c1801a03a9962754c504bf34b8986acfb9be91cac7d54315a15541b36b134f74bd2dc53940115a5381e087bc25c6f71be831a8baa234cc1ee3eeb74ed83116beb2b8849d108a3730e8ce27e2bfb82419a7b407ac7c222fd0e6280a8078ce64e47ef54ac9d5be9aaae0162e0de568a44a18d3df90845d919c4f01463406340a44f40efb43a99b371618488e2670d1a2d7ee6f1d3be39342104e937ed85fb86599c33e9ee0be9a004946259d8b858909880d59aa00daa0d3280b5f39e34074c4b3a5434029a76a9e9f5cc0163b5c80024158a1cfc4cb1d3061d5834066cb0a403c008599a70f6bc27b8d03106ea3ae91987278c5b143b015547224ab5e24185cd9b81665273e7b6e7cecd82ddbf8098002de94049737bc09828cf3036f31c3735c8b0e98eb704672f348c7f7c93cd1fb2ae905119ff54e0dff3542b0e9dd983dcea2cc5eea6cf303e74ec687af5c41b6fa38f5e203c7ec8e1238ef85831a214afef21060ea781ec68247b65c6916353cc8b73d1ae79354606af2a930709aa118da1636c274dd7e3774b884a79aa6b5711a538d33cf9c01c1c9b83bc6a1f55c91ccb23b05b1deb43a7decdaffefd2862f61366aa8449c69e33642f012f2bb208fa98eeda1f3346f076c8eeef19475e9be115423364f78f84105a8643d34d90cfbfdcd8cf872589a45dc7f54cf3134a36f4e495c23f9da8db15bccb708d4014f2ca512cb5d4f7c13e84300d5cff6eb39b202bab053bdb9674f0648609427d0f8402ddeac30f4fcd3ced3efc3b422d406c09b340bedc1571e1bfc3d44dc281634c5fe5e758e7395cfbe6d6c130fd17d92372d277c159b70000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>m_securityType</tabstop>
+ <tabstop>m_investmentSymbol</tabstop>
+ <tabstop>m_investmentName</tabstop>
+ <tabstop>m_fraction</tabstop>
+ <tabstop>m_tradingMarket</tabstop>
+ <tabstop>m_investmentIdentification</tabstop>
+ <tabstop>m_tradingCurrencyEdit</tabstop>
+ <tabstop>m_priceMode</tabstop>
+ <tabstop>m_useFinanceQuote</tabstop>
+ <tabstop>m_onlineSourceCombo</tabstop>
+ <tabstop>m_onlineFactor</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/knewloanwizard.cpp b/kmymoney2/dialogs/knewloanwizard.cpp
new file mode 100644
index 0000000..28c48ef
--- /dev/null
+++ b/kmymoney2/dialogs/knewloanwizard.cpp
@@ -0,0 +1,1088 @@
+/***************************************************************************
+ knewloanwizard.cpp - description
+ -------------------
+ begin : Wed Oct 8 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <math.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <knuminput.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "knewloanwizard.h"
+
+#include "../kmymoneyutils.h"
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include "../widgets/kmymoneycombo.h"
+
+#include "../dialogs/knewaccountdlg.h"
+#include "../dialogs/ksplittransactiondlg.h"
+
+#include "../mymoney/mymoneyfinancialcalculator.h"
+#include "../mymoney/mymoneyfile.h"
+
+#include "../kmymoney2.h"
+
+KNewLoanWizard::KNewLoanWizard(QWidget *parent, const char *name ) :
+ KNewLoanWizardDecl(parent, name, true)
+{
+ connect(m_borrowButton, SIGNAL(clicked()), this, SLOT(slotLiabilityLoan()));
+ connect(m_lendButton, SIGNAL(clicked()), this, SLOT(slotAssetLoan()));
+
+ connect(m_nameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished()));
+ // connect(m_payeeEdit, SIGNAL(newPayee(const QString&)), this, SLOT(slotNewPayee(const QString&)));
+ connect(m_payeeEdit, SIGNAL(createItem(const QString&, QString&)), this, SIGNAL(createPayee(const QString&, QString&)));
+
+ connect(m_previousPaymentButton, SIGNAL(clicked()), this, SLOT(slotPaymentsMade()));
+ connect(m_noPreviousPaymentButton, SIGNAL(clicked()), this, SLOT(slotNoPaymentsMade()));
+
+ connect(m_allPaymentsButton, SIGNAL(clicked()), this, SLOT(slotRecordAllPayments()));
+ connect(m_thisYearPaymentButton, SIGNAL(clicked()), this, SLOT(slotRecordThisYearsPayments()));
+
+ connect(m_firstDueDateEdit, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotCheckPageFinished()));
+
+ connect(m_interestOnPaymentButton, SIGNAL(clicked()), this, SLOT(slotInterestOnPayment()));
+ connect(m_interestOnReceptionButton, SIGNAL(clicked()), this, SLOT(slotInterestOnReception()));
+
+ connect(m_loanAmountEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckPageFinished()));
+
+ connect(m_interestAccountEdit, SIGNAL(stateChanged()), this, SLOT(slotCheckPageFinished()));
+
+ connect(m_nextDueDateEdit, SIGNAL(dateChanged(const QDate&)), this, SLOT(slotCheckPageFinished()));
+ connect(m_paymentAccountEdit, SIGNAL(stateChanged()), this, SLOT(slotCheckPageFinished()));
+
+ connect(m_assetAccountEdit, SIGNAL(stateChanged()), this, SLOT(slotCheckPageFinished()));
+ connect(m_dontCreatePayoutCheckBox, SIGNAL(clicked()), this, SLOT(slotCheckPageFinished()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadEditWidgets()));
+
+ loadComboBoxes();
+
+ resetCalculator();
+
+ slotReloadEditWidgets();
+
+ // As default we assume a liability loan, with fixed interest rate,
+ // with a first payment due on the 30th of this month. All payments
+ // should be recorded and none have been made so far.
+ m_dontCreatePayoutCheckBox->setChecked(false);
+ m_borrowButton->animateClick();
+ m_fixedInterestButton->animateClick();
+ m_noPreviousPaymentButton->animateClick();
+ m_allPaymentsButton->animateClick();
+ m_interestOnReceptionButton->animateClick();
+
+ m_interestFrequencyAmountEdit->setValue(1);
+ m_interestFrequencyUnitEdit->setCurrentItem(static_cast<int>(MyMoneyAccountLoan::changeYearly));
+ m_paymentFrequencyUnitEdit->setCurrentItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_MONTHLY)));
+ m_firstDueDateEdit->loadDate(QDate(QDate::currentDate().year(),QDate::currentDate().month(),30));
+
+ m_paymentAccountEdit->removeButtons();
+ m_assetAccountEdit->removeButtons();
+ m_interestAccountEdit->removeButtons();
+
+ // load button icons
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem createCategoryButtenItem( i18n( "&Create..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new category"),
+ i18n("Use this to open the new account editor"));
+ m_createCategoryButton->setGuiItem(createCategoryButtenItem);
+ connect(m_createCategoryButton, SIGNAL(clicked()), this, SLOT(slotCreateCategory()));
+
+ KGuiItem additionalFeeButtenItem( i18n( "&Additional fees..." ),
+ 0, //QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Enter additional fees"),
+ i18n("Use this to add any additional fees other than principal and interest contained in your periodical payments."));
+ m_additionalFeeButton->setGuiItem(additionalFeeButtenItem);
+ connect(m_additionalFeeButton, SIGNAL(clicked()), this, SLOT(slotAdditionalFees()));
+
+ KGuiItem createAssetButtenItem( i18n( "&Create..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new asset account"),
+ i18n("Use this to create a new account to which the initial payment should be made"));
+ m_createNewAssetButton->setGuiItem(createAssetButtenItem);
+ connect(m_createNewAssetButton, SIGNAL(clicked()), kmymoney2, SLOT(slotAccountNew()));
+
+ // enable the finish button on the last page
+ setFinishEnabled(m_summaryPage, true);
+
+ // FIXME: we currently only support interest calculation on reception
+ setAppropriate(m_interestCalculationPage, false);
+
+ // turn off all pages that are contained here for derived classes
+ setAppropriate(m_editIntroPage, false);
+ setAppropriate(m_editSelectionPage, false);
+ setAppropriate(m_effectiveDatePage, false);
+ setAppropriate(m_paymentEditPage, false);
+ setAppropriate(m_interestEditPage, false);
+ setAppropriate(m_summaryEditPage, false);
+
+ // for now, we don't have online help :-(
+ helpButton()->hide();
+
+ // setup a phony transaction for additional fee processing
+ m_account = MyMoneyAccount("Phony-ID", MyMoneyAccount());
+ m_split.setAccountId(m_account.id());
+ m_split.setValue(0);
+ m_transaction.addSplit(m_split);
+}
+
+KNewLoanWizard::~KNewLoanWizard()
+{
+}
+
+void KNewLoanWizard::resetCalculator(void)
+{
+ m_loanAmount1->setText(QString());
+ m_interestRate1->setText(QString());
+ m_duration1->setText(QString());
+ m_payment1->setText(QString());
+ m_balloon1->setText(QString());
+
+ m_loanAmount2->setText(QString());
+ m_interestRate2->setText(QString());
+ m_duration2->setText(QString());
+ m_payment2->setText(QString());
+ m_balloon2->setText(QString());
+
+ m_loanAmount3->setText(QString());
+ m_interestRate3->setText(QString());
+ m_duration3->setText(QString());
+ m_payment3->setText(QString());
+ m_balloon3->setText(QString());
+
+ m_loanAmount4->setText(QString());
+ m_interestRate4->setText(QString());
+ m_duration4->setText(QString());
+ m_payment4->setText(QString());
+ m_balloon4->setText(QString());
+
+ m_loanAmount5->setText(QString());
+ m_interestRate5->setText(QString());
+ m_duration5->setText(QString());
+ m_payment5->setText(QString());
+ m_balloon5->setText(QString());
+
+ m_additionalCost->setText(MyMoneyMoney(0).formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
+}
+
+void KNewLoanWizard::slotLiabilityLoan(void)
+{
+ m_generalReceiverText->setText(i18n("To whom do you make payments?"));
+ m_receiverLabel->setText(i18n("Payments to"));
+}
+
+void KNewLoanWizard::slotAssetLoan(void)
+{
+ m_generalReceiverText->setText(i18n("From whom do you expect payments?"));
+ m_receiverLabel->setText(i18n("Payments from"));
+}
+
+void KNewLoanWizard::slotPaymentsMade(void)
+{
+ setAppropriate(m_recordPaymentPage, true);
+}
+
+void KNewLoanWizard::slotNoPaymentsMade(void)
+{
+ m_allPaymentsButton->animateClick();
+ setAppropriate(m_recordPaymentPage, false);
+}
+
+void KNewLoanWizard::slotRecordAllPayments(void)
+{
+ m_firstPaymentLabel->setText(
+ QString("\n") +
+ i18n("Please enter the date, the first payment for this loan was/is due."));
+ m_firstPaymentNote->setText(
+ i18n("Note: Consult the loan contract for details of the first due date. "
+ "Keep in mind, that the first due date usually differs from the date "
+ "the contract was signed"));
+ m_balanceLabel->setText(
+ QString("\n") +
+ i18n("Please enter the original loan amount in the field below or leave it "
+ "empty to be calculated."));
+}
+
+void KNewLoanWizard::slotRecordThisYearsPayments(void)
+{
+ m_firstPaymentLabel->setText(
+ QString("\n") +
+ i18n("Please enter the date, the first payment for this loan was/is due this year."));
+ m_firstPaymentNote->setText(
+ i18n("Note: You can easily figure out the date of the first payment "
+ "if you consult the last statement of last year."));
+ m_balanceLabel->setText(
+ QString("\n") +
+ i18n("Please enter the remaining loan amount of last years final "
+ "statement in the field below. You should not leave this field empty."));
+}
+
+void KNewLoanWizard::slotCheckPageFinished(void)
+{
+ nextButton()->setEnabled(false);
+
+ if(currentPage() == m_namePage) {
+ if(!m_nameEdit->text().isEmpty()) {
+ nextButton()->setEnabled(true);
+ }
+
+ } else if(currentPage() == m_loanAmountPage) {
+ nextButton()->setEnabled(true);
+ if(m_thisYearPaymentButton->isChecked()
+ && !m_loanAmountEdit->isValid()) {
+ nextButton()->setEnabled(false);
+ }
+
+ } else if(currentPage() == m_interestCategoryPage) {
+ if(m_interestAccountEdit->selectedItems().count() > 0) {
+ nextButton()->setEnabled(true);
+ }
+
+ } else if(currentPage() == m_firstPaymentPage) {
+ if(m_firstDueDateEdit->date().isValid())
+ nextButton()->setEnabled(true);
+
+ } else if(currentPage() == m_schedulePage) {
+ if(m_nextDueDateEdit->date().isValid()
+ && m_nextDueDateEdit->date() >= m_firstDueDateEdit->date()
+ && m_paymentAccountEdit->selectedItems().count() > 0)
+ nextButton()->setEnabled(true);
+
+ } else if(currentPage() == m_assetAccountPage) {
+ if(m_dontCreatePayoutCheckBox->isChecked()) {
+ m_assetAccountEdit->setEnabled(false);
+ m_paymentDate->setEnabled(false);
+ m_createNewAssetButton->setEnabled(false);
+ nextButton()->setEnabled(true);
+ } else {
+ m_assetAccountEdit->setEnabled(true);
+ m_paymentDate->setEnabled(true);
+ m_createNewAssetButton->setEnabled(true);
+ if(!m_assetAccountEdit->selectedItems().isEmpty()
+ && m_paymentDate->date().isValid())
+ nextButton()->setEnabled(true);
+ }
+ } else
+ nextButton()->setEnabled(true);
+}
+
+void KNewLoanWizard::updateLoanAmount(void)
+{
+ QString txt;
+ if(m_loanAmountEdit->lineedit()->text().isEmpty()) {
+ txt = QString("<") + i18n("calculate") + QString(">");
+ } else {
+ txt = m_loanAmountEdit->value().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId())));
+ }
+ m_loanAmount1->setText(txt);
+ m_loanAmount2->setText(txt);
+ m_loanAmount3->setText(txt);
+ m_loanAmount4->setText(txt);
+ m_loanAmount5->setText(txt);
+}
+
+void KNewLoanWizard::updateInterestRate(void)
+{
+ QString txt;
+ if(m_interestRateEdit->lineedit()->text().isEmpty()) {
+ txt = QString("<") + i18n("calculate") + QString(">");
+ } else {
+ txt = m_interestRateEdit->value().formatMoney("", 3) + QString("%");
+ }
+ m_interestRate1->setText(txt);
+ m_interestRate2->setText(txt);
+ m_interestRate3->setText(txt);
+ m_interestRate4->setText(txt);
+ m_interestRate5->setText(txt);
+}
+
+void KNewLoanWizard::updateDuration(void)
+{
+ QString txt;
+ if(m_durationValueEdit->value() == 0) {
+ txt = QString("<") + i18n("calculate") + QString(">");
+ } else {
+ txt = QString().sprintf("%d ", m_durationValueEdit->value())
+ + m_durationUnitEdit->currentText();
+ }
+ m_duration1->setText(txt);
+ m_duration2->setText(txt);
+ m_duration3->setText(txt);
+ m_duration4->setText(txt);
+ m_duration5->setText(txt);
+}
+
+void KNewLoanWizard::updatePayment(void)
+{
+ QString txt;
+ if(m_paymentEdit->lineedit()->text().isEmpty()) {
+ txt = QString("<") + i18n("calculate") + QString(">");
+ } else {
+ txt = m_paymentEdit->value().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId())));
+ }
+ m_payment1->setText(txt);
+ m_payment2->setText(txt);
+ m_payment3->setText(txt);
+ m_payment4->setText(txt);
+ m_payment5->setText(txt);
+ m_basePayment->setText(txt);
+}
+
+void KNewLoanWizard::updateFinalPayment(void)
+{
+ QString txt;
+ if(m_finalPaymentEdit->lineedit()->text().isEmpty()) {
+ txt = QString("<") + i18n("calculate") + QString(">");
+ } else {
+ txt = m_finalPaymentEdit->value().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId())));
+ }
+ m_balloon1->setText(txt);
+ m_balloon2->setText(txt);
+ m_balloon3->setText(txt);
+ m_balloon4->setText(txt);
+ m_balloon5->setText(txt);
+}
+
+void KNewLoanWizard::updateLoanInfo(void)
+{
+ updateLoanAmount();
+ updateInterestRate();
+ updateDuration();
+ updatePayment();
+ updateFinalPayment();
+ updatePeriodicPayment();
+
+ QString txt;
+
+ int fraction = m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()));
+ m_loanAmount6->setText(m_loanAmountEdit->value().formatMoney(fraction));
+ m_interestRate6->setText(m_interestRateEdit->value().formatMoney("", 3) + QString("%"));
+ txt = QString().sprintf("%d ", m_durationValueEdit->value())
+ + m_durationUnitEdit->currentText();
+ m_duration6->setText(txt);
+ m_payment6->setText(m_paymentEdit->value().formatMoney(fraction));
+ m_balloon6->setText(m_finalPaymentEdit->value().formatMoney(fraction));
+}
+
+void KNewLoanWizard::updatePeriodicPayment(void)
+{
+ MyMoneyMoney base(m_basePayment->text());
+ MyMoneyMoney add(m_additionalCost->text());
+
+ m_periodicPayment->setText((base + add).formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
+}
+
+void KNewLoanWizard::updateSummary(void)
+{
+ // General
+ if(m_borrowButton->isChecked())
+ m_summaryLoanType->setText(i18n("borrowed"));
+ else
+ m_summaryLoanType->setText(i18n("lend"));
+
+ m_summaryFirstPayment->setText(KGlobal::locale()->formatDate(m_firstDueDateEdit->date(), true));
+ if(m_payeeEdit->selectedItem().isEmpty()) {
+ m_summaryPayee->setText(i18n("not assigned"));
+ } else {
+ m_summaryPayee->setText(m_payeeEdit->currentText());
+ }
+
+ // Calculation
+ if(m_interestOnReceptionButton->isChecked())
+ m_summaryInterestDue->setText(i18n("on reception"));
+ else
+ m_summaryInterestDue->setText(i18n("on due date"));
+ m_summaryPaymentFrequency->setText(m_paymentFrequencyUnitEdit->currentText());
+ m_summaryAmount->setText(m_loanAmount6->text());
+ m_summaryInterestRate->setText(m_interestRate6->text());
+ m_summaryTerm->setText(m_duration6->text());
+ m_summaryPeriodicPayment->setText(m_payment6->text());
+ m_summaryBalloonPayment->setText(m_balloon6->text());
+
+ // Payment
+ try {
+ QStringList sel = m_interestAccountEdit->selectedItems();
+ if(sel.count() != 1)
+ throw new MYMONEYEXCEPTION("Need a single selected interest category");
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(sel.first());
+ m_summaryInterestCategory->setText(acc.name());
+ } catch(MyMoneyException *e) {
+ qWarning("Unable to determine interest category for loan account creation");
+ delete e;
+ }
+ m_summaryAdditionalFees->setText(m_additionalCost->text());
+ m_summaryTotalPeriodicPayment->setText(m_periodicPayment->text());
+ m_summaryNextPayment->setText(KGlobal::locale()->formatDate(m_nextDueDateEdit->date(), true));
+
+ try {
+ QStringList sel = m_paymentAccountEdit->selectedItems();
+ if(sel.count() != 1)
+ throw new MYMONEYEXCEPTION("Need a single selected payment account");
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(sel.first());
+ m_summaryPaymentAccount->setText(acc.name());
+ } catch(MyMoneyException *e) {
+ qWarning("Unable to determine payment account for loan account creation");
+ delete e;
+ }
+}
+
+void KNewLoanWizard::next()
+{
+ bool dontLeavePage = false;
+ QString errMsg = i18n(
+ "The loan wizard is unable to calculate two different values for your loan "
+ "at the same time. "
+ "Please enter a value for the %1 on this page or backup to the page where the "
+ " current value to be calculated is defined and fill in a value.");
+
+ if(currentPage() == m_lendBorrowPage) {
+ // load the appropriate categories into the list
+ loadAccountList();
+ m_nameEdit->setFocus();
+
+ } else if(currentPage() == m_interestTypePage) {
+ if(m_fixedInterestButton->isChecked()) {
+ setAppropriate(m_previousPaymentsPage, true);
+ if(m_previousPaymentButton->isChecked())
+ setAppropriate(m_recordPaymentPage, true);
+ else
+ setAppropriate(m_recordPaymentPage, false);
+ setAppropriate(m_variableInterestDatePage, false);
+
+ } else {
+ setAppropriate(m_previousPaymentsPage, false);
+ setAppropriate(m_recordPaymentPage, false);
+ setAppropriate(m_variableInterestDatePage, true);
+ }
+
+ } else if(currentPage() == m_loanAmountPage) {
+ m_interestRateEdit->setFocus();
+ if(m_thisYearPaymentButton->isChecked()
+ && m_loanAmountEdit->lineedit()->text().isEmpty()) {
+ errMsg = i18n("You selected, that payments have already been made towards this loan. "
+ "This requires you to enter the loan amount exactly as found on your "
+ "last statement.");
+ dontLeavePage = true;
+ KMessageBox::error(0, errMsg, i18n("Calculation error"));
+ } else
+ updateLoanAmount();
+
+ } else if(currentPage() == m_interestPage) {
+
+ if(m_loanAmountEdit->lineedit()->text().isEmpty()
+ && m_interestRateEdit->lineedit()->text().isEmpty()) {
+ dontLeavePage = true;
+ KMessageBox::error(0, errMsg.arg(i18n("interest rate")), i18n("Calculation error"));
+ } else
+ updateInterestRate();
+
+ } else if(currentPage() == m_durationPage) {
+ if((m_loanAmountEdit->lineedit()->text().isEmpty()
+ || m_interestRateEdit->lineedit()->text().isEmpty())
+ && m_durationValueEdit->value() == 0) {
+ dontLeavePage = true;
+ KMessageBox::error(0, errMsg.arg(i18n("term")), i18n("Calculation error"));
+ } else
+ updateDuration();
+
+ } else if(currentPage() == m_paymentPage) {
+ if((m_loanAmountEdit->lineedit()->text().isEmpty()
+ || m_interestRateEdit->lineedit()->text().isEmpty()
+ || m_durationValueEdit->value() == 0)
+ && m_paymentEdit->lineedit()->text().isEmpty()) {
+ dontLeavePage = true;
+ KMessageBox::error(0, errMsg.arg(i18n("principal and interest")), i18n("Calculation error"));
+ } else
+ updatePayment();
+
+ } else if(currentPage() == m_finalPaymentPage) {
+ if((m_loanAmountEdit->lineedit()->text().isEmpty()
+ || m_interestRateEdit->lineedit()->text().isEmpty()
+ || m_durationValueEdit->value() == 0
+ || m_paymentEdit->lineedit()->text().isEmpty())
+ && m_finalPaymentEdit->lineedit()->text().isEmpty()) {
+ // if two fields are empty and one of them is the final payment
+ // we assume the final payment to be 0 instead of presenting a
+ m_finalPaymentEdit->setValue(MyMoneyMoney(0, 1));
+ }
+ updateFinalPayment();
+ if(!calculateLoan()) {
+ dontLeavePage = true;
+ } else
+ updateLoanInfo();
+
+ } else if(currentPage() == m_additionalFeesPage) {
+ m_nextDueDateEdit->setEnabled(true);
+ if(m_allPaymentsButton->isChecked() || m_noPreviousPaymentButton->isChecked()) {
+ m_nextDueDateEdit->setDate(m_firstDueDateEdit->date());
+ m_nextDueDateEdit->setEnabled(false);
+ if(m_assetAccountPage)
+ setAppropriate(m_assetAccountPage, true);
+ } else {
+ QDate nextPayment(QDate::currentDate().year(), 1, m_firstDueDateEdit->date().day());
+ m_nextDueDateEdit->setDate(nextPayment);
+ if(m_assetAccountPage)
+ setAppropriate(m_assetAccountPage, false);
+ m_assetAccountEdit->slotDeselectAllAccounts();
+ }
+ if(m_nextDueDateEdit->date() < m_firstDueDateEdit->date()) {
+ m_nextDueDateEdit->setDate(m_firstDueDateEdit->date());
+ }
+
+ } else if(currentPage() == m_schedulePage) {
+ updateSummary();
+ }
+
+/*
+ switch(m_accountType) {
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::Asset:
+ if(indexOf(accountPaymentPage) != -1) {
+ removePage(accountPaymentPage);
+ }
+ setAppropriate(accountNumberPage, false);
+ setFinishEnabled(accountDetailsPage, true);
+ break;
+
+ case MyMoneyAccount::CreditCard:
+ if(indexOf(accountPaymentPage) == -1) {
+ loadPaymentMethods();
+ addPage(accountPaymentPage, m_accountPaymentPageTitle);
+ }
+ setAppropriate(accountPaymentPage, true);
+ setFinishEnabled(accountPaymentPage, true);
+ setFinishEnabled(accountDetailsPage, false);
+ break;
+
+ default:
+ setAppropriate(accountNumberPage, institutionComboBox->currentText() != "");
+ if(indexOf(accountPaymentPage) != -1) {
+ removePage(accountPaymentPage);
+ }
+ setFinishEnabled(accountDetailsPage, true);
+ break;
+ }
+*/
+ if(!dontLeavePage)
+ KNewLoanWizardDecl::next();
+
+ // setup the availability of widgets on the selected page
+ slotCheckPageFinished();
+}
+
+void KNewLoanWizard::loadComboBoxes(void)
+{
+ m_interestFrequencyUnitEdit->insertItem(i18n("Days"), static_cast<int>(MyMoneyAccountLoan::changeDaily));
+ m_interestFrequencyUnitEdit->insertItem(i18n("Weeks"), static_cast<int>(MyMoneyAccountLoan::changeWeekly));
+ m_interestFrequencyUnitEdit->insertItem(i18n("Months"), static_cast<int>(MyMoneyAccountLoan::changeMonthly));
+ m_interestFrequencyUnitEdit->insertItem(i18n("Years"), static_cast<int>(MyMoneyAccountLoan::changeYearly));
+
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_DAILY)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_WEEKLY)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_FORTNIGHTLY)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERWEEK)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURWEEKS)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_MONTHLY)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERMONTH)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_QUARTERLY)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURMONTHS)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_TWICEYEARLY)));
+ m_paymentFrequencyUnitEdit->insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_YEARLY)));
+
+ m_durationUnitEdit->insertItem(i18n("Months"), static_cast<int>(MyMoneySchedule::OCCUR_MONTHLY));
+ m_durationUnitEdit->insertItem(i18n("Years"), static_cast<int>(MyMoneySchedule::OCCUR_YEARLY));
+ m_durationUnitEdit->insertItem(i18n("Payments"), static_cast<int>(MyMoneySchedule::OCCUR_ONCE));
+
+}
+
+void KNewLoanWizard::slotInterestOnPayment(void)
+{
+ m_interestOnPaymentButton->setChecked(true);
+ m_interestOnReceptionButton->setChecked(false);
+}
+
+void KNewLoanWizard::slotInterestOnReception(void)
+{
+ m_interestOnPaymentButton->setChecked(false);
+ m_interestOnReceptionButton->setChecked(true);
+}
+
+int KNewLoanWizard::calculateLoan(void)
+{
+ MyMoneyFinancialCalculator calc;
+ long double val;
+ int PF;
+ QString result;
+
+ // FIXME: for now, we only support interest calculation at the end of the period
+ calc.setBep();
+ // FIXME: for now, we only support periodic compounding
+ calc.setDisc();
+
+ PF = MyMoneySchedule::eventsPerYear(MyMoneySchedule::stringToOccurence(
+ m_paymentFrequencyUnitEdit->currentText()));
+ if(PF == 0)
+ return 0;
+ calc.setPF(PF);
+
+ // FIXME: for now we only support compounding frequency == payment frequency
+ calc.setCF(PF);
+
+
+ if(!m_loanAmountEdit->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_loanAmountEdit->value().abs().toDouble());
+ if(m_borrowButton->isChecked())
+ val = -val;
+ calc.setPv(val);
+ }
+
+ if(!m_interestRateEdit->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_interestRateEdit->value().abs().toDouble());
+ calc.setIr(val);
+ }
+
+ if(!m_paymentEdit->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_paymentEdit->value().abs().toDouble());
+ if(m_lendButton->isChecked())
+ val = -val;
+ calc.setPmt(val);
+ }
+
+ if(!m_finalPaymentEdit->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_finalPaymentEdit->value().abs().toDouble());
+ if(m_lendButton->isChecked())
+ val = -val;
+ calc.setFv(val);
+ }
+
+ if(m_durationValueEdit->value() != 0) {
+ calc.setNpp(static_cast<long double>(term()));
+ }
+
+ int fraction = m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()));
+ // setup of parameters is done, now do the calculation
+ try {
+ if(m_loanAmountEdit->lineedit()->text().isEmpty()) {
+ // calculate the amount of the loan out of the other information
+ val = calc.presentValue();
+ m_loanAmountEdit->loadText(MyMoneyMoney(static_cast<double>(val)).abs().formatMoney(fraction));
+ result = i18n("KMyMoney has calculated the amount of the loan as %1.")
+ .arg(m_loanAmountEdit->lineedit()->text());
+
+ } else if(m_interestRateEdit->lineedit()->text().isEmpty()) {
+ // calculate the interest rate out of the other information
+ val = calc.interestRate();
+ m_interestRateEdit->loadText(MyMoneyMoney(static_cast<double>(val)).abs().formatMoney("", 3));
+ result = i18n("KMyMoney has calculated the interest rate to %1%.")
+ .arg(m_interestRateEdit->lineedit()->text());
+
+ } else if(m_paymentEdit->lineedit()->text().isEmpty()) {
+ // calculate the periodical amount of the payment out of the other information
+ val = calc.payment();
+ m_paymentEdit->setValue(MyMoneyMoney(static_cast<double>(val)).abs());
+ // reset payment as it might have changed due to rounding
+ val = static_cast<long double> (m_paymentEdit->value().abs().toDouble());
+ if(m_lendButton->isChecked())
+ val = -val;
+ calc.setPmt(val);
+
+ result = i18n("KMyMoney has calculated a periodic payment of %1 to cover principal and interest.")
+ .arg(m_paymentEdit->lineedit()->text());
+
+ val = calc.futureValue();
+ if((m_borrowButton->isChecked() && val < 0 && fabsl(val) >= fabsl(calc.payment()))
+ || (m_lendButton->isChecked() && val > 0 && fabs(val) >= fabs(calc.payment()))) {
+ calc.setNpp(calc.npp()-1);
+ updateTermWidgets(calc.npp());
+ val = calc.futureValue();
+ MyMoneyMoney refVal(static_cast<double>(val));
+ m_finalPaymentEdit->loadText(refVal.abs().formatMoney(fraction));
+ result += QString(" ");
+ result += i18n("The number of payments has been decremented and the final payment has been modified to %1.")
+ .arg(m_finalPaymentEdit->lineedit()->text());
+ } else if((m_borrowButton->isChecked() && val < 0 && fabsl(val) < fabsl(calc.payment()))
+ || (m_lendButton->isChecked() && val > 0 && fabs(val) < fabs(calc.payment()))) {
+ m_finalPaymentEdit->loadText(MyMoneyMoney(0,1).formatMoney(fraction));
+ } else {
+ MyMoneyMoney refVal(static_cast<double>(val));
+ m_finalPaymentEdit->loadText(refVal.abs().formatMoney(fraction));
+ result += i18n("The final payment has been modified to %1.")
+ .arg(m_finalPaymentEdit->lineedit()->text());
+ }
+
+ } else if(m_durationValueEdit->value() == 0) {
+ // calculate the number of payments out of the other information
+ val = calc.numPayments();
+ if(val == 0)
+ throw new MYMONEYEXCEPTION("incorrect fincancial calculation");
+
+ // if the number of payments has a fractional part, then we
+ // round it to the smallest integer and calculate the balloon payment
+ result = i18n("KMyMoney has calculated the term of your loan as %1. ")
+ .arg(updateTermWidgets(floorl(val)));
+
+ if(val != floorl(val)) {
+ calc.setNpp(floorl(val));
+ val = calc.futureValue();
+ MyMoneyMoney refVal(static_cast<double>(val));
+ m_finalPaymentEdit->loadText(refVal.abs().formatMoney(fraction));
+ result += i18n("The final payment has been modified to %1.")
+ .arg(m_finalPaymentEdit->lineedit()->text());
+ }
+
+ } else {
+ // calculate the future value of the loan out of the other information
+ val = calc.futureValue();
+
+ // we differentiate between the following cases:
+ // a) the future value is greater than a payment
+ // b) the future value is less than a payment or the loan is overpaid
+ // c) all other cases
+ //
+ // a) means, we have paid more than we owed. This can't be
+ // b) means, we paid more than we owed but the last payment is
+ // less in value than regular payments. That means, that the
+ // future value is to be treated as (fully payed back)
+ // c) the loan is not payed back yet
+ if((m_borrowButton->isChecked() && val < 0 && fabsl(val) > fabsl(calc.payment()))
+ || (m_lendButton->isChecked() && val > 0 && fabs(val) > fabs(calc.payment()))) {
+ // case a)
+ qDebug("Future Value is %Lf", val);
+ throw new MYMONEYEXCEPTION("incorrect fincancial calculation");
+
+ } else if((m_borrowButton->isChecked() && val < 0 && fabsl(val) <= fabsl(calc.payment()))
+ || (m_lendButton->isChecked() && val > 0 && fabs(val) <= fabs(calc.payment()))) {
+ // case b)
+ val = 0;
+ }
+
+ MyMoneyMoney refVal(static_cast<double>(val));
+ result = i18n("KMyMoney has calculated a final payment of %1 for this loan.")
+ .arg(refVal.abs().formatMoney(fraction));
+
+ if(!m_finalPaymentEdit->lineedit()->text().isEmpty()) {
+ if((m_finalPaymentEdit->value().abs() - refVal.abs()).abs().toDouble() > 1) {
+ throw new MYMONEYEXCEPTION("incorrect fincancial calculation");
+ }
+ result = i18n("KMyMoney has successfully verified your loan information.");
+ }
+ m_finalPaymentEdit->loadText(refVal.abs().formatMoney(fraction));
+ }
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ KMessageBox::error(0,
+ i18n("You have entered mis-matching information. Please backup to the "
+ "appropriate page and update your figures or leave one value empty "
+ "to let KMyMoney calculate it for you"),
+ i18n("Calculation error"));
+ return 0;
+ }
+
+ result += i18n("\n\nAccept this or modify the loan information and recalculate.");
+
+ KMessageBox::information(0, result, i18n("Calculation successful"));
+ return 1;
+}
+
+QString KNewLoanWizard::updateTermWidgets(const long double val)
+{
+ long long vl = static_cast<long long>(floorl(val));
+
+ QString valString;
+ MyMoneySchedule::occurenceE unit;
+ unit = MyMoneySchedule::stringToOccurence(m_paymentFrequencyUnitEdit->currentText());
+
+ if((unit == MyMoneySchedule::OCCUR_MONTHLY)
+ && ((vl % 12) == 0)) {
+ vl /= 12;
+ unit = MyMoneySchedule::OCCUR_YEARLY;
+ }
+
+ switch(unit) {
+ case MyMoneySchedule::OCCUR_MONTHLY:
+ valString = i18n("one month", "%n months", vl);
+ m_durationUnitEdit->setCurrentItem(static_cast<int>(MyMoneySchedule::OCCUR_MONTHLY));
+ break;
+ case MyMoneySchedule::OCCUR_YEARLY:
+ valString = i18n("one year", "%n years", vl);
+ m_durationUnitEdit->setCurrentItem(static_cast<int>(MyMoneySchedule::OCCUR_YEARLY));
+ break;
+ default:
+ valString = i18n("one payment", "%n payments", vl);
+ m_durationUnitEdit->setCurrentItem(static_cast<int>(MyMoneySchedule::OCCUR_ONCE));
+ break;
+ }
+ m_durationValueEdit->setValue(vl);
+ return valString;
+}
+
+void KNewLoanWizard::slotCreateCategory(void)
+{
+ MyMoneyAccount acc, base;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if(m_borrowButton->isChecked()) {
+ base = file->expense();
+ acc.setAccountType(MyMoneyAccount::Expense);
+ } else {
+ base = file->income();
+ acc.setAccountType(MyMoneyAccount::Income);
+ }
+ acc.setParentAccountId(base.id());
+
+ KNewAccountDlg* dlg = new KNewAccountDlg(acc, true, true);
+ if(dlg->exec() == QDialog::Accepted) {
+ acc = dlg->account();
+
+ MyMoneyFileTransaction ft;
+ try {
+ QString id;
+ id = file->createCategory(base, acc.name());
+ if(id.isEmpty())
+ throw new MYMONEYEXCEPTION("failure while creating the account hierarchy");
+
+ ft.commit();
+
+ m_interestAccountEdit->setSelected(id);
+
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to add account: %1").arg(e->what()));
+ delete e;
+ }
+ }
+ delete dlg;
+}
+
+void KNewLoanWizard::loadAccountList(void)
+{
+ AccountSet interestSet, assetSet;
+
+ if(m_borrowButton->isChecked()) {
+ interestSet.addAccountType(MyMoneyAccount::Expense);
+ } else {
+ interestSet.addAccountType(MyMoneyAccount::Income);
+ }
+ interestSet.load(m_interestAccountEdit);
+
+ assetSet.addAccountType(MyMoneyAccount::Checkings);
+ assetSet.addAccountType(MyMoneyAccount::Savings);
+ assetSet.addAccountType(MyMoneyAccount::Cash);
+ assetSet.addAccountType(MyMoneyAccount::Asset);
+ assetSet.addAccountType(MyMoneyAccount::Currency);
+ assetSet.load(m_assetAccountEdit);
+
+ assetSet.addAccountType(MyMoneyAccount::CreditCard);
+ assetSet.addAccountType(MyMoneyAccount::Liability);
+ assetSet.load(m_paymentAccountEdit);
+}
+
+void KNewLoanWizard::slotAdditionalFees(void)
+{
+ // KMessageBox::information(0, QString("Not yet implemented ... if you want to help, contact kmymoney2-developer@lists.sourceforge.net"), QString("Development notice"));
+ MyMoneyAccount account("Phony-ID", MyMoneyAccount());
+
+ QMap<QString, MyMoneyMoney> priceInfo;
+ KSplitTransactionDlg* dlg = new KSplitTransactionDlg(m_transaction, m_split, account, false, !m_borrowButton->isChecked(), MyMoneyMoney(0), priceInfo);
+ connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), this, SIGNAL(newCategory(MyMoneyAccount&)));
+
+ if(dlg->exec() == QDialog::Accepted) {
+ m_transaction = dlg->transaction();
+ // sum up the additional fees
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ MyMoneyMoney fees;
+ for(it = m_transaction.splits().begin(); it != m_transaction.splits().end(); ++it) {
+ if((*it).accountId() != account.id()) {
+ fees += (*it).value();
+ }
+ }
+ m_additionalCost->setText(fees.formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
+ }
+
+ delete dlg;
+ updatePeriodicPayment();
+}
+
+MyMoneyTransaction KNewLoanWizard::transaction() const
+{
+ MyMoneyTransaction t;
+
+ MyMoneySplit sPayment, sInterest, sAmortization;
+ // setup accounts. at this point, we cannot fill in the id of the
+ // account that the amortization will be performed on, because we
+ // create the account. So the id is yet unknown.
+ sPayment.setAccountId(m_paymentAccountEdit->selectedItems().first());
+ sInterest.setAccountId(m_interestAccountEdit->selectedItems().first());
+
+ // values
+ if(m_borrowButton->isChecked()) {
+ sPayment.setValue(-m_paymentEdit->value());
+ } else {
+ sPayment.setValue(m_paymentEdit->value());
+ }
+ sInterest.setValue(MyMoneyMoney::autoCalc);
+ sAmortization.setValue(MyMoneyMoney::autoCalc);
+ // don't forget the shares
+ sPayment.setShares(sPayment.value());
+ sInterest.setShares(sInterest.value());
+ sAmortization.setShares(sAmortization.value());
+
+ // setup the commodity
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(sPayment.accountId());
+ t.setCommodity(acc.currencyId());
+
+ // actions
+ sPayment.setAction(MyMoneySplit::ActionAmortization);
+ sAmortization.setAction(MyMoneySplit::ActionAmortization);
+ sInterest.setAction(MyMoneySplit::ActionInterest);
+
+ // payee
+ QString payeeId = m_payeeEdit->selectedItem();
+ sPayment.setPayeeId(payeeId);
+ sAmortization.setPayeeId(payeeId);
+
+ MyMoneyAccount account("Phony-ID", MyMoneyAccount());
+ sAmortization.setAccountId(account.id());
+
+ // IMPORTANT: Payment split must be the first one, because
+ // the schedule view expects it this way during display
+ t.addSplit(sPayment);
+ t.addSplit(sAmortization);
+ t.addSplit(sInterest);
+
+ // copy the splits from the other costs and update the payment split
+ QValueList<MyMoneySplit>::ConstIterator it;
+ for(it = m_transaction.splits().begin(); it != m_transaction.splits().end(); ++it) {
+ if((*it).accountId() != account.id()) {
+ MyMoneySplit sp = (*it);
+ sp.clearId();
+ t.addSplit(sp);
+ sPayment.setValue(sPayment.value()-sp.value());
+ sPayment.setShares(sPayment.value());
+ t.modifySplit(sPayment);
+ }
+ }
+ return t;
+}
+
+MyMoneySchedule KNewLoanWizard::schedule(void) const
+{
+ MyMoneySchedule sched(m_nameEdit->text(),
+ MyMoneySchedule::TYPE_LOANPAYMENT,
+ MyMoneySchedule::stringToOccurence(m_paymentFrequencyUnitEdit->currentText()), 1,
+ MyMoneySchedule::STYPE_OTHER,
+ QDate(),
+ QDate(),
+ false,
+ false);
+
+ MyMoneyTransaction t = transaction();
+ t.setPostDate(m_nextDueDateEdit->date());
+ sched.setTransaction(t);
+
+ return sched;
+}
+
+void KNewLoanWizard::slotReloadEditWidgets(void)
+{
+ // load the various account widgets
+ loadAccountList();
+
+ // reload payee widget
+ QString payeeId = m_payeeEdit->selectedItem();
+
+ m_payeeEdit->loadPayees(MyMoneyFile::instance()->payeeList());
+
+ if(!payeeId.isEmpty()) {
+ m_payeeEdit->setSelectedItem(payeeId);
+ }
+}
+
+int KNewLoanWizard::term(void) const
+{
+ int factor = 0;
+
+ if(m_durationValueEdit->value() != 0) {
+ factor = 1;
+ switch(m_durationUnitEdit->currentItem()) {
+ case MyMoneySchedule::OCCUR_YEARLY: // years
+ factor = 12;
+ // tricky fall through here
+
+ case MyMoneySchedule::OCCUR_MONTHLY: // months
+ factor *= 30;
+ factor *= m_durationValueEdit->value();
+ // factor now is the duration in days. we divide this by the
+ // payment frequency and get the number of payments
+ factor /= MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::stringToOccurence(
+ m_paymentFrequencyUnitEdit->currentText()));
+ break;
+
+ case MyMoneySchedule::OCCUR_ONCE: // payments
+ factor = m_durationValueEdit->value();
+ break;
+ }
+ }
+ return factor;
+}
+
+QString KNewLoanWizard::initialPaymentAccount(void) const
+{
+ if(m_dontCreatePayoutCheckBox->isChecked()) {
+ return QString();
+ }
+ return m_assetAccountEdit->selectedItems().first();
+}
+
+QDate KNewLoanWizard::initialPaymentDate(void) const
+{
+ if(m_dontCreatePayoutCheckBox->isChecked()) {
+ return QDate();
+ }
+ return m_paymentDate->date();
+}
+
+#include "knewloanwizard.moc"
diff --git a/kmymoney2/dialogs/knewloanwizard.h b/kmymoney2/dialogs/knewloanwizard.h
new file mode 100644
index 0000000..5e291b7
--- /dev/null
+++ b/kmymoney2/dialogs/knewloanwizard.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ knewloanwizard.h - description
+ -------------------
+ begin : Wed Oct 8 2003
+ copyright : (C) 2000-2003 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWLOANWIZARD_H
+#define KNEWLOANWIZARD_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <../dialogs/knewloanwizarddecl.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kmymoneydateinput.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class implementes a wizard for the creation of loan accounts.
+ * The user is asked a set of questions and according to the answers
+ * the respective MyMoneyAccount object can be requested from the
+ * wizard when accept() has been called. A MyMoneySchedule is also
+ * available to create a schedule entry for the payments to the newly
+ * created loan.
+ */
+class KNewLoanWizard : public KNewLoanWizardDecl
+{
+ Q_OBJECT
+public:
+ KNewLoanWizard(QWidget *parent=0, const char *name=0);
+ ~KNewLoanWizard();
+
+ /**
+ * This method returns the schedule for the payments. The account
+ * where the amortization should be transferred to is the one
+ * we currently try to create with this wizard. The appropriate split
+ * will be returned as the first split of the transaction inside
+ *
+ * as parameter @p accountId as this is the account that was created
+ * after this wizard was left via the accept() method.
+ *
+ * @return MyMoneySchedule object for payments
+ */
+ MyMoneySchedule schedule(void) const;
+
+ /**
+ * This method returns the id of the account to/from which
+ * the payout should be created. If the checkbox that allows
+ * to skip the creation of this transaction is checked, this
+ * method returns QString()
+ *
+ * @return id of account or empty QString
+ */
+ QString initialPaymentAccount(void) const;
+
+ /**
+ * This method returns the date of the payout transaction.
+ * If the checkbox that allows to skip the creation of
+ * this transaction is checked, this method returns QDate()
+ *
+ * @return selected date or invalid QDate if checkbox is selected.
+ */
+ QDate initialPaymentDate(void) const;
+
+protected:
+ /**
+ * This method returns the transaction that is stored within
+ * the schedule. See schedule().
+ *
+ * @return MyMoneyTransaction object to be used within the schedule
+ */
+ MyMoneyTransaction transaction(void) const;
+
+public slots:
+ void next();
+
+protected slots:
+ void slotLiabilityLoan(void);
+ void slotAssetLoan(void);
+ virtual void slotCheckPageFinished(void);
+ void slotPaymentsMade(void);
+ void slotNoPaymentsMade(void);
+ void slotRecordAllPayments(void);
+ void slotRecordThisYearsPayments(void);
+ void slotInterestOnPayment(void);
+ void slotInterestOnReception(void);
+ void slotCreateCategory(void);
+ virtual void slotAdditionalFees(void);
+ // void slotNewPayee(const QString&);
+ void slotReloadEditWidgets(void);
+
+protected:
+ void loadComboBoxes(void);
+ void loadAccountList(void);
+ void resetCalculator(void);
+ void updateLoanAmount(void);
+ void updateInterestRate(void);
+ void updateDuration(void);
+ void updatePayment(void);
+ void updateFinalPayment(void);
+ void updateLoanInfo(void);
+ QString updateTermWidgets(const long double v);
+ void updatePeriodicPayment(void);
+ void updateSummary(void);
+ int calculateLoan(void);
+ int term(void) const;
+
+signals:
+ /**
+ * This signal is emitted, when a new category name has been
+ * entered by the user and this name is not known as account
+ * by the MyMoneyFile object.
+ * Before the signal is emitted, a MyMoneyAccount is constructed
+ * by this object and filled with the desired name. All other members
+ * of MyMoneyAccount will remain in their default state. Upon return,
+ * the connected slot should have created the object in the MyMoneyFile
+ * engine and filled the member @p id.
+ *
+ * @param acc reference to MyMoneyAccount object that caries the name
+ * and will return information about the created category.
+ */
+ void newCategory(MyMoneyAccount& acc);
+
+ /**
+ * This signal is sent out, when a new payee needs to be created
+ * @sa KMyMoneyCombo::createItem()
+ *
+ * @param txt The name of the payee to be created
+ * @param id A connected slot should store the id of the created object in this variable
+ */
+ void createPayee(const QString& txt, QString& id);
+
+protected:
+ MyMoneyAccountLoan m_account;
+ MyMoneyTransaction m_transaction;
+ MyMoneySplit m_split;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/knewloanwizarddecl.ui b/kmymoney2/dialogs/knewloanwizarddecl.ui
new file mode 100644
index 0000000..d45eb4b
--- /dev/null
+++ b/kmymoney2/dialogs/knewloanwizarddecl.ui
@@ -0,0 +1,5497 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KNewLoanWizardDecl</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>KNewLoanWizardDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>589</width>
+ <height>458</height>
+ </rect>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>800</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>New Loan Wizard</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="titleFont">
+ <font>
+ </font>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_newIntroPage</cstring>
+ </property>
+ <attribute name="title">
+ <string></string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>98</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <family>Helvetica</family>
+ <pointsize>16</pointsize>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>New Loan Account Wizard</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignHCenter</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>119</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Welcome to the New Loan Account Wizard which will guide you through the creation of a new loan e.g. for your home, your car or any other loan that you pay or gain interest for.
+
+Please make sure that you have the relevant information handy. You usually get the information out of your contract and the last statement.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_editIntroPage</cstring>
+ </property>
+ <attribute name="title">
+ <string></string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>98</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_1_2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <family>Helvetica</family>
+ <pointsize>16</pointsize>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Edit Loan Account Wizard</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignHCenter</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>119</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Welcome to the Edit Loan Account Wizard. Please use this wizard to modify information about your loan account.
+
+Please make sure that you have the relevant information handy. You usually get the information out of your contract and the last statement.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer79</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_newGeneralInfoPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>General Information</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+In the first step, KMyMoney will ask you some general information about the loan account to be created.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>138</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>1. General Information</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>
+2. Calculate Loan
+
+3. Payments</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>137</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer44</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_editSelectionPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Edit selection</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_2_1</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please select, which data of the loan you want to modify.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer64</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>48</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout33</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer67_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>93</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_selectionButtonGroup</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_editInterestRateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Modify the interest rate</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_editOtherCostButton</cstring>
+ </property>
+ <property name="text">
+ <string>Modify additional fees</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_editOtherInfoButton</cstring>
+ </property>
+ <property name="text">
+ <string>Modify other loan information</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer66</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>108</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer65</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>47</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_effectiveDatePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Effective date</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_effectiveDateLabel</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_effectiveDateNoteLabel</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer68_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout34</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_7</cstring>
+ </property>
+ <property name="text">
+ <string>When should the changes become active?</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_effectiveChangeDateEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer69_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>87</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_lendBorrowPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Lending or borrowing money</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Do you borrow or lend money?</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>61</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout38</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_borrowButton</cstring>
+ </property>
+ <property name="text">
+ <string>I am borrowing money</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_lendButton</cstring>
+ </property>
+ <property name="text">
+ <string>I am lending money</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>299</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_namePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Name of the loan</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+How do you want to call this loan? Examples for names are 'car loan', 'school loan', 'home owner loan'.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer15_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>56</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyLineEdit">
+ <property name="name">
+ <cstring>m_nameEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer19</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>56</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_generalReceiverText</cstring>
+ </property>
+ <property name="text">
+ <string>TextLabel6</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout55</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_receiverLabel</cstring>
+ </property>
+ <property name="text">
+ <string>TextLabel7</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyPayeeCombo">
+ <property name="name">
+ <cstring>m_payeeEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer21</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>56</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_interestTypePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Type of interest</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel5_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Is the interest of this loan fixed over a period of time or is it adapted from time to time? If the interest rate changes during the amortization phase of the loan you should choose the option 'variable interest rate'.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer23</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>53</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout39</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_fixedInterestButton</cstring>
+ </property>
+ <property name="text">
+ <string>Fixed interest rate</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_variableInterestButton</cstring>
+ </property>
+ <property name="text">
+ <string>Variable interest rate</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>286</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer24</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>53</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_previousPaymentsPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Payments?</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Were there any payments for this loan whether they are entered into KMyMoney or not?</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer28</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout40</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_noPreviousPaymentButton</cstring>
+ </property>
+ <property name="text">
+ <string>No, no payments were made yet.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_previousPaymentButton</cstring>
+ </property>
+ <property name="text">
+ <string>Yes, payments were made.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>202</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer29</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Note: Payments made to obtain the loan (e.g. Dissagio) are not considered as payments in this context.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer41</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_recordPaymentPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Recording payments?</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel7_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Do you want to record all payments of this loan with KMyMoney?</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer33</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>69</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout41</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup4</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_allPaymentsButton</cstring>
+ </property>
+ <property name="text">
+ <string>Yes, record all payments.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_thisYearPaymentButton</cstring>
+ </property>
+ <property name="text">
+ <string>No, only record payments since the beginning of this year.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14_2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>137</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer34</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>69</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_variableInterestDatePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Date of next interest change</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel8_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Select the date when the interest rate for this loan will be modified and the frequency of the future changes.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer39</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>99</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout44</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Next interest change on</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout42</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>m_interestFrequencyAmountEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo">
+ <property name="name">
+ <cstring>m_interestFrequencyUnitEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="0" column="1">
+ <property name="name">
+ <cstring>m_interestChangeDateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Time until next change</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer40</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>80</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_paymentEditPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Payment</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel8_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please enter the amount you pay for principal and interest or leave the field empty to calculate it.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer70_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout39</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer76</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout35</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="kMyMoneyEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_newPaymentEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>Current amount</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_paymentLabel</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>Principal and interest</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer75</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer71</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>19</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel4_5</cstring>
+ </property>
+ <property name="text">
+ <string>KMyMoney either calculates the new interest rate or the amount for principal and interest. If you know the amount for principal and interest then enter it here.
+
+If KMyMoney should calculate this value for you, then leave the field blank.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_interestEditPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Interest Rate</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel5_4</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please enter the interest rate or leave the field empty to calculate it.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer72</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>29</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout40</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer77</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>101</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout36</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="kMyMoneyEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_newInterestRateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRateLabel</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel7_3</cstring>
+ </property>
+ <property name="text">
+ <string>Current rate</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_5</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer78</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>101</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer73</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>29</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel9_4</cstring>
+ </property>
+ <property name="text">
+ <string>KMyMoney either calculates the new interest rate or the amount for principal and interest. If you know the interest rate then enter it here.
+
+If KMyMoney should calculate this value for you, then leave the field blank.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_firstPaymentPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Date of first payment</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_firstPaymentLabel</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer42</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>78</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout22_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>First payment due on</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_firstDueDateEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer43</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>28</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_firstPaymentNote</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignBottom</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_newCalculateLoanPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Calculate Loan</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+You have successfully entered the general information about your loan. Next, KMyMoney needs some information about the calculation of the loan.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer10_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>19</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout31</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>136</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout30</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3_4</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>1. General Information</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel4_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+2. Calculate Loan</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel4_3</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>
+3. Payments</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>18</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>135</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer51</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_paymentFrequencyPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Payment frequency</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel11_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+How often will there be payments made to this loan?</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer54</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>49</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout33</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer57</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>39</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>m_paymentFrequencyUnitEdit</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer56</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>56</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer55</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>49</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_interestCalculationPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Interest calculation</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel12_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+When does the actual interest rate get calculated?</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer61</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>69</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout42</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_interestOnReceptionButton</cstring>
+ </property>
+ <property name="text">
+ <string>When the payment is received.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_interestOnPaymentButton</cstring>
+ </property>
+ <property name="text">
+ <string>When the payment is due.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14_2_2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>296</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer62</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>69</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_loanAmountPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Loan amount</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_balanceLabel</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer68</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>15</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout38</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel16</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_loanAmountEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_loanAmount1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRate1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_duration1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payment1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_balloon1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_interestPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Interest</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel14_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please enter the interest rate or leave the field empty to calculate it.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer67</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout36</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_interestRateEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_3</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8_3</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9_2</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_loanAmount2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRate2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_duration2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payment2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_balloon2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_durationPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Duration</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel15_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please enter the term of this loan or leave the field empty to calculate it. The term is the time that is required to fully repay the loan. This time might be different from the time your loan contract is signed for.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer67_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>54</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout43</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Term</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>m_durationValueEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo">
+ <property name="name">
+ <cstring>m_durationUnitEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_loanAmount3</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRate3</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_duration3</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payment3</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_balloon3</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_paymentPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Payment</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel16_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please enter the amount you pay for principal and interest or leave the field empty to calculate it.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer74</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout36_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal and interest</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_paymentEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8_3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_loanAmount4</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRate4</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_duration4</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payment4</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_balloon4</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_finalPaymentPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Final amortization payment</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel17_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please enter the amount of a final amortization payment or leave the field empty to calculate it.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer74_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout44</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_4_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_finalPaymentEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2_2_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_3_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8_3_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_loanAmount5</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRate5</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_duration5</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payment5</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_balloon5</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_calculationOverviewPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Calculation Overview</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel18_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+KMyMoney has calculated the loan as shown in the overview below. You can accept these values by selecting "Next" or change them by choosing "Back" to return to the input field for the information you want to change.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer79</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>22</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2_2_2_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_3_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8_3_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Final amortization payment</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_loanAmount6</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_interestRate6</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_duration6</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_payment6</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_balloon6</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_newPaymentsPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Payments</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel19_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+In the following steps, KMyMoney supports you in setting up categories and schedules for your loan payments.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer10_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>14</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout31_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>136</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout30_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel19_3</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>1. General Information</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel19_4</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>
+2. Calculate Loan</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel19_5</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>
+3. Payments</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>18</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>135</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer51_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>18</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_interestCategoryPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Interest category</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel20_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+Please select the category you want to assign the interest payments to or create a new category.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer90</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>38</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_interestAccountEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout29</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer54_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>264</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_createCategoryButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer91</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>22</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_additionalFeesPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Additional Fees</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel21_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+If your regular payment contains any additional fees, click on the button "Additional fees" to enter them.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer58</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame9</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>TextLabel21_1_3</cstring>
+ </property>
+ <property name="text">
+ <string>= periodical payment:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>m_periodicPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>m_additionalCost</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>Layout63</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel21_1_2</cstring>
+ </property>
+ <property name="text">
+ <string>+</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_additionalFeeButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>m_basePayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>TextLabel21_1</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer173_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>spacer173</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer59</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel21_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>If no additional fees are included in your periodical payment or you have entered all such fees, then click on "Next".</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer60</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_schedulePage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Schedule</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel22_2</cstring>
+ </property>
+ <property name="text">
+ <string>KMyMoney will create a schedule for this payment and reminds you whenever a payment must be made.&lt;p&gt;
+If you selected to record all payments this date has already been supplied. If you selected to record only this years payments, then the &lt;b&gt;First payment due date&lt;/b&gt; is the date of the first payment made in this year.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer67_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout49</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="kMyMoneyAccountSelector" row="1" column="1">
+ <property name="name">
+ <cstring>m_paymentAccountEdit</cstring>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="0" column="1">
+ <property name="name">
+ <cstring>m_nextDueDateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_dueLabel</cstring>
+ </property>
+ <property name="text">
+ <string>First payment due on:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2_5</cstring>
+ </property>
+ <property name="text">
+ <string>Make payment from/to:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer68_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_summaryEditPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Summary</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel10_4</cstring>
+ </property>
+ <property name="text">
+ <string>
+KMyMoney has calculated the loan as shown below. If you want to accept these values use the "Finish" button to update your account, otherwise use the "Back" button to modify your settings.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer74_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2_2_2_2_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_3_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel8_3_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Additional fees:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel9_2_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Total payment:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel10_2_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Valid from:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel11_3_2_2_2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Affected payments:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_payment7</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_additionalFees7</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_totalPayment7</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_interestRate7</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_startDateChanges</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>m_affectedPayments</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_assetAccountPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Asset Account</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel10_4_2</cstring>
+ </property>
+ <property name="text">
+ <string>If this loan is for an asset, such as a car or a house, you can create the asset account now. An asset account represents the total value of an asset. The money from this loan will be transfered into the asset account you create or select.
+If this loan is a 'consumer loan' (money to use however you want), you can use a checking account instead.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer80</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_dontCreatePayoutCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Don't create payout transaction</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout124</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyAccountSelector">
+ <property name="name">
+ <cstring>m_assetAccountEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout123</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer244</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>466</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_createNewAssetButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Press this to create a new asset account</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout170</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Date of payment</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_paymentDate</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer328</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_summaryPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Summary</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel22_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>
+This page summarizes the data you entered. If you need to modify anything, please use the "Back" button to go to respective page. Otherwise use the "Finish" button to create the account.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer69</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout61</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout60</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>General</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout52</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel5_3</cstring>
+ </property>
+ <property name="text">
+ <string>Payee:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_summaryLoanType</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_summaryPayee</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4_4</cstring>
+ </property>
+ <property name="text">
+ <string>First payment:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_summaryFirstPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel3_5</cstring>
+ </property>
+ <property name="text">
+ <string>Amount is:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Loan calculation</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout57</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_summaryTotalPeriodicPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>m_summaryPaymentAccount</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_summaryAdditionalFees</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel15</cstring>
+ </property>
+ <property name="text">
+ <string>Periodic Payment:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>TextLabel14</cstring>
+ </property>
+ <property name="text">
+ <string>Additional Fees:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel13</cstring>
+ </property>
+ <property name="text">
+ <string>Interest category:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel17</cstring>
+ </property>
+ <property name="text">
+ <string>Payment from:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>m_summaryInterestCategory</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_summaryNextPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel16_3</cstring>
+ </property>
+ <property name="text">
+ <string>Next due date:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Payment</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout59</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>m_summaryInterestRate</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel10_3</cstring>
+ </property>
+ <property name="text">
+ <string>Term:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>m_summaryPeriodicPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel9_3</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_summaryPaymentFrequency</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>TextLabel12</cstring>
+ </property>
+ <property name="text">
+ <string>Final Payment:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>m_summaryTerm</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6_4</cstring>
+ </property>
+ <property name="text">
+ <string>Interest is due:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_summaryAmount</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel11_4</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>m_summaryBalloonPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel8_4</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Payment frequency:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>m_summaryInterestDue</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer70</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyLineEdit</class>
+ <header location="local">../widgets/kmymoneylineedit.h</header>
+ <sizehint>
+ <width>90</width>
+ <height>25</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>kMyMoneyAccountSelector</class>
+ <header location="global">../widgets/kmymoneyaccountselector.h</header>
+ <sizehint>
+ <width>80</width>
+ <height>80</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1110">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000041d49444154388d8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d09a6c508138cb8c13d647141163de49043bca9f1628eb9294810f24f88c15b728b07617358888785d980427290b4a8d00b19a8821da8228cf42316ac87eed9247ac95c9aeaeef9eaabdffb5ebf85f178ccfcf7f5b79fec07a7280a08a008f25ceb7c29e5da573716e65a0be3f198ef6f5ededff9b9e1b34faf90882092a1ea21428b9220ffbf46054055b19386ba6970ae6665b5e0d2c5eb0b066067bbe1f21757c88f5504eff0c192189081303a5582b16854fccce2fe041f00cdd0a8103b874556405476b62d972ec2c2b90ff3fd8df5cb946549d80b34aea15ccaa94625450e2d0e558b460b7371a734b5e027251a155545678ab62d7eea90b4c504078908c107acb354cb251b1f8f08b1c18631aabbb4d18211404804f22545863561d2f060fb34aa8a18d0086204e72c46a32292e1a796f278c1da7a859d8da9a737506db04d0a24103d8949480b214d3bbee952a05c1d536f9d2684160c744f048311543d459eb1b65ee1754cedae13a64abd5d6127053c9d0281f22d4f75c6a2118a5c09272d7ab740638bf4ef2dd2174032d0d8d04c6fe19c32bedd8bc65e342aa3f785e2784bfd6bc1bd9db24b05505616a4edd67d5a8c1801a03a9962754c504bf34b8986acfb9be91cac7d54315a15541b36b134f74bd2dc53940115a5381e087bc25c6f71be831a8baa234cc1ee3eeb74ed83116beb2b8849d108a3730e8ce27e2bfb82419a7b407ac7c222fd0e6280a8078ce64e47ef54ac9d5be9aaae0162e0de568a44a18d3df90845d919c4f01463406340a44f40efb43a99b371618488e2670d1a2d7ee6f1d3be39342104e937ed85fb86599c33e9ee0be9a004946259d8b858909880d59aa00daa0d3280b5f39e34074c4b3a5434029a76a9e9f5cc0163b5c80024158a1cfc4cb1d3061d5834066cb0a403c008599a70f6bc27b8d03106ea3ae91987278c5b143b015547224ab5e24185cd9b81665273e7b6e7cecd82ddbf8098002de94049737bc09828cf3036f31c3735c8b0e98eb704672f348c7f7c93cd1fb2ae905119ff54e0dff3542b0e9dd983dcea2cc5eea6cf303e74ec687af5c41b6fa38f5e203c7ec8e1238ef85831a214afef21060ea781ec68247b65c6916353cc8b73d1ae79354606af2a930709aa118da1636c274dd7e3774b884a79aa6b5711a538d33cf9c01c1c9b83bc6a1f55c91ccb23b05b1deb43a7decdaffefd2862f61366aa8449c69e33642f012f2bb208fa98eeda1f3346f076c8eeef19475e9be115423364f78f84105a8643d34d90cfbfdcd8cf872589a45dc7f54cf3134a36f4e495c23f9da8db15bccb708d4014f2ca512cb5d4f7c13e84300d5cff6eb39b202bab053bdb9674f0648609427d0f8402ddeac30f4fcd3ced3efc3b422d406c09b340bedc1571e1bfc3d44dc281634c5fe5e758e7395cfbe6d6c130fd17d92372d277c159b70000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/konlinequoteconfigurationdecl.ui b/kmymoney2/dialogs/konlinequoteconfigurationdecl.ui
new file mode 100644
index 0000000..0ca2d14
--- /dev/null
+++ b/kmymoney2/dialogs/konlinequoteconfigurationdecl.ui
@@ -0,0 +1,199 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kOnlineQuoteConfigurationDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kOnlineQuoteConfigurationDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>282</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Online Quote Configuration</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>240</y>
+ <width>476</width>
+ <height>33</height>
+ </rect>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>90</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Perl Location:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>40</y>
+ <width>90</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Script:</string>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo">
+ <property name="name">
+ <cstring>cmbScriptName</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>40</y>
+ <width>310</width>
+ <height>21</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>edtPerlLocation</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>10</y>
+ <width>380</width>
+ <height>21</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnBrowse</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>430</x>
+ <y>40</y>
+ <width>61</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Browse...</string>
+ </property>
+ </widget>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>kOnlineQuoteConfigurationDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>kOnlineQuoteConfigurationDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/konlinequoteconfigurationdlg.cpp b/kmymoney2/dialogs/konlinequoteconfigurationdlg.cpp
new file mode 100644
index 0000000..8503d5a
--- /dev/null
+++ b/kmymoney2/dialogs/konlinequoteconfigurationdlg.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ konlinequoteconfigurationdlg.cpp - description
+ -------------------
+ begin : Tuesday July 1st, 2004
+ copyright : (C) 2004 by Kevin Tambascio
+ email : ktambascio@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <klistbox.h>
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinequoteconfigurationdecl.h"
+#include "konlinequoteconfigurationdlg.h"
+
+
+KOnlineQuoteConfigurationDlg::KOnlineQuoteConfigurationDlg(QWidget *parent) : kOnlineQuoteConfigurationDecl(parent)
+{
+
+}
+
+KOnlineQuoteConfigurationDlg::~KOnlineQuoteConfigurationDlg()
+{
+
+}
+
+#include "konlinequoteconfigurationdlg.moc"
diff --git a/kmymoney2/dialogs/konlinequoteconfigurationdlg.h b/kmymoney2/dialogs/konlinequoteconfigurationdlg.h
new file mode 100644
index 0000000..f6ea139
--- /dev/null
+++ b/kmymoney2/dialogs/konlinequoteconfigurationdlg.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ konlinequoteconfigurationdlg.h - description
+ -------------------
+ begin : Tuesday July 1st, 2004
+ copyright : (C) 2004 by Kevin Tambascio
+ email : ktambascio@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KONLINEQUOTECONFIGURATIONDIALOG_H
+#define KONLINEQUOTECONFIGURATIONDIALOG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinequoteconfigurationdecl.h"
+//#include "../mymoney/mymoneyonlinepriceupdate.h"
+
+
+/**
+ * @author Kevin Tambascio
+ */
+
+class KOnlineQuoteConfigurationDlg : public kOnlineQuoteConfigurationDecl
+{
+ Q_OBJECT
+public:
+ KOnlineQuoteConfigurationDlg(QWidget *parent);
+ ~KOnlineQuoteConfigurationDlg();
+
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kpayeereassigndlg.cpp b/kmymoney2/dialogs/kpayeereassigndlg.cpp
new file mode 100644
index 0000000..0ed8a5a
--- /dev/null
+++ b/kmymoney2/dialogs/kpayeereassigndlg.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+ kpayeereassigndlg.cpp
+ -------------------
+ copyright : (C) 2005 by Andreas Nicolai
+ (C) 2007 by Thomas Baumgart
+ author : Andreas Nicolai, Thomas Baumgart
+ email : ghorwin@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdialog.h>
+#include <klocale.h>
+#include <kstdguiitem.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kpayeereassigndlg.h"
+#include <kmymoney/kmymoneycombo.h>
+#include <kmymoney/kguiutils.h>
+
+KPayeeReassignDlg::KPayeeReassignDlg( QWidget* parent, const char* name) :
+ KPayeeReassignDlgDecl( parent, name)
+{
+ buttonOk->setGuiItem(KStdGuiItem::ok());
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+ kMandatoryFieldGroup* mandatory = new kMandatoryFieldGroup(this);
+ mandatory->add(payeeCombo);
+ mandatory->setOkButton(buttonOk);
+}
+
+KPayeeReassignDlg::~KPayeeReassignDlg()
+{
+}
+
+QString KPayeeReassignDlg::show(const QValueList<MyMoneyPayee>& payeeslist)
+{
+ if (payeeslist.isEmpty())
+ return QString(); // no payee available? nothing can be selected...
+
+ payeeCombo->loadPayees(payeeslist);
+
+ // execute dialog and if aborted, return empty string
+ if (this->exec() == QDialog::Rejected)
+ return QString();
+
+ // otherwise return index of selected payee
+ return payeeCombo->selectedItem();
+}
+
+
+void KPayeeReassignDlg::accept(void)
+{
+ // force update of payeeCombo
+ buttonOk->setFocus();
+
+ if(payeeCombo->selectedItem().isEmpty()) {
+ KMessageBox::information(this, i18n("This dialog does not allow to create new payees. Please pick a payee from the list."), i18n("Payee creation"));
+ } else {
+ KPayeeReassignDlgDecl::accept();
+ }
+}
+
+#include "kpayeereassigndlg.moc"
diff --git a/kmymoney2/dialogs/kpayeereassigndlg.h b/kmymoney2/dialogs/kpayeereassigndlg.h
new file mode 100644
index 0000000..3edab86
--- /dev/null
+++ b/kmymoney2/dialogs/kpayeereassigndlg.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ kpayeereassigndlg.cpp
+ -------------------
+ copyright : (C) 2005 by Andreas Nicolai
+ (C) 2007 by Thomas Baumgart
+ author : Andreas Nicolai, Thomas Baumgart
+ email : ghorwin@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KPAYEEREASSIGNDLG_H
+#define KPAYEEREASSIGNDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qvaluelist.h>
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneypayee.h>
+#include "kmymoney2/dialogs/kpayeereassigndlgdecl.h"
+
+/**
+ * Implementation of the dialog that lets the user select a payee in order
+ * to re-assign transactions (for instance, if payees are deleted).
+ */
+class KPayeeReassignDlg : public KPayeeReassignDlgDecl
+{
+ Q_OBJECT
+public:
+ /** Default constructor */
+ KPayeeReassignDlg( QWidget* parent = 0, const char* name = 0);
+
+ /** Destructor */
+ ~KPayeeReassignDlg();
+
+ /**
+ * This function sets up the dialog, lets the user select a payee and returns
+ * the id of the selected payee in the payeeslist.
+ *
+ * @param payeeslist reference to QValueList of MyMoneyPayee objects to be contained in the list
+ *
+ * @return Returns the id of the selected payee in the list or QString() if
+ * the dialog was aborted. QString() is also returned if the payeeslist is empty.
+ */
+ QString show(const QValueList<MyMoneyPayee>& payeeslist);
+
+ /**
+ * Returns true, if the names of the payees to be deleted should be copied
+ * to the selected payee's match list.
+ */
+ bool addToMatchList(void) const { return m_copyToMatchList->isChecked(); }
+
+protected:
+ void accept(void);
+
+};
+
+#endif // KPAYEEREASSIGNDLG_H
diff --git a/kmymoney2/dialogs/kpayeereassigndlgdecl.ui b/kmymoney2/dialogs/kpayeereassigndlgdecl.ui
new file mode 100644
index 0000000..a968709
--- /dev/null
+++ b/kmymoney2/dialogs/kpayeereassigndlgdecl.ui
@@ -0,0 +1,186 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KPayeeReassignDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KPayeeReassignDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>558</width>
+ <height>312</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Reassign payees</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>The transactions associated with the selected payees need to be re-assigned to a different payee before the selected payees can be deleted. Please select a payee from the list below.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignJustify|AlignTop</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Available payees:</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyPayeeCombo">
+ <property name="name">
+ <cstring>payeeCombo</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_copyToMatchList</cstring>
+ </property>
+ <property name="text">
+ <string>Assign deleted names to the above selected payee's matching list</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>305</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KPayeeReassignDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KPayeeReassignDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kplugindlg.ui b/kmymoney2/dialogs/kplugindlg.ui
new file mode 100644
index 0000000..33a6f88
--- /dev/null
+++ b/kmymoney2/dialogs/kplugindlg.ui
@@ -0,0 +1,154 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KPluginDlg</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KPluginDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>503</width>
+ <height>285</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>PluginDlg</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView" row="0" column="0" rowspan="1" colspan="4">
+ <column>
+ <property name="text">
+ <string>PlugIn</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Status</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Feature</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listView</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>180</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>2</number>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="3">
+ <property name="name">
+ <cstring>closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>13</number>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>KPluginDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KPluginDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KPluginDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/krecentfileitem.cpp b/kmymoney2/dialogs/krecentfileitem.cpp
new file mode 100644
index 0000000..679078d
--- /dev/null
+++ b/kmymoney2/dialogs/krecentfileitem.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+ krecentfileitem.cpp - description
+ -------------------
+ begin : Wed Jul 30 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtooltip.h>
+#include <qwidget.h>
+#include <qrect.h>
+#include <qpoint.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include "krecentfileitem.h"
+
+KRecentFileItem::KRecentFileItem(const QString& url, QIconView* parent, const QString& text, const QPixmap& icon)
+ : QIconViewItem(parent, text, icon),
+ m_url(url),
+ m_parent(parent)
+{
+ QToolTip::add(parent, rect(), url);
+ // avoid moving this item around
+ setDragEnabled(false);
+}
+
+KRecentFileItem::~KRecentFileItem()
+{
+}
+
+bool KRecentFileItem::move( int x, int y )
+{
+ QRect r = rect();
+ QToolTip::remove(m_parent, rect());
+ r.moveTopLeft(QPoint(x,y));
+ QToolTip::add(m_parent, r, m_url);
+ return QIconViewItem::move(x,y);
+}
+
diff --git a/kmymoney2/dialogs/krecentfileitem.h b/kmymoney2/dialogs/krecentfileitem.h
new file mode 100644
index 0000000..bb88cba
--- /dev/null
+++ b/kmymoney2/dialogs/krecentfileitem.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ krecentfileitem.h - description
+ -------------------
+ begin : Wed Jul 30 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KRECENTFILEITEM_H
+#define KRECENTFILEITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qwidget.h>
+#include <qiconview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kurl.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+
+/**
+ * @author Michael Edwardes
+ */
+
+class KRecentFileItem : public QIconViewItem {
+public:
+ KRecentFileItem(const QString& url, QIconView* parent, const QString& text, const QPixmap& icon);
+ ~KRecentFileItem();
+ QString fileURL(void) const { return m_url; }
+
+ bool move( int x, int y );
+
+private:
+ QString m_url;
+ QWidget* m_parent;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kreconciledlg.cpp b/kmymoney2/dialogs/kreconciledlg.cpp
new file mode 100644
index 0000000..75e7b48
--- /dev/null
+++ b/kmymoney2/dialogs/kreconciledlg.cpp
@@ -0,0 +1,463 @@
+/***************************************************************************
+ kreconciledlg.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <klocale.h>
+#if QT_VERSION > 300
+#include <kstandarddirs.h>
+#else
+#include <kstddirs.h>
+#endif
+
+
+#include "kreconciledlg.h"
+
+KReconcileDlg::KReconcileDlg(const MyMoneyMoney /* previousBal */, const MyMoneyMoney /* endingBal */,
+ const QDate /* endingDate */, MyMoneyAccount* /*accountIndex */,
+ const MyMoneyFile* /* file */, QWidget *parent, const char *name)
+ : KReconcileDlgDecl(parent,name,true)
+{
+/*
+ m_balanced = false;
+ m_debitsQList.setAutoDelete(false);
+ m_creditsQList.setAutoDelete(false);
+ m_reconciledTransactions.setAutoDelete(false);
+
+ m_file = file;
+ m_accountIndex = accountIndex;
+ m_endingBalance = endingBal;
+ m_previousBalance = previousBal;
+ m_clearedBalance.setAmount(0.0);
+ m_debitBalance.setAmount(0.0);
+ m_creditBalance.setAmount(0.0);
+ m_endingDate = endingDate;
+
+
+ totalCreditsLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ totalDebitsLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ previousLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ endingLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ differenceLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+
+
+ debitListView->setRootIsDecorated(false);
+ debitListView->addColumn(i18n("Date"));
+ debitListView->addColumn(i18n("Number"));
+ debitListView->addColumn(i18n("Payee"));
+ debitListView->addColumn(i18n("Amount"));
+ debitListView->addColumn(i18n("C"));
+ debitListView->setMultiSelection(true);
+ debitListView->setAllColumnsShowFocus(true);
+ // never show a horizontal scroll bar
+ debitListView->setHScrollBarMode(QScrollView::AlwaysOff);
+
+ creditListView->setRootIsDecorated(false);
+ creditListView->addColumn(i18n("Date"));
+ creditListView->addColumn(i18n("Number"));
+ creditListView->addColumn(i18n("Payee"));
+ creditListView->addColumn(i18n("Amount"));
+ creditListView->addColumn(i18n("C"));
+ creditListView->setMultiSelection(true);
+ creditListView->setAllColumnsShowFocus(true);
+ // never show a horizontal scroll bar
+ creditListView->setHScrollBarMode(QScrollView::AlwaysOff);
+
+ endingLabel->setText(KGlobal::locale()->formatMoney(m_clearedBalance.amount(),""));
+
+ previousLabel->setText(KGlobal::locale()->formatMoney(m_endingBalance.amount(),""));
+
+ broughtForwardLabel->setText(KGlobal::locale()->formatMoney(m_previousBalance.amount(),""));
+
+ totalCreditsLabel->setText(i18n("Deposits: ") + KGlobal::locale()->formatMoney(m_creditBalance.amount(),""));
+
+ totalDebitsLabel->setText(i18n("Withdrawals: ") + KGlobal::locale()->formatMoney(m_debitBalance.amount(),""));
+
+
+ loadLists();
+ insertTransactions();
+
+ connect(debitListView, SIGNAL(clicked(QListViewItem*, const QPoint&, int)), this, SLOT(slotDebitSelected(QListViewItem*, const QPoint&, int)));
+ connect(creditListView, SIGNAL(clicked(QListViewItem*, const QPoint&, int)), this, SLOT(slotCreditSelected(QListViewItem*, const QPoint&, int)));
+ connect(buttonCancel, SIGNAL(clicked()), this, SLOT(cancelClicked()));
+ connect(buttonOk, SIGNAL(clicked()), this, SLOT(finishClicked()));
+ connect(buttonEdit, SIGNAL(clicked()), this, SLOT(editClicked()));
+
+ doDifference();
+*/
+}
+
+KReconcileDlg::~KReconcileDlg()
+{
+}
+
+void KReconcileDlg::clearReconcile()
+{
+/*
+ MyMoneyTransaction *temp_transaction;
+ for(temp_transaction = m_creditsQList.first();temp_transaction;temp_transaction = m_creditsQList.next())
+ {
+ if(temp_transaction->state() == MyMoneyTransaction::Reconciled)
+ {
+ temp_transaction->setState(MyMoneyTransaction::Unreconciled);
+ }
+ }
+ for(temp_transaction = m_debitsQList.first();temp_transaction;temp_transaction = m_debitsQList.next())
+ {
+ if(temp_transaction->state() == MyMoneyTransaction::Reconciled)
+ {
+ temp_transaction->setState(MyMoneyTransaction::Unreconciled);
+ }
+ }
+*/
+}
+
+void KReconcileDlg::loadLists(void)
+{
+/*
+ // Load the internal transaaction lists
+ m_creditsQList.clear();
+ m_debitsQList.clear();
+
+ unsigned int i=0;
+ MyMoneyTransaction *transaction;
+ for (i=0, transaction=m_accountIndex->transactionFirst(); transaction; transaction=m_accountIndex->transactionNext(), i++) {
+ if (transaction->date()>m_endingDate)
+ break;
+
+ if (transaction->state()!=MyMoneyTransaction::Reconciled) {
+ if (transaction->type() == MyMoneyTransaction::Debit) {
+ transaction->setIndex(i);
+ m_debitsQList.append(transaction);
+ }
+ else {
+ transaction->setIndex(i);
+ m_creditsQList.append(transaction);
+ }
+ }
+ }
+ resizeEvent(NULL);
+*/
+}
+
+void KReconcileDlg::insertTransactions(void)
+{
+/*
+ creditListView->clear();
+ debitListView->clear();
+
+ QListIterator<MyMoneyTransaction> it(m_debitsQList);
+ for ( ; it.current(); ++it) {
+ (void) new KReconcileListItem(debitListView, it.current());
+ }
+
+ QListIterator<MyMoneyTransaction> it2(m_creditsQList);
+ for ( ; it2.current(); ++it2) {
+ (void) new KReconcileListItem(creditListView, it2.current());
+ }
+
+ resizeEvent(0);
+*/
+}
+
+void KReconcileDlg::slotDebitSelected(QListViewItem* /* item */, const QPoint&/*p*/, int/* col*/)
+{
+/*
+ KReconcileListItem *reconcileItem = (KReconcileListItem*)item;
+ if (!reconcileItem)
+ return;
+
+ // Changed double types to MyMoneyMoney because in the future
+ // we will support mulitple currencies and have our own incompatable
+ // internal format. (one that rounds properly and supports large numbers
+ // e.g unsigned long.int with sign being a boolean).
+// MyMoneyMoney dblDebit = m_debitBalance;
+// MyMoneyMoney dblCleared = m_clearedBalance;
+ MyMoneyMoney dblItem = reconcileItem->transaction()->amount();
+
+ if(reconcileItem->isSelected())
+ {
+ m_debitBalance += dblItem;
+ m_clearedBalance -= dblItem;
+ reconcileItem->setReconciled(true);
+ m_reconciledTransactions.append(reconcileItem->transaction());
+ }
+ else
+ {
+ m_debitBalance -= dblItem;
+ m_clearedBalance += dblItem;
+ reconcileItem->setReconciled(false);
+ m_reconciledTransactions.remove(reconcileItem->transaction());
+ }
+ totalDebitsLabel->setText(i18n("Withdrawals: ") + KGlobal::locale()->formatMoney(m_debitBalance.amount(),""));
+
+ endingLabel->setText(KGlobal::locale()->formatMoney(m_clearedBalance.amount(),""));
+
+ doDifference();
+*/
+}
+
+void KReconcileDlg::slotCreditSelected(QListViewItem* /* item */, const QPoint&, int)
+{
+/*
+ KReconcileListItem *reconcileItem = (KReconcileListItem*)item;
+ if (!reconcileItem)
+ return;
+
+ // See above func
+// double dblCredit = m_creditBalance.amount();
+// double dblCleared = m_clearedBalance.amount();
+ MyMoneyMoney dblItem = reconcileItem->transaction()->amount();
+ if(reconcileItem->isSelected())
+ {
+ m_creditBalance += dblItem;
+ m_clearedBalance += dblItem;
+ reconcileItem->setReconciled(true);
+ m_reconciledTransactions.append(reconcileItem->transaction());
+ }
+ else
+ {
+ m_creditBalance -= dblItem;
+ m_clearedBalance -= dblItem;
+ reconcileItem->setReconciled(false);
+ m_reconciledTransactions.remove(reconcileItem->transaction());
+ }
+
+ totalCreditsLabel->setText(i18n("Deposits: ") + KGlobal::locale()->formatMoney(m_creditBalance.amount(),""));
+
+ endingLabel->setText(KGlobal::locale()->formatMoney(m_clearedBalance.amount(),""));
+
+ doDifference();
+*/
+}
+
+void KReconcileDlg::doDifference(void)
+{
+/*
+ MyMoneyMoney difference((m_previousBalance + m_clearedBalance)- m_endingBalance);
+
+ differenceLabel->setText(KGlobal::locale()->formatMoney(difference.amount(),""));
+ if (difference.isZero())
+ m_balanced = true;
+ else
+ m_balanced = false;
+*/
+}
+
+void KReconcileDlg::finishClicked(void)
+{
+/*
+ if (!m_balanced) {
+ if ((KMessageBox::questionYesNo(this, i18n("Account did not balance, are you sure ?")))==KMessageBox::No) {
+ clearReconcile();
+ return;
+ }
+ }
+// else
+// {
+// }
+ emit reconcileFinished(true);
+*/
+}
+
+/*
+void KReconcileDlg::updateData(void)
+{
+ // Simply reload the list clearing the status.
+ qDebug("In updateData");
+ m_reconciledTransactions.clear();
+ m_debitsQList.clear();
+ m_creditsQList.clear();
+
+ loadLists();
+ insertTransactions();
+ doDifference();
+}
+*/
+void KReconcileDlg::cancelClicked()
+{
+/*
+ clearReconcile();
+ // Stop the transaction view from being refreshed on
+ // cancel by passing false.
+ emit reconcileFinished(false);
+*/
+}
+
+void KReconcileDlg::resetData(const MyMoneyMoney /* previousBal */, const MyMoneyMoney /* endingBal */, const QDate /* endingDate */, MyMoneyAccount* /* accountIndex */, const MyMoneyFile* /* file */)
+{
+/*
+ m_reconciledTransactions.clear();
+ m_debitsQList.clear();
+ m_creditsQList.clear();
+
+ m_balanced = false;
+
+ m_file = file;
+ m_bankIndex = bankIndex;
+ m_accountIndex = accountIndex;
+ m_endingBalance = endingBal;
+ m_previousBalance = previousBal;
+ m_clearedBalance.setAmount(0.0);
+ m_debitBalance.setAmount(0.0);
+ m_creditBalance.setAmount(0.0);
+ m_endingDate = endingDate;
+
+
+ //totalCreditsLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ //totalDebitsLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ //previousLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ //endingLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+ //differenceLabel->setAlignment(AlignRight | AlignVCenter | ExpandTabs | SingleLine);
+
+
+ endingLabel->setText(KGlobal::locale()->formatMoney(m_clearedBalance.amount(),""));
+
+ previousLabel->setText(KGlobal::locale()->formatMoney(m_endingBalance.amount(),""));
+
+ broughtForwardLabel->setText(KGlobal::locale()->formatMoney(m_previousBalance.amount(),""));
+
+ totalCreditsLabel->setText(i18n("Deposits: ") + KGlobal::locale()->formatMoney(m_creditBalance.amount(),""));
+
+ totalDebitsLabel->setText(i18n("Withdrawals: ") + KGlobal::locale()->formatMoney(m_debitBalance.amount(),""));
+
+ loadLists();
+ insertTransactions();
+*/
+}
+
+void KReconcileDlg::slotTransactionChanged()
+{
+/*
+ reloadLists();
+ insertTransactions();
+ show();
+*/
+}
+
+/** No descriptions */
+void KReconcileDlg::reloadLists()
+{
+/*
+ unsigned int i=0;
+ MyMoneyTransaction *transaction;
+ for (i=0, transaction=m_accountIndex->transactionFirst(); transaction; transaction=m_accountIndex->transactionNext(), i++) {
+ if (transaction->state()!=MyMoneyTransaction::Reconciled) {
+ if (transaction->type() == MyMoneyTransaction::Debit) {
+ transaction->setIndex(i);
+ if(m_debitsQList.find(transaction) < 0)
+ {
+ m_debitsQList.append(transaction);
+ }
+ }
+ else {
+ transaction->setIndex(i);
+ if(m_creditsQList.find(transaction) < 0)
+ {
+ m_creditsQList.append(transaction);
+ }
+ }
+ }
+ }
+
+
+ QListIterator<MyMoneyTransaction> it(m_debitsQList);
+ for ( ; it.current(); ++it) {
+ bool transactionFound = inTransactions(it.current());
+ if(transactionFound == false)
+ m_debitsQList.remove(it.current());
+ }
+
+ QListIterator<MyMoneyTransaction> it2(m_creditsQList);
+ for ( ; it2.current(); ++it2) {
+ bool transactionFound = inTransactions(it2.current());
+ if(transactionFound == false)
+ m_creditsQList.remove(it2.current());
+ }
+*/
+}
+
+
+/** No descriptions */
+bool KReconcileDlg::inTransactions(MyMoneyTransaction * /*credittrans */)
+{
+/*
+ MyMoneyTransaction *transaction;
+ int i = 0;
+ for ( i=0, transaction=m_accountIndex->transactionFirst(); transaction; transaction=m_accountIndex->transactionNext(), i++) {
+ if( credittrans == transaction)
+ return true;
+ }
+*/
+ return false;
+}
+
+/* Not used (yet?)
+bool KReconcileDlg::inCredits(MyMoneyTransaction *transaction)
+{
+ QListIterator<MyMoneyTransaction> it(m_creditsQList);
+ for ( ; it.current(); ++it) {
+ if(transaction == it.current())
+ return true;
+ }
+
+ return false;
+
+}
+*/
+
+/* Not used (yet?)
+bool KReconcileDlg::inDebits(MyMoneyTransaction *transaction)
+{
+ QListIterator<MyMoneyTransaction> it(m_debitsQList);
+ for ( ; it.current(); ++it) {
+ if(transaction == it.current())
+ return true;
+ }
+
+ return false;
+
+}
+*/
+
+void KReconcileDlg::editClicked()
+{
+/*
+ hide();
+*/
+}
+
+void KReconcileDlg::resizeEvent(QResizeEvent* /* e */)
+{
+/*
+ debitListView->setColumnWidth( 2, debitListView->visibleWidth()
+ - debitListView->columnWidth(0)
+ - debitListView->columnWidth(1)
+ - debitListView->columnWidth(3)
+ - debitListView->columnWidth(4));
+
+ creditListView->setColumnWidth( 2, creditListView->visibleWidth()
+ - creditListView->columnWidth(0)
+ - creditListView->columnWidth(1)
+ - creditListView->columnWidth(3)
+ - creditListView->columnWidth(4));
+
+ // call base class resizeEvent()
+ KReconcileDlgDecl::resizeEvent(e);
+*/
+}
+
+#include "kreconciledlg.moc"
diff --git a/kmymoney2/dialogs/kreconciledlg.h b/kmymoney2/dialogs/kreconciledlg.h
new file mode 100644
index 0000000..9ddb079
--- /dev/null
+++ b/kmymoney2/dialogs/kreconciledlg.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ kreconciledlg.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRECONCILEDLG_H
+#define KRECONCILEDLG_H
+
+#include <qlabel.h>
+#include <klistview.h>
+#include <qpushbutton.h>
+
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneymoney.h"
+
+#include "kreconciledlgdecl.h"
+
+// This dialog is used for reconciliation.
+class KReconcileDlg : public KReconcileDlgDecl {
+ Q_OBJECT
+public:
+ KReconcileDlg(const MyMoneyMoney previousBal, const MyMoneyMoney endingBal, const QDate endingDate, MyMoneyAccount *accountIndex, const MyMoneyFile* file, QWidget *parent=0, const char *name=0);
+ ~KReconcileDlg();
+// void updateData(void);
+ void resetData(const MyMoneyMoney previousBal, const MyMoneyMoney endingBal, const QDate endingDate, MyMoneyAccount *accountIndex, const MyMoneyFile* file);
+ /** No descriptions */
+
+protected:
+ void resizeEvent(QResizeEvent*);
+
+protected slots:
+ void slotDebitSelected(QListViewItem*, const QPoint&, int);
+ void slotCreditSelected(QListViewItem*, const QPoint&, int);
+ void finishClicked();
+ void cancelClicked();
+ /** No descriptions */
+ void editClicked();
+
+signals:
+ void reconcileFinished(bool);
+
+private:
+ MyMoneyMoney m_endingBalance;
+ MyMoneyMoney m_previousBalance;
+ MyMoneyMoney m_clearedBalance;
+ MyMoneyMoney m_debitBalance;
+ MyMoneyMoney m_creditBalance;
+
+ MyMoneyFile* m_file;
+ //MyMoneyBank m_bankIndex;
+ MyMoneyAccount *m_accountIndex;
+
+ QList<MyMoneyTransaction> m_debitsQList;
+ QList<MyMoneyTransaction> m_creditsQList;
+ QList<MyMoneyTransaction> m_reconciledTransactions;
+
+ bool m_balanced; // true when the account is balanced (determined by doDifference)
+
+ QDate m_endingDate;
+
+ void loadLists(void);
+ void insertTransactions(void);
+ void doDifference(void);
+ /** No descriptions */
+ bool inTransactions(MyMoneyTransaction *debittrans);
+ /** No descriptions */
+ bool inDebits(MyMoneyTransaction *transaction);
+ /** No descriptions */
+ bool inCredits(MyMoneyTransaction *transaction);
+
+ void reloadLists();
+ void clearReconcile();
+
+public slots: // Public slots
+ /** No descriptions */
+ void slotTransactionChanged();
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kreconciledlgdecl.ui b/kmymoney2/dialogs/kreconciledlgdecl.ui
new file mode 100644
index 0000000..c75ceed
--- /dev/null
+++ b/kmymoney2/dialogs/kreconciledlgdecl.ui
@@ -0,0 +1,709 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KReconcileDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>reconcileDlg</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Reconciliation Dialog</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>descriptionLabel</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="text">
+ <string>This dialog will assist in helping you to balance your account.
+
+Click on an appropriate transaction within one of the two list views to mark it as reconciled. To create a transaction or edit
+a transaction you can return to the register by clicking on the Edit Transactions button.
+
+Your account is balanced when the Difference is Zero. Click on the Finish button to save the reconciled transactions.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout27</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout25</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>420</width>
+ <height>0</height>
+ </size>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>420</width>
+ <height>15</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Withdrawals</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>debitListView</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>420</width>
+ <height>100</height>
+ </size>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout26</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_3_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>15</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Deposits</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>creditListView</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>420</width>
+ <height>100</height>
+ </size>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>totalDebitsLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>$</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>totalCreditsLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>$</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>infoGroup</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Balance</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Previous Balance:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>broughtForwardLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Ending Balance:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>previousLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Cleared Balance:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>endingLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Difference:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>differenceLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonEdit</cstring>
+ </property>
+ <property name="text">
+ <string>Edit Transactions...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>Finish</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>reconcileDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>reconcileDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kreportconfigurationfilterdlg.cpp b/kmymoney2/dialogs/kreportconfigurationfilterdlg.cpp
new file mode 100644
index 0000000..949601d
--- /dev/null
+++ b/kmymoney2/dialogs/kreportconfigurationfilterdlg.cpp
@@ -0,0 +1,687 @@
+/***************************************************************************
+ kreportconfigurationdlg.cpp - description
+ -------------------
+ begin : Mon Jun 21 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qvariant.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qlayout.h>
+#include <qspinbox.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qtabwidget.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kapplication.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+#include <klistview.h>
+#include <kcombobox.h>
+#include <kguiitem.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kstdguiitem.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kreportconfigurationfilterdlg.h"
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/kmymoneycombo.h>
+#include "../widgets/kmymoneyreportconfigtab1decl.h"
+#include "../widgets/kmymoneyreportconfigtab2decl.h"
+#include "../widgets/kmymoneyreportconfigtab3decl.h"
+#include "../widgets/kmymoneyreportconfigtabchartdecl.h"
+
+KReportConfigurationFilterDlg::KReportConfigurationFilterDlg(
+ MyMoneyReport report, QWidget *parent, const char *name)
+ : KFindTransactionDlg(parent, name),
+ m_tab2(0),
+ m_tab3(0),
+ m_tabChart(0),
+ m_initialState(report),
+ m_currentState(report)
+{
+ //
+ // Rework labelling
+ //
+
+ setCaption( i18n( "Report Configuration" ) );
+ delete TextLabel1;
+
+ //
+ // Rework the buttons
+ //
+
+ // the Ok button is always enabled
+ disconnect(SIGNAL(selectionEmpty(bool)));
+ m_searchButton->setGuiItem( KStdGuiItem::ok() );
+ m_searchButton->setEnabled(true);
+
+ // reconnect the close button
+ m_closeButton->disconnect();
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+ //
+ // Add new tabs
+ //
+
+ m_tab1 = new kMyMoneyReportConfigTab1Decl( m_criteriaTab, "kMyMoneyReportConfigTab1" );
+ m_criteriaTab->insertTab( m_tab1, i18n("Report"), 0 );
+
+ if ( m_initialState.reportType() == MyMoneyReport::ePivotTable )
+ {
+ m_tab2 = new kMyMoneyReportConfigTab2Decl( m_criteriaTab, "kMyMoneyReportConfigTab2" );
+ m_criteriaTab->insertTab( m_tab2, i18n( "Rows/Columns"), 1 );
+ connect(m_tab2->m_comboRows, SIGNAL(highlighted(int)), this, SLOT(slotRowTypeChanged(int)));
+ connect(m_tab2->m_comboColumns, SIGNAL(activated(int)), this, SLOT(slotColumnTypeChanged(int)));
+ //control the state of the includeTransfer check
+ connect(m_categoriesView, SIGNAL(stateChanged()), this, SLOT(slotUpdateCheckTransfers()));
+
+#ifdef HAVE_KDCHART
+ m_tabChart = new kMyMoneyReportConfigTabChartDecl( m_criteriaTab, "kMyMoneyReportConfigTabChart" );
+ m_criteriaTab->insertTab( m_tabChart, i18n( "Chart"), 2 );
+#endif
+ }
+ else if ( m_initialState.reportType() == MyMoneyReport::eQueryTable )
+ {
+ // eInvestmentHoldings is a special-case report, and you cannot configure the
+ // rows & columns of that report.
+ if ( m_initialState.rowType() < MyMoneyReport::eAccountByTopAccount )
+ {
+ m_tab3 = new kMyMoneyReportConfigTab3Decl( m_criteriaTab, "kMyMoneyReportConfigTab3" );
+ m_criteriaTab->insertTab( m_tab3, i18n("Rows/Columns"), 1 );
+ }
+ }
+
+ m_criteriaTab->showPage( m_tab1 );
+ m_criteriaTab->setMinimumSize( 500,200 );
+
+ QValueList<MyMoneyBudget> list = MyMoneyFile::instance()->budgetList();
+ QValueList<MyMoneyBudget>::const_iterator it_b;
+ for(it_b = list.begin(); it_b != list.end(); ++it_b) {
+ m_budgets.push_back(*it_b);
+ }
+
+ //
+ // Now set up the widgets with proper values
+ //
+ slotReset();
+}
+
+KReportConfigurationFilterDlg::~KReportConfigurationFilterDlg()
+{
+}
+
+void KReportConfigurationFilterDlg::slotSearch(void)
+{
+ // setup the filter from the dialog widgets
+ setupFilter();
+
+ // Copy the m_filter over to the filter part of m_currentConfig.
+ m_currentState.assignFilter(m_filter);
+
+ // Then extract the report properties
+ m_currentState.setName( m_tab1->m_editName->text() );
+ m_currentState.setComment( m_tab1->m_editComment->text() );
+ m_currentState.setConvertCurrency( m_tab1->m_checkCurrency->isChecked() );
+ m_currentState.setFavorite( m_tab1->m_checkFavorite->isChecked() );
+
+ if ( m_tab2 )
+ {
+ MyMoneyReport::EDetailLevel dl[4] = { MyMoneyReport::eDetailAll, MyMoneyReport::eDetailTop, MyMoneyReport::eDetailGroup, MyMoneyReport::eDetailTotal };
+
+ m_currentState.setDetailLevel( dl[m_tab2->m_comboDetail->currentItem()] );
+
+ // modify the rowtype only if the widget is enabled
+ if(m_tab2->m_comboRows->isEnabled()) {
+ MyMoneyReport::ERowType rt[2] = { MyMoneyReport::eExpenseIncome, MyMoneyReport::eAssetLiability };
+ m_currentState.setRowType( rt[m_tab2->m_comboRows->currentItem()] );
+ }
+
+ m_currentState.setShowingRowTotals(false);
+ if(m_tab2->m_comboRows->currentItem() == 0)
+ m_currentState.setShowingRowTotals(m_tab2->m_checkTotalColumn->isChecked());
+
+ MyMoneyReport::EColumnType ct[6] = { MyMoneyReport::eDays, MyMoneyReport::eWeeks, MyMoneyReport::eMonths, MyMoneyReport::eBiMonths, MyMoneyReport::eQuarters, MyMoneyReport::eYears };
+ bool dy[6] = { true, true, false, false, false, false };
+ m_currentState.setColumnType( ct[m_tab2->m_comboColumns->currentItem()] );
+
+ //TODO (Ace) This should be implicit in the call above. MMReport needs fixin'
+ m_currentState.setColumnsAreDays( dy[m_tab2->m_comboColumns->currentItem()] );
+
+ m_currentState.setIncludingSchedules( m_tab2->m_checkScheduled->isChecked() );
+
+ m_currentState.setIncludingTransfers( m_tab2->m_checkTransfers->isChecked() );
+
+ m_currentState.setIncludingUnusedAccounts( m_tab2->m_checkUnused->isChecked() );
+
+ if(m_tab2->m_comboBudget->isEnabled()) {
+ m_currentState.setBudget(m_budgets[m_tab2->m_comboBudget->currentItem()].id(), m_initialState.rowType() == MyMoneyReport::eBudgetActual);
+ } else {
+ m_currentState.setBudget(QString(), false);
+ }
+
+ //set moving average days
+ if(m_tab2->m_movingAverageDays->isEnabled()) {
+ m_currentState.setMovingAverageDays( m_tab2->m_movingAverageDays->value() );
+ }
+ }
+ else if ( m_tab3 )
+ {
+ MyMoneyReport::ERowType rtq[7] = { MyMoneyReport::eCategory, MyMoneyReport::eTopCategory, MyMoneyReport::ePayee, MyMoneyReport::eAccount, MyMoneyReport::eTopAccount, MyMoneyReport::eMonth, MyMoneyReport::eWeek };
+ m_currentState.setRowType( rtq[m_tab3->m_comboOrganizeBy->currentItem()] );
+
+ unsigned qc = MyMoneyReport::eQCnone;
+
+ if (m_currentState.queryColumns() & MyMoneyReport::eQCloan)
+ // once a loan report, always a loan report
+ qc = MyMoneyReport::eQCloan;
+
+ if ( m_tab3->m_checkNumber->isChecked() )
+ qc |= MyMoneyReport::eQCnumber;
+ if ( m_tab3->m_checkPayee->isChecked() )
+ qc |= MyMoneyReport::eQCpayee;
+ if ( m_tab3->m_checkCategory->isChecked() )
+ qc |= MyMoneyReport::eQCcategory;
+ if ( m_tab3->m_checkMemo->isChecked() )
+ qc |= MyMoneyReport::eQCmemo;
+ if ( m_tab3->m_checkAccount->isChecked() )
+ qc |= MyMoneyReport::eQCaccount;
+ if ( m_tab3->m_checkReconciled->isChecked() )
+ qc |= MyMoneyReport::eQCreconciled;
+ if ( m_tab3->m_checkAction->isChecked() )
+ qc |= MyMoneyReport::eQCaction;
+ if ( m_tab3->m_checkShares->isChecked() )
+ qc |= MyMoneyReport::eQCshares;
+ if ( m_tab3->m_checkPrice->isChecked() )
+ qc |= MyMoneyReport::eQCprice;
+ if( m_tab3->m_checkBalance->isChecked() )
+ qc |= MyMoneyReport::eQCbalance;
+
+ m_currentState.setQueryColumns(static_cast<MyMoneyReport::EQueryColumns>(qc));
+
+ m_currentState.setTax( m_tab3->m_checkTax->isChecked() );
+ m_currentState.setInvestmentsOnly( m_tab3->m_checkInvestments->isChecked() );
+ m_currentState.setLoansOnly( m_tab3->m_checkLoans->isChecked() );
+
+ m_currentState.setDetailLevel(m_tab3->m_checkHideSplitDetails->isChecked() ?
+ MyMoneyReport::eDetailNone : MyMoneyReport::eDetailAll);
+ }
+
+ if ( m_tabChart )
+ {
+ MyMoneyReport::EChartType ct[5] = { MyMoneyReport::eChartLine, MyMoneyReport::eChartBar, MyMoneyReport::eChartStackedBar, MyMoneyReport::eChartPie, MyMoneyReport::eChartRing };
+ m_currentState.setChartType( ct[m_tabChart->m_comboType->currentItem()] );
+
+ m_currentState.setChartGridLines( m_tabChart->m_checkGridLines->isChecked() );
+ m_currentState.setChartDataLabels( m_tabChart->m_checkValues->isChecked() );
+ m_currentState.setChartByDefault( m_tabChart->m_checkShowChart->isChecked() );
+ m_currentState.setChartLineWidth( m_tabChart->m_lineWidth->value() );
+ }
+
+ // setup the date lock
+ MyMoneyTransactionFilter::dateOptionE range = m_dateRange->currentItem();
+ m_currentState.setDateFilter(range);
+
+ done(true);
+}
+
+void KReportConfigurationFilterDlg::slotRowTypeChanged(int row)
+{
+ m_tab2->m_checkTotalColumn->setEnabled(row == 0);
+}
+
+void KReportConfigurationFilterDlg::slotColumnTypeChanged(int row)
+{
+ if(m_tab2->m_comboBudget->isEnabled() && row < 2) {
+ m_tab2->m_comboColumns->setCurrentItem(2);
+ }
+}
+
+void KReportConfigurationFilterDlg::slotReset(void)
+{
+ //
+ // Set up the widget from the initial filter
+ //
+ m_currentState = m_initialState;
+
+ //
+ // Report Properties
+ //
+
+ m_tab1->m_editName->setText( m_initialState.name() );
+ m_tab1->m_editComment->setText( m_initialState.comment() );
+ m_tab1->m_checkCurrency->setChecked( m_initialState.isConvertCurrency() );
+ m_tab1->m_checkFavorite->setChecked( m_initialState.isFavorite() );
+
+ if ( m_tab2 )
+ {
+ switch ( m_initialState.detailLevel() )
+ {
+ case MyMoneyReport::eDetailNone:
+ case MyMoneyReport::eDetailEnd:
+ case MyMoneyReport::eDetailAll:
+ m_tab2->m_comboDetail->setCurrentItem(0);
+ break;
+ case MyMoneyReport::eDetailTop:
+ m_tab2->m_comboDetail->setCurrentItem(1);
+ break;
+ case MyMoneyReport::eDetailGroup:
+ m_tab2->m_comboDetail->setCurrentItem(2);
+ break;
+ case MyMoneyReport::eDetailTotal:
+ m_tab2->m_comboDetail->setCurrentItem(3);
+ break;
+ }
+
+ switch(m_initialState.rowType()) {
+ case MyMoneyReport::eExpenseIncome:
+ case MyMoneyReport::eBudget:
+ case MyMoneyReport::eBudgetActual:
+ m_tab2->m_comboRows->setCurrentItem(0); // income / expense
+ break;
+ default:
+ m_tab2->m_comboRows->setCurrentItem(1); // asset / liability
+ break;
+ }
+ m_tab2->m_checkTotalColumn->setChecked(m_initialState.isShowingRowTotals());
+
+ slotRowTypeChanged(m_tab2->m_comboRows->currentItem());
+
+ if ( m_initialState.isColumnsAreDays() )
+ {
+ switch ( m_initialState.columnType() )
+ {
+ case MyMoneyReport::eNoColumns:
+ case MyMoneyReport::eDays:
+ m_tab2->m_comboColumns->setCurrentItem(0);
+ break;
+ case MyMoneyReport::eWeeks:
+ m_tab2->m_comboColumns->setCurrentItem(1);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch ( m_initialState.columnType() )
+ {
+ case MyMoneyReport::eNoColumns:
+ case MyMoneyReport::eMonths:
+ m_tab2->m_comboColumns->setCurrentItem(2);
+ break;
+ case MyMoneyReport::eBiMonths:
+ m_tab2->m_comboColumns->setCurrentItem(3);
+ break;
+ case MyMoneyReport::eQuarters:
+ m_tab2->m_comboColumns->setCurrentItem(4);
+ break;
+ case MyMoneyReport::eYears:
+ m_tab2->m_comboColumns->setCurrentItem(5);
+ break;
+ default:
+ break;
+ }
+ }
+
+ //load budgets combo
+ if(m_initialState.rowType() == MyMoneyReport::eBudget
+ || m_initialState.rowType() == MyMoneyReport::eBudgetActual) {
+ m_tab2->m_comboRows->setEnabled(false);
+ m_tab2->m_budgetFrame->setEnabled(!m_budgets.empty());
+ QValueVector<MyMoneyBudget>::const_iterator it_b;
+ int i = 0;
+ for(it_b = m_budgets.begin(); it_b != m_budgets.end(); ++it_b) {
+ m_tab2->m_comboBudget->insertItem((*it_b).name(), i);
+ //set the current selected item
+ if( (m_initialState.budget() == "Any" && (*it_b).budgetStart().year() == QDate::currentDate().year())
+ || m_initialState.budget() == (*it_b).id())
+ m_tab2->m_comboBudget->setCurrentItem(i);
+ i++;
+ }
+ }
+
+ //set moving average days spinbox
+ m_tab2->m_movingAverageDays->setEnabled( m_initialState.isIncludingMovingAverage() );
+ if(m_initialState.isIncludingMovingAverage() ) {
+ m_tab2->m_movingAverageDays->setValue( m_initialState.movingAverageDays() );
+ }
+
+ m_tab2->m_checkScheduled->setChecked( m_initialState.isIncludingSchedules() );
+ m_tab2->m_checkTransfers->setChecked( m_initialState.isIncludingTransfers() );
+ m_tab2->m_checkUnused->setChecked( m_initialState.isIncludingUnusedAccounts() );
+ }
+ else if ( m_tab3 )
+ {
+ switch ( m_initialState.rowType() )
+ {
+ case MyMoneyReport::eNoColumns:
+ case MyMoneyReport::eCategory:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(0);
+ break;
+ case MyMoneyReport::eTopCategory:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(1);
+ break;
+ case MyMoneyReport::ePayee:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(2);
+ break;
+ case MyMoneyReport::eAccount:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(3);
+ break;
+ case MyMoneyReport::eTopAccount:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(4);
+ break;
+ case MyMoneyReport::eMonth:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(5);
+ break;
+ case MyMoneyReport::eWeek:
+ m_tab3->m_comboOrganizeBy->setCurrentItem(6);
+ break;
+ default:
+ throw new MYMONEYEXCEPTION("KReportConfigurationFilterDlg::slotReset(): QueryTable report has invalid rowtype");
+ }
+
+ unsigned qc = m_initialState.queryColumns();
+ m_tab3->m_checkNumber->setChecked(qc & MyMoneyReport::eQCnumber);
+ m_tab3->m_checkPayee->setChecked(qc & MyMoneyReport::eQCpayee);
+ m_tab3->m_checkCategory->setChecked(qc & MyMoneyReport::eQCcategory);
+ m_tab3->m_checkMemo->setChecked(qc & MyMoneyReport::eQCmemo);
+ m_tab3->m_checkAccount->setChecked(qc & MyMoneyReport::eQCaccount);
+ m_tab3->m_checkReconciled->setChecked(qc & MyMoneyReport::eQCreconciled);
+ m_tab3->m_checkAction->setChecked(qc & MyMoneyReport::eQCaction);
+ m_tab3->m_checkShares->setChecked(qc & MyMoneyReport::eQCshares);
+ m_tab3->m_checkPrice->setChecked(qc & MyMoneyReport::eQCprice);
+ m_tab3->m_checkBalance->setChecked(qc & MyMoneyReport::eQCbalance);
+
+ m_tab3->m_checkTax->setChecked( m_initialState.isTax() );
+ m_tab3->m_checkInvestments->setChecked( m_initialState.isInvestmentsOnly() );
+ m_tab3->m_checkLoans->setChecked( m_initialState.isLoansOnly() );
+
+ m_tab3->m_checkHideSplitDetails->setChecked
+ (m_initialState.detailLevel() == MyMoneyReport::eDetailNone);
+ }
+
+ if ( m_tabChart )
+ {
+ switch( m_initialState.chartType() )
+ {
+ case MyMoneyReport::eChartNone:
+ case MyMoneyReport::eChartLine:
+ m_tabChart->m_comboType->setCurrentItem(0);
+ break;
+ case MyMoneyReport::eChartBar:
+ m_tabChart->m_comboType->setCurrentItem(1);
+ break;
+ case MyMoneyReport::eChartStackedBar:
+ m_tabChart->m_comboType->setCurrentItem(2);
+ break;
+ case MyMoneyReport::eChartPie:
+ m_tabChart->m_comboType->setCurrentItem(3);
+ break;
+ case MyMoneyReport::eChartRing:
+ m_tabChart->m_comboType->setCurrentItem(4);
+ break;
+ case MyMoneyReport::eChartEnd:
+ throw new MYMONEYEXCEPTION("KReportConfigurationFilterDlg::slotReset(): Report has invalid charttype");
+ }
+ m_tabChart->m_checkGridLines->setChecked(m_initialState.isChartGridLines());
+ m_tabChart->m_checkValues->setChecked(m_initialState.isChartDataLabels());
+ m_tabChart->m_checkShowChart->setChecked(m_initialState.isChartByDefault());
+ m_tabChart->m_lineWidth->setValue(m_initialState.chartLineWidth());
+ }
+
+ //
+ // Text Filter
+ //
+
+ QRegExp textfilter;
+ if ( m_initialState.textFilter(textfilter))
+ {
+ m_textEdit->setText(textfilter.pattern());
+ m_caseSensitive->setChecked(textfilter.caseSensitive());
+ m_regExp->setChecked(!textfilter.wildcard());
+ m_textNegate->setCurrentItem(m_initialState.isInvertingText());
+ }
+
+ //
+ // Type & State Filters
+ //
+
+ int type;
+ if ( m_initialState.firstType(type) )
+ m_typeBox->setCurrentItem(type);
+
+ int state;
+ if ( m_initialState.firstState(state) )
+ m_stateBox->setCurrentItem(state);
+
+ //
+ // Number Filter
+ //
+
+ QString nrFrom, nrTo;
+ if ( m_initialState.numberFilter(nrFrom, nrTo) )
+ {
+ if ( nrFrom == nrTo )
+ {
+ m_nrEdit->setEnabled(true);
+ m_nrFromEdit->setEnabled(false);
+ m_nrToEdit->setEnabled(false);
+ m_nrEdit->setText(nrFrom);
+ m_nrFromEdit->setText(QString());
+ m_nrToEdit->setText(QString());
+ m_nrButton->setChecked(true);
+ m_nrRangeButton->setChecked(false);
+ }
+ else
+ {
+ m_nrEdit->setEnabled(false);
+ m_nrFromEdit->setEnabled(true);
+ m_nrToEdit->setEnabled(false);
+ m_nrEdit->setText(QString());
+ m_nrFromEdit->setText(nrFrom);
+ m_nrToEdit->setText(nrTo);
+ m_nrButton->setChecked(false);
+ m_nrRangeButton->setChecked(true);
+ }
+ }
+ else
+ {
+ m_nrEdit->setEnabled(true);
+ m_nrFromEdit->setEnabled(false);
+ m_nrToEdit->setEnabled(false);
+ m_nrEdit->setText(QString());
+ m_nrFromEdit->setText(QString());
+ m_nrToEdit->setText(QString());
+ m_nrButton->setChecked(true);
+ m_nrRangeButton->setChecked(false);
+ }
+
+ //
+ // Amount Filter
+ //
+
+ MyMoneyMoney from, to;
+ if ( m_initialState.amountFilter(from,to) ) // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&);
+ {
+ if ( from == to )
+ {
+ m_amountEdit->setEnabled(true);
+ m_amountFromEdit->setEnabled(false);
+ m_amountToEdit->setEnabled(false);
+ m_amountEdit->loadText(QString::number(from.toDouble()));
+ m_amountFromEdit->loadText(QString());
+ m_amountToEdit->loadText(QString());
+ m_amountButton->setChecked(true);
+ m_amountRangeButton->setChecked(false);
+ }
+ else
+ {
+ m_amountEdit->setEnabled(false);
+ m_amountFromEdit->setEnabled(true);
+ m_amountToEdit->setEnabled(true);
+ m_amountEdit->loadText(QString());
+ m_amountFromEdit->loadText(QString::number(from.toDouble()));
+ m_amountToEdit->loadText(QString::number(to.toDouble()));
+ m_amountButton->setChecked(false);
+ m_amountRangeButton->setChecked(true);
+ }
+ }
+ else
+ {
+ m_amountEdit->setEnabled(true);
+ m_amountFromEdit->setEnabled(false);
+ m_amountToEdit->setEnabled(false);
+ m_amountEdit->loadText(QString());
+ m_amountFromEdit->loadText(QString());
+ m_amountToEdit->loadText(QString());
+ m_amountButton->setChecked(true);
+ m_amountRangeButton->setChecked(false);
+ }
+
+ //
+ // Payees Filter
+ //
+
+ QStringList payees;
+ if ( m_initialState.payees(payees) )
+ {
+ if ( payees.empty() )
+ {
+ m_emptyPayeesButton->setChecked(true);
+ }
+ else
+ {
+ selectAllItems(m_payeesView, false);
+ selectItems(m_payeesView,payees,true);
+ }
+ }
+ else
+ {
+ selectAllItems(m_payeesView, true);
+ }
+
+ //
+ // Accounts Filter
+ //
+
+ QStringList accounts;
+ if ( m_initialState.accounts(accounts) )
+ {
+ m_accountsView->selectAllItems(false);
+ m_accountsView->selectItems(accounts,true);
+ }
+ else
+ m_accountsView->selectAllItems(true);
+
+ //
+ // Categories Filter
+ //
+
+ if ( m_initialState.categories(accounts) )
+ {
+ m_categoriesView->selectAllItems(false);
+ m_categoriesView->selectItems(accounts,true);
+ }
+ else
+ m_categoriesView->selectAllItems(true);
+
+ //
+ // Date Filter
+ //
+
+ // the following call implies a call to slotUpdateSelections,
+ // that's why we call it last
+
+ m_initialState.updateDateFilter();
+ QDate dateFrom, dateTo;
+ if ( m_initialState.dateFilter( dateFrom, dateTo ) )
+ {
+ if(m_initialState.isUserDefined()) {
+ m_dateRange->setCurrentItem(MyMoneyTransactionFilter::userDefined);
+ m_fromDate->setDate(dateFrom);
+ m_toDate->setDate(dateTo);
+ } else {
+ m_fromDate->setDate(dateFrom);
+ m_toDate->setDate(dateTo);
+ KFindTransactionDlg::slotDateChanged();
+ }
+ }
+ else
+ {
+ m_dateRange->setCurrentItem(MyMoneyTransactionFilter::allDates);
+ slotDateRangeChanged(MyMoneyTransactionFilter::allDates);
+ }
+
+ slotRightSize();
+}
+
+void KReportConfigurationFilterDlg::slotDateChanged(void)
+{
+ if(m_dateRange->currentItem() != MyMoneyTransactionFilter::userDefined) {
+ KFindTransactionDlg::slotDateChanged();
+ }
+ slotUpdateSelections();
+}
+
+void KReportConfigurationFilterDlg::slotShowHelp(void)
+{
+ kapp->invokeHelp("details.reports.config");
+}
+
+//TODO Fix the reports and engine to include transfers even if categories are filtered - bug #1523508
+void KReportConfigurationFilterDlg::slotUpdateCheckTransfers(void)
+{
+ if(!m_categoriesView->allItemsSelected()) {
+ m_tab2->m_checkTransfers->setChecked(false);
+ m_tab2->m_checkTransfers->setDisabled(true);
+ } else {
+ m_tab2->m_checkTransfers->setEnabled(true);
+ }
+}
+
+#include "kreportconfigurationfilterdlg.moc"
diff --git a/kmymoney2/dialogs/kreportconfigurationfilterdlg.h b/kmymoney2/dialogs/kreportconfigurationfilterdlg.h
new file mode 100644
index 0000000..56e398d
--- /dev/null
+++ b/kmymoney2/dialogs/kreportconfigurationfilterdlg.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ kreportconfigurationdlg.h - description
+ -------------------
+ begin : Mon Jun 21 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KREPORTCONFIGURATIONFILTERDLG_H
+#define KREPORTCONFIGURATIONFILTERDLG_H
+
+#include <qvaluevector.h>
+
+#include "../dialogs/kfindtransactiondlg.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneybudget.h"
+
+class kMyMoneyReportConfigTab1Decl;
+class kMyMoneyReportConfigTab2Decl;
+class kMyMoneyReportConfigTab3Decl;
+class kMyMoneyReportConfigTabChartDecl;
+class MyMoneyBudget;
+
+/**
+ * @author Ace Jones
+ */
+class KReportConfigurationFilterDlg : public KFindTransactionDlg
+{
+Q_OBJECT
+public:
+ KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent = 0, const char *name = 0);
+ ~KReportConfigurationFilterDlg();
+
+ const MyMoneyReport& getConfig(void) const { return m_currentState; }
+
+protected:
+ kMyMoneyReportConfigTab1Decl* m_tab1;
+ kMyMoneyReportConfigTab2Decl* m_tab2;
+ kMyMoneyReportConfigTab3Decl* m_tab3;
+ kMyMoneyReportConfigTabChartDecl* m_tabChart;
+
+ MyMoneyReport m_initialState;
+ MyMoneyReport m_currentState;
+
+protected slots:
+ void slotRowTypeChanged(int);
+ void slotColumnTypeChanged(int);
+ void slotReset(void);
+ void slotSearch(void);
+ void slotShowHelp(void);
+ /**
+ * This is to enable/disable the check to Include Transfers based on whether Categories are filtered or not.
+ * This is because if Categories are filtered, transfers will not be included anyway
+ */
+ void slotUpdateCheckTransfers(void);
+
+ virtual void slotDateChanged(void);
+
+private:
+ QValueVector<MyMoneyBudget> m_budgets;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/ksecuritylisteditor.cpp b/kmymoney2/dialogs/ksecuritylisteditor.cpp
new file mode 100644
index 0000000..ee4c486
--- /dev/null
+++ b/kmymoney2/dialogs/ksecuritylisteditor.cpp
@@ -0,0 +1,220 @@
+/***************************************************************************
+ ksecuritylisteditor.cpp - description
+ -------------------
+ begin : Wed Dec 16 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <klistview.h>
+#include <kguiitem.h>
+#include <kiconloader.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksecuritylisteditor.h"
+
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../dialogs/knewinvestmentwizard.h"
+
+#include "../kmymoneyutils.h"
+
+#define ID_COL 0
+#define TYPE_COL 1
+#define NAME_COL 2
+#define SYMBOL_COL 3
+#define MARKET_COL 4
+#define CURR_COL 5
+#define ACCFRACT_COL 6
+#define CASHFRACT_COL 7
+
+#define CURRENCY_MARKET QString("ISO 4217")
+
+KSecurityListEditor::KSecurityListEditor(QWidget *parent, const char *name) :
+ KSecurityListEditorDecl(parent, name)
+{
+ m_listView->setColumnWidth(ID_COL, 0);
+ m_listView->setColumnWidthMode(NAME_COL, QListView::Maximum);
+ m_listView->setColumnWidthMode(ID_COL, QListView::Manual);
+ m_listView->setColumnAlignment(CURR_COL, Qt::AlignHCenter);
+ m_listView->setMultiSelection(false);
+ m_listView->setAllColumnsShowFocus(true);
+
+ KIconLoader *il = KGlobal::iconLoader();
+ KGuiItem removeButtenItem( i18n( "&Delete" ),
+ QIconSet(il->loadIcon("delete", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Delete this entry"),
+ i18n("Remove this security item from the file"));
+ m_deleteButton->setGuiItem(removeButtenItem);
+
+ KGuiItem addButtenItem( i18n( "&Add" ),
+ QIconSet(il->loadIcon("file_new", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Add a new entry"),
+ i18n("Create a new security entry."));
+ m_addButton->setGuiItem(addButtenItem);
+
+ KGuiItem editButtenItem( i18n( "&Edit" ),
+ QIconSet(il->loadIcon("edit", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Modify the selected entry"),
+ i18n("Change the security information of the selected entry."));
+ m_editButton->setGuiItem(editButtenItem);
+
+ KGuiItem okButtenItem( i18n("&Close" ),
+ QIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Close the dialog"),
+ i18n("Use this to close the dialog and return to the application."));
+ m_closeButton->setGuiItem(okButtenItem);
+
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_showCurrencyButton, SIGNAL(toggled(bool)), this, SLOT(slotLoadList()));
+ connect(m_listView, SIGNAL(selectionChanged()), this, SLOT(slotUpdateButtons()));
+
+ connect(m_editButton, SIGNAL(clicked()), this, SLOT(slotEditSecurity()));
+ connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteSecurity()));
+
+ // FIXME for now, the only way to add a new security is to add a new investment
+ m_addButton->hide();
+
+ slotLoadList();
+}
+
+KSecurityListEditor::~KSecurityListEditor()
+{
+}
+
+void KSecurityListEditor::slotLoadList(void)
+{
+ m_listView->clear();
+
+ QValueList<MyMoneySecurity> list = MyMoneyFile::instance()->securityList();
+ QValueList<MyMoneySecurity>::ConstIterator it;
+ if(m_showCurrencyButton->isChecked()) {
+ list += MyMoneyFile::instance()->currencyList();
+ }
+ for(it = list.begin(); it != list.end(); ++it) {
+ KListViewItem* newItem = new KListViewItem(m_listView, QString((*it).id()));
+ fillItem(newItem, *it);
+
+ }
+ slotUpdateButtons();
+}
+
+void KSecurityListEditor::fillItem(QListViewItem* item, const MyMoneySecurity& security)
+{
+ QString market = security.tradingMarket();
+ MyMoneySecurity tradingCurrency;
+ if(security.isCurrency())
+ market = CURRENCY_MARKET;
+ else
+ tradingCurrency = MyMoneyFile::instance()->security(security.tradingCurrency());
+
+ item->setText(TYPE_COL, KMyMoneyUtils::securityTypeToString(security.securityType()));
+ item->setText(NAME_COL, security.name());
+ item->setText(SYMBOL_COL, security.tradingSymbol());
+ item->setText(MARKET_COL, market);
+ item->setText(CURR_COL, tradingCurrency.tradingSymbol());
+ item->setText(ACCFRACT_COL, QString::number(security.smallestAccountFraction()));
+
+ // smallestCashFraction is only applicable for currencies
+ if(security.isCurrency())
+ item->setText(CASHFRACT_COL, QString::number(security.smallestCashFraction()));
+}
+
+void KSecurityListEditor::slotUpdateButtons(void)
+{
+ QListViewItem* item = m_listView->selectedItem();
+
+ if(item) {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(item->text(ID_COL).latin1());
+ m_editButton->setEnabled(item->text(MARKET_COL) != CURRENCY_MARKET);
+ m_deleteButton->setEnabled(!MyMoneyFile::instance()->isReferenced(security));
+
+ } else {
+ m_editButton->setEnabled(false);
+ m_deleteButton->setEnabled(false);
+ }
+}
+
+void KSecurityListEditor::slotEditSecurity(void)
+{
+ QListViewItem* item = m_listView->selectedItem();
+ if(item) {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(item->text(ID_COL).latin1());
+
+ KNewInvestmentWizard dlg(security, this, "KNewInvestmentWizard");
+ if(dlg.exec() == QDialog::Accepted) {
+ dlg.createObjects(QString());
+ security = MyMoneyFile::instance()->security(item->text(ID_COL).latin1());
+ fillItem(item, security);
+ }
+ }
+}
+
+void KSecurityListEditor::slotDeleteSecurity(void)
+{
+ QListViewItem* item = m_listView->selectedItem();
+ if(item) {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(item->text(ID_COL).latin1());
+ QString msg;
+ QString dontAsk;
+ if(security.isCurrency()) {
+ msg = QString("<p>") + i18n("Do you really want to remove the currency <b>%1</b> from the file?</p><i>Note: It is currently not supported to add currencies.</i>").arg(security.name());
+ dontAsk = "DeleteCurrency";
+ } else {
+ msg = QString("<p>") + i18n("Do you really want to remove the %1 <b>%2</b> from the file?").arg(KMyMoneyUtils::securityTypeToString(security.securityType())).arg(security.name());
+ dontAsk = "DeleteSecurity";
+ }
+ if(KMessageBox::questionYesNo(this, msg, i18n("Delete security"), KStdGuiItem::yes(), KStdGuiItem::no(), dontAsk) == KMessageBox::Yes) {
+ MyMoneyFileTransaction ft;
+ try {
+ if(security.isCurrency())
+ MyMoneyFile::instance()->removeCurrency(security);
+ else
+ MyMoneyFile::instance()->removeSecurity(security);
+ ft.commit();
+ slotLoadList();
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+ }
+}
+
+// Make sure, that these definitions are only used within this file
+// this does not seem to be necessary, but when building RPMs the
+// build option 'final' is used and all CPP files are concatenated.
+// So it could well be, that in another CPP file these definitions
+// are also used.
+#undef ID_COL
+#undef TYPE_COL
+#undef NAME_COL
+#undef SYMBOL_COL
+#undef MARKET_COL
+#undef CURR_COL
+#undef ACCFRACT_COL
+#undef CASHFRACT_COL
+
+#include "ksecuritylisteditor.moc"
diff --git a/kmymoney2/dialogs/ksecuritylisteditor.h b/kmymoney2/dialogs/ksecuritylisteditor.h
new file mode 100644
index 0000000..050edbe
--- /dev/null
+++ b/kmymoney2/dialogs/ksecuritylisteditor.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ ksecuritylisteditor.h - description
+ -------------------
+ begin : Wed Dec 16 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSECURITYLISTEDITOR_H
+#define KSECURITYLISTEDITOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksecuritylisteditordecl.h"
+
+#include "../mymoney/mymoneysecurity.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KSecurityListEditor : public KSecurityListEditorDecl
+{
+ Q_OBJECT
+public:
+ KSecurityListEditor(QWidget *parent, const char* name = 0);
+ ~KSecurityListEditor();
+
+protected slots:
+ void slotLoadList(void);
+ void slotUpdateButtons(void);
+ void slotEditSecurity(void);
+ void slotDeleteSecurity(void);
+
+protected:
+ void fillItem(QListViewItem* item, const MyMoneySecurity& security);
+
+};
+
+#endif
diff --git a/kmymoney2/dialogs/ksecuritylisteditordecl.ui b/kmymoney2/dialogs/ksecuritylisteditordecl.ui
new file mode 100644
index 0000000..cbb9999
--- /dev/null
+++ b/kmymoney2/dialogs/ksecuritylisteditordecl.ui
@@ -0,0 +1,262 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KSecurityListEditorDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSecurityListEditorDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>722</width>
+ <height>453</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Security List Editor</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>ID</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Symbol</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Market</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Fraction</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Cash Fraction</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listView</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>51</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_addButton</cstring>
+ </property>
+ <property name="text">
+ <string>Add...</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_editButton</cstring>
+ </property>
+ <property name="text">
+ <string>Edit...</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>Delete...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>110</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_showCurrencyButton</cstring>
+ </property>
+ <property name="text">
+ <string>Show national currencies</string>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>91</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kselectdatabasedlg.cpp b/kmymoney2/dialogs/kselectdatabasedlg.cpp
new file mode 100644
index 0000000..941712c
--- /dev/null
+++ b/kmymoney2/dialogs/kselectdatabasedlg.cpp
@@ -0,0 +1,232 @@
+/***************************************************************************
+ kselectdatabasedlg.cpp
+ -------------------
+ copyright : (C) 2005 by Tony Bloomfield
+ author : Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qapplication.h>
+#include <qsqldatabase.h>
+#include <qfiledialog.h>
+#include <qstatusbar.h>
+#include <qcheckbox.h>
+#include <qcolor.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kapplication.h>
+#include <kurlrequester.h>
+#include <ktextbrowser.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kselectdatabasedlg.h"
+
+KSelectDatabaseDlg::KSelectDatabaseDlg(QWidget *parent, const char *name)
+ : KSelectDatabaseDlgDecl(parent, name) {
+ listDrivers->clear();
+ // list drivers supported by KMM
+ QMap<QString, QString> map = m_map.driverMap();
+ // list drivers installed on system
+ QStringList list = QSqlDatabase::drivers();
+ if (list.count() == 0) {
+ KMessageBox::error (0, i18n("There are no Qt SQL drivers installed in your system.\n"
+ "Please consult documentation for your distro, or visit the Qt web site (www.trolltech.com)"
+ " and search for SQL drivers."),
+ "");
+ setError();
+ } else {
+ QStringList::Iterator it = list.begin();
+ while(it != list.end()) {
+ QString dname = *it;
+ if (map.keys().contains(dname)) { // only display if driver is supported
+ dname = dname + " - " + map[dname];
+ listDrivers->insertItem (dname);
+ }
+ it++;
+ }
+ textDbName->setText ("KMyMoney");
+ textHostName->setText ("localhost");
+ textUserName->setText("");
+ struct passwd * pwd = getpwuid(geteuid());
+ if (pwd != 0)
+ textUserName->setText (QString(pwd->pw_name));
+ textPassword->setText ("");
+ m_requiredFields = new kMandatoryFieldGroup(this);
+ m_requiredFields->setOkButton(buttonOK);
+ m_requiredFields->add(listDrivers);
+ m_requiredFields->add(textDbName);
+ connect (listDrivers, SIGNAL(clicked(QListBoxItem *)),
+ this, SLOT(slotDriverSelected(QListBoxItem *)));
+ connect (buttonSQL, SIGNAL(clicked()), this, SLOT(slotGenerateSQL()));
+ connect (buttonOK, SIGNAL(clicked()), this, SLOT(accept()));
+ checkPreLoad->setChecked(false);
+ buttonSQL->setEnabled(true);
+ }
+ connect (buttonHelp, SIGNAL(clicked()), this, SLOT(slotHelp()));
+ // ensure a driver gets selected; pre-select if only one
+ listDrivers->clearSelection();
+ if (listDrivers->count() == 1) {
+ listDrivers->setSelected(0, true);
+ slotDriverSelected(listDrivers->item(0));
+ }
+}
+
+KSelectDatabaseDlg::KSelectDatabaseDlg(KURL openURL, QWidget *parent, const char *name)
+ : KSelectDatabaseDlgDecl(parent, name) {
+ // here we are re-opening a database from a URL
+ // probably taken from the last-used or recent file list
+ listDrivers->clear();
+ // check that the SQL driver is still available
+ QString driverName = openURL.queryItem("driver");
+ // list drivers installed on system
+ QStringList list = QSqlDatabase::drivers();
+ // list drivers supported by KMM
+ QMap<QString, QString> map = m_map.driverMap();
+ if (!list.contains(driverName)) {
+ KMessageBox::error (0, i18n("Qt SQL driver %1 is no longer installed on your system").arg(driverName),
+ "");
+ setError();
+ } else if (!map.contains(driverName)) {
+ KMessageBox::error (0, i18n("Qt SQL driver %1 is not suported").arg(driverName),
+ "");
+ setError();
+ } else {
+ // fill in the fixed data from the URL
+ listDrivers->insertItem (QString(driverName + " - " + map[driverName]));
+ listDrivers->setSelected(0,true);
+ QString dbName = openURL.path().right(openURL.path().length() - 1); // remove separator slash
+ textDbName->setText (dbName);
+ textHostName->setText (openURL.host());
+ textUserName->setText(openURL.user());
+ // disable all but the password field, coz that's why we're here
+ textDbName->setEnabled(false);
+ listDrivers->setEnabled(false);
+ textHostName->setEnabled(false);
+ textUserName->setEnabled(false);
+ textPassword->setEnabled(true);
+ textPassword->setFocus();
+ buttonSQL->setEnabled(false);
+ // set password as required
+ m_requiredFields = new kMandatoryFieldGroup(this);
+ m_requiredFields->add(textPassword);
+ m_requiredFields->setOkButton(buttonOK);
+
+ connect (buttonOK, SIGNAL(clicked()), this, SLOT(accept()));
+ checkPreLoad->setChecked(false);
+ }
+ connect (buttonHelp, SIGNAL(clicked()), this, SLOT(slotHelp()));
+
+}
+
+KSelectDatabaseDlg::~KSelectDatabaseDlg() {
+ if (m_requiredFields != 0) delete m_requiredFields;
+}
+
+void KSelectDatabaseDlg::setMode (int openMode) {
+ m_mode = openMode;
+ checkPreLoad->setEnabled (openMode == IO_ReadWrite);
+}
+
+const KURL KSelectDatabaseDlg::selectedURL() {
+ KURL url;
+ url.setProtocol("sql");
+ url.setUser(textUserName->text());
+ url.setPass(textPassword->text());
+ url.setHost(textHostName->text());
+ url.setPath("/" + textDbName->text());
+ QString qs = QString("driver=%1")
+ .arg(listDrivers->currentText().section (' ', 0, 0));
+ if (checkPreLoad->isChecked()) qs.append("&options=loadAll");
+ if (!textPassword->text().isEmpty()) qs.append("&secure=yes");
+ url.setQuery(qs);
+ return (url);
+}
+
+void KSelectDatabaseDlg::slotDriverSelected (QListBoxItem *driver) {
+ databaseTypeE dbType = m_map.driverToType(driver->text().section(' ', 0, 0));
+ if (!m_map.isTested(dbType)) {
+ int rc = KMessageBox::warningContinueCancel (0,
+ i18n("Qt SQL driver %1 has not been fully tested in a KMyMoney environment. Please make sure you have adequate backups of your data. Please report any problems to the developer mailing list at kmymoney2-developer@lists.sourceforge.net")
+ .arg(driver->text()),
+ "");
+ if (rc == KMessageBox::Cancel) {
+ listDrivers->clearSelection();
+ return;
+ }
+ }
+
+ if (dbType == Sqlite3){
+ QString dbName = QFileDialog::getOpenFileName(
+ "",
+ i18n("SQLite files (*.sql);; All files (*.*)"),
+ this,
+ "",
+ i18n("Select SQLite file"));
+ if (dbName.isNull()) {
+ listDrivers->setSelected(driver, false);
+ return;
+ } else {
+ textDbName->setText(dbName);
+ }
+ // sql databases do not react to host/user/password; file system permissions must be used
+ textHostName->setEnabled (false);
+ textUserName->setEnabled (false);
+ textPassword->setEnabled(false);
+ } else {
+ textUserName->setEnabled (true); // but not host
+ textHostName->setEnabled (true);
+ textPassword->setEnabled(true);
+ }
+}
+
+void KSelectDatabaseDlg::slotGenerateSQL () {
+ QString fileName = QFileDialog::getSaveFileName(
+ "",
+ i18n("All files (*.*)"),
+ this,
+ "",
+ i18n("Select output file"));
+ if (fileName == "") return;
+ QFile out(fileName);
+ if (!out.open(IO_WriteOnly)) return;
+ QTextStream s(&out);
+ MyMoneyDbDef db;
+ s << db.generateSQL(listDrivers->currentText().section (' ', 0, 0));
+ out.close();
+}
+
+void KSelectDatabaseDlg::slotHelp(void) {
+ kapp->invokeHelp("details.database.selectdatabase");
+}
+
+void KSelectDatabaseDlg::setError() {
+ buttonOK->setEnabled(false);
+ buttonSQL->setEnabled(false);
+ m_requiredFields = 0;
+}
+
+#include "kselectdatabasedlg.moc"
diff --git a/kmymoney2/dialogs/kselectdatabasedlg.h b/kmymoney2/dialogs/kselectdatabasedlg.h
new file mode 100644
index 0000000..bc5a782
--- /dev/null
+++ b/kmymoney2/dialogs/kselectdatabasedlg.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ kselectdatabase.h
+ -------------------
+ copyright : (C) 2005 by Tony Bloomfield
+ author : Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSELECTDATABASEDLG_H
+#define KSELECTDATABASEDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qlistbox.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kurl.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kselectdatabasedlgdecl.h"
+#include "../mymoney/storage/mymoneystoragesql.h"
+#include "kmymoney/kguiutils.h"
+
+class KSelectDatabaseDlg : public KSelectDatabaseDlgDecl
+{
+Q_OBJECT
+public:
+ KSelectDatabaseDlg(QWidget *parent = 0, const char *name = 0);
+ KSelectDatabaseDlg(KURL openURL, QWidget *parent = 0, const char *name = 0);
+ ~KSelectDatabaseDlg();
+ /** Set the mode of this dialog
+ * @param - openMode (IO_ReadWrite = open database; IO_WriteOnly = saveas database)
+ **/
+ void setMode(int openMode);
+ /** Return URL of database
+ * @return - pseudo-URL of database selected by user
+ **/
+ const KURL selectedURL();
+
+public slots:
+ void slotDriverSelected(QListBoxItem *driver);
+ void slotHelp();
+ void slotGenerateSQL();
+private:
+ void setError();
+ int m_mode;
+ MyMoneyDbDrivers m_map;
+ kMandatoryFieldGroup* m_requiredFields;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kselectdatabasedlgdecl.ui b/kmymoney2/dialogs/kselectdatabasedlgdecl.ui
new file mode 100644
index 0000000..4736fb7
--- /dev/null
+++ b/kmymoney2/dialogs/kselectdatabasedlgdecl.ui
@@ -0,0 +1,250 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSelectDatabaseDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSelectDatabaseDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>640</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KMyMoney - Select Database</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="title">
+ <string>CAUTION!</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>&lt;font color="#ff2727"&gt;This software is still in an experimental stage, and there are still some known response time problems. Please be patient; we are working on them.
+As always, please make sure you have adequate backups of your data.&lt;/font&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Database Type</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>listDrivers</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Database Name</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>textDbName</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Host Name</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>textHostName</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>User Name</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>textUserName</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBoxPassword</cstring>
+ </property>
+ <property name="title">
+ <string>Password</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>textPassword</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkPreLoad</cstring>
+ </property>
+ <property name="text">
+ <string>Preload &amp;all data</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonSQL</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Generate SQL</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOK</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Ca&amp;ncel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOK</sender>
+ <signal>released()</signal>
+ <receiver>KSelectDatabaseDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>released()</signal>
+ <receiver>KSelectDatabaseDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kselecttransactionsdlg.cpp b/kmymoney2/dialogs/kselecttransactionsdlg.cpp
new file mode 100644
index 0000000..7a87dc8
--- /dev/null
+++ b/kmymoney2/dialogs/kselecttransactionsdlg.cpp
@@ -0,0 +1,178 @@
+/***************************************************************************
+ kselecttransactionsdlg.cpp
+ -------------------
+ begin : Wed May 16 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kapplication.h>
+#include <kactivelabel.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "kmergetransactionsdlg.h"
+
+KSelectTransactionsDlg::KSelectTransactionsDlg(const MyMoneyAccount& _account, QWidget* parent, const char* name) :
+ KSelectTransactionsDlgDecl(parent, name),
+ m_account(_account)
+{
+ // setup descriptive texts
+ setCaption(i18n("Select Transaction"));
+ m_description->setText(i18n("Select a transaction and press the OK button or use Cancel to select none."));
+
+ // clear current register contents
+ m_register->clear();
+
+ // no selection possible
+ m_register->setSelectionMode(QTable::Single);
+
+ // setup header font
+ QFont font = KMyMoneyGlobalSettings::listHeaderFont();
+ QFontMetrics fm( font );
+ int height = fm.lineSpacing()+6;
+ m_register->horizontalHeader()->setMinimumHeight(height);
+ m_register->horizontalHeader()->setMaximumHeight(height);
+ m_register->horizontalHeader()->setFont(font);
+
+ // setup cell font
+ font = KMyMoneyGlobalSettings::listCellFont();
+ m_register->setFont(font);
+
+ // ... setup the register columns ...
+ m_register->setupRegister(m_account);
+
+ // setup buttons
+ m_helpButton->setGuiItem(KStdGuiItem::help());
+ buttonOk->setGuiItem(KStdGuiItem::ok());
+ buttonCancel->setGuiItem(KStdGuiItem::cancel());
+
+ // default is to need at least one transaction selected
+ buttonOk->setDisabled(true);
+
+ // catch some events from the register
+ m_register->installEventFilter(this);
+
+ connect(m_register, SIGNAL(selectionChanged(const KMyMoneyRegister::SelectedTransactions&)), this, SLOT(slotEnableOk(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(m_register, SIGNAL(editTransaction()), this, SLOT(accept()));
+
+ connect(m_helpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
+}
+
+void KSelectTransactionsDlg::slotEnableOk(const KMyMoneyRegister::SelectedTransactions& list)
+{
+ buttonOk->setEnabled(list.count() != 0);
+}
+
+void KSelectTransactionsDlg::addTransaction(const MyMoneyTransaction& t)
+{
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).accountId() == m_account.id()) {
+ KMyMoneyRegister::Transaction* tr = KMyMoneyRegister::Register::transactionFactory(m_register, t, (*it_s), 0);
+ // force full detail display
+ tr->setNumRowsRegister(tr->numRowsRegister(true));
+ break;
+ }
+ }
+}
+
+int KSelectTransactionsDlg::exec(void)
+{
+ m_register->updateRegister(true);
+ m_register->updateContents();
+
+ m_register->setFocus();
+
+ return KSelectTransactionsDlgDecl::exec();
+}
+
+void KSelectTransactionsDlg::slotHelp(void)
+{
+ // kapp->invokeHelp("details.ledgers.match");
+}
+
+void KSelectTransactionsDlg::show(void)
+{
+ KSelectTransactionsDlgDecl::show();
+ m_register->resize(KMyMoneyRegister::DetailColumn);
+}
+
+void KSelectTransactionsDlg::resizeEvent(QResizeEvent* ev)
+{
+ // don't forget the resizer
+ KSelectTransactionsDlgDecl::resizeEvent(ev);
+
+ // resize the register
+ m_register->resize(KMyMoneyRegister::DetailColumn);
+}
+
+MyMoneyTransaction KSelectTransactionsDlg::transaction(void) const
+{
+ MyMoneyTransaction t;
+
+ QValueList<KMyMoneyRegister::RegisterItem*> list;
+ list = m_register->selectedItems();
+ if(list.count()) {
+ KMyMoneyRegister::Transaction* _t = dynamic_cast<KMyMoneyRegister::Transaction*>(list[0]);
+ if(_t)
+ t = _t->transaction();
+ }
+ return t;
+}
+
+bool KSelectTransactionsDlg::eventFilter(QObject* o, QEvent* e)
+{
+ bool rc = false;
+ QKeyEvent* k;
+
+ if(o == m_register) {
+ switch(e->type()) {
+ case QEvent::KeyPress:
+ k = dynamic_cast<QKeyEvent*>(e);
+ if((k->state() & Qt::KeyButtonMask) == 0) {
+ switch(k->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if(buttonOk->isEnabled()) {
+ accept();
+ rc = true;
+ }
+ // tricky fall through here
+ default:
+ break;
+ }
+ }
+ // tricky fall through here
+ default:
+ break;
+ }
+ }
+ return rc;
+}
+
+#include "kselecttransactionsdlg.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kselecttransactionsdlg.h b/kmymoney2/dialogs/kselecttransactionsdlg.h
new file mode 100644
index 0000000..7bab9eb
--- /dev/null
+++ b/kmymoney2/dialogs/kselecttransactionsdlg.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ kselecttransactionsdlg.h
+ -------------------
+ begin : Wed May 16 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSELECTTRANSACTIONSDLG_H
+#define KSELECTTRANSACTIONSDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QResizeEvent;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/register.h>
+#include <kmymoney/mymoneyaccount.h>
+
+#include "../dialogs/kselecttransactionsdlgdecl.h"
+
+class KSelectTransactionsDlg: public KSelectTransactionsDlgDecl
+{
+ Q_OBJECT
+public:
+ KSelectTransactionsDlg(const MyMoneyAccount& account, QWidget* parent = 0, const char* name = 0);
+
+ /**
+ * Adds the transaction @a t to the dialog
+ */
+ void addTransaction(const MyMoneyTransaction& t);
+ int exec(void);
+ void show(void);
+
+ MyMoneyTransaction transaction(void) const;
+
+ bool eventFilter(QObject* o, QEvent* e);
+
+public slots:
+ virtual void slotHelp();
+
+protected slots:
+ void slotEnableOk(const KMyMoneyRegister::SelectedTransactions& list);
+
+protected:
+ void resizeEvent(QResizeEvent* ev);
+
+private:
+ /**
+ * The account in which the transactions are displayed
+ */
+ MyMoneyAccount m_account;
+};
+
+#endif // KMERGETRANSACTIONSDLG_H
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/dialogs/kselecttransactionsdlgdecl.ui b/kmymoney2/dialogs/kselecttransactionsdlgdecl.ui
new file mode 100644
index 0000000..76d825b
--- /dev/null
+++ b/kmymoney2/dialogs/kselecttransactionsdlgdecl.ui
@@ -0,0 +1,174 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSelectTransactionsDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSelectTransactionsDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>794</width>
+ <height>456</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>xxx</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>m_description</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyRegister::Register">
+ <column>
+ <property name="text">
+ <string>Security</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Details</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>C</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Payment</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Deposit</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Quantity</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Balance</string>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_register</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>3</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="numRows">
+ <number>0</number>
+ </property>
+ <property name="numCols">
+ <number>12</number>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_helpButton</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>430</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KSelectTransactionsDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KSelectTransactionsDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/ksortoptiondlg.ui b/kmymoney2/dialogs/ksortoptiondlg.ui
new file mode 100644
index 0000000..e5606ae
--- /dev/null
+++ b/kmymoney2/dialogs/ksortoptiondlg.ui
@@ -0,0 +1,129 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSortOptionDlg</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSortOptionDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>348</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Sort options</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_useDefault</cstring>
+ </property>
+ <property name="text">
+ <string>Use default</string>
+ </property>
+ </widget>
+ <widget class="TransactionSortOption">
+ <property name="name">
+ <cstring>m_sortOption</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_helpButton</cstring>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>237</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_okButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_okButton</sender>
+ <signal>clicked()</signal>
+ <receiver>KSortOptionDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>m_cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>KSortOptionDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>m_useDefault</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_sortOption</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">ksortoptiondlg.ui.h</include>
+</includes>
+<slots>
+ <slot>setSortOption( const QString &amp; option, const QString &amp; def )</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function returnType="QString">sortOption( void ) const</function>
+ <function>hideDefaultButton( void )</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/ksortoptiondlg.ui.h b/kmymoney2/dialogs/ksortoptiondlg.ui.h
new file mode 100644
index 0000000..62c26b7
--- /dev/null
+++ b/kmymoney2/dialogs/ksortoptiondlg.ui.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kstdguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+void KSortOptionDlg::init()
+{
+ m_okButton->setGuiItem(KStdGuiItem::ok());
+ m_cancelButton->setGuiItem(KStdGuiItem::cancel());
+ m_helpButton->setGuiItem(KStdGuiItem::help());
+}
+
+void KSortOptionDlg::setSortOption(const QString& option, const QString& def)
+{
+ if(option.isEmpty()) {
+ m_sortOption->setSettings(def);
+ m_useDefault->setChecked(true);
+ } else {
+ m_sortOption->setSettings(option);
+ m_useDefault->setChecked(false);
+ }
+}
+
+QString KSortOptionDlg::sortOption(void) const
+{
+ QString rc;
+ if(!m_useDefault->isChecked()) {
+ rc = m_sortOption->settings();
+ }
+ return rc;
+}
+
+void KSortOptionDlg::hideDefaultButton(void)
+{
+ m_useDefault->hide();
+}
+
diff --git a/kmymoney2/dialogs/ksplitcorrectiondlg.ui b/kmymoney2/dialogs/ksplitcorrectiondlg.ui
new file mode 100644
index 0000000..f5d9757
--- /dev/null
+++ b/kmymoney2/dialogs/ksplitcorrectiondlg.ui
@@ -0,0 +1,245 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSplitCorrectionDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSplitCorrectionDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>462</width>
+ <height>292</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Correct splits</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>explanation</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>question</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>How do you want to proceed?</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>continueBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Continue to edit splits</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>changeBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Change total amount of transaction to %1.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>distributeBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Distribute difference of %1 among all splits.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>leaveBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Leave %1 unassigned.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>KSplitCorrectionDlgDecl</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>KSplitCorrectionDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/ksplittransactiondlg.cpp b/kmymoney2/dialogs/ksplittransactiondlg.cpp
new file mode 100644
index 0000000..a197b4c
--- /dev/null
+++ b/kmymoney2/dialogs/ksplittransactiondlg.cpp
@@ -0,0 +1,449 @@
+/***************************************************************************
+ ksplittransactiondlg.cpp - description
+ -------------------
+ begin : Thu Jan 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qtable.h>
+#include <qtimer.h>
+#include <qptrlist.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcursor.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kactivelabel.h>
+#include <kstdguiitem.h>
+#include <kapplication.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksplittransactiondlg.h"
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/mymoneyfile.h>
+
+#include "kmymoneysplittable.h"
+#include "../dialogs/ksplitcorrectiondlg.h"
+
+KSplitTransactionDlg::KSplitTransactionDlg(const MyMoneyTransaction& t,
+ const MyMoneySplit& s,
+ const MyMoneyAccount& acc,
+ const bool amountValid,
+ const bool deposit,
+ const MyMoneyMoney& calculatedValue,
+ const QMap<QString, MyMoneyMoney>& priceInfo,
+ QWidget* parent, const char* name) :
+ KSplitTransactionDlgDecl(parent, name, true),
+ m_account(acc),
+ m_split(s),
+ m_precision(2),
+ m_amountValid(amountValid),
+ m_isDeposit(deposit),
+ m_calculatedValue(calculatedValue)
+{
+ // add icons to buttons
+ KIconLoader *il = KGlobal::iconLoader();
+
+ KGuiItem clearButtenItem( i18n( "Clear &All" ),
+ QIconSet(il->loadIcon("edittrash", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Clear all splits"),
+ i18n("Use this to clear all splits of this transaction"));
+ clearAllBtn->setGuiItem(clearButtenItem);
+
+
+ KGuiItem mergeButtenItem( i18n( "&Merge" ),
+ QIconSet(il->loadIcon("math_sum", KIcon::Small, KIcon::SizeSmall)),
+ "", "");
+ mergeBtn->setGuiItem(mergeButtenItem);
+
+ // make finish the default
+ finishBtn->setDefault(true);
+
+ // setup the focus
+ cancelBtn->setFocusPolicy(QWidget::NoFocus);
+ finishBtn->setFocusPolicy(QWidget::NoFocus);
+ clearAllBtn->setFocusPolicy(QWidget::NoFocus);
+
+ // connect signals with slots
+ connect(transactionsTable, SIGNAL(transactionChanged(const MyMoneyTransaction&)),
+ this, SLOT(slotSetTransaction(const MyMoneyTransaction&)));
+ connect(transactionsTable, SIGNAL(createCategory(const QString&, QString&)), this, SLOT(slotCreateCategory(const QString&, QString&)));
+ connect(transactionsTable, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+
+ connect(transactionsTable, SIGNAL(returnPressed()), this, SLOT(accept()));
+ connect(transactionsTable, SIGNAL(escapePressed()), this, SLOT(reject()));
+
+ connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(finishBtn, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(clearAllBtn, SIGNAL(clicked()), this, SLOT(slotClearAllSplits()));
+ connect(mergeBtn, SIGNAL(clicked()), this, SLOT(slotMergeSplits()));
+ connect(clearZeroBtn, SIGNAL(clicked()), this, SLOT(slotClearUnusedSplits()));
+
+ // setup the precision
+ try {
+ MyMoneySecurity currency = MyMoneyFile::instance()->currency(t.commodity());
+ m_precision = MyMoneyMoney::denomToPrec(m_account.fraction(currency));
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ slotSetTransaction(t);
+
+ // pass on those vars
+ transactionsTable->setup(priceInfo);
+
+ QSize size(width(), height());
+ kapp->config()->setGroup("SplitTransactionEditor");
+ size = kapp->config()->readSizeEntry("Geometry", &size);
+ size.setHeight(size.height()-1);
+ QDialog::resize( size.expandedTo(minimumSizeHint()) );
+
+ // Trick: it seems, that the initial sizing of the dialog does
+ // not work correctly. At least, the columns do not get displayed
+ // correct. Reason: the return value of transactionsTable->visibleWidth()
+ // is incorrect. If the widget is visible, resizing works correctly.
+ // So, we let the dialog show up and resize it then. It's not really
+ // clean, but the only way I got the damned thing working.
+ QTimer::singleShot( 10, this, SLOT(initSize()) );
+}
+
+KSplitTransactionDlg::~KSplitTransactionDlg()
+{
+ kapp->config()->setGroup("SplitTransactionEditor");
+ kapp->config()->writeEntry("Geometry", size());
+}
+
+int KSplitTransactionDlg::exec(void)
+{
+ // for deposits, we invert the sign of all splits.
+ // don't forget to revert when we're done ;-)
+ if(m_isDeposit) {
+ for(unsigned i = 0; i < m_transaction.splits().count(); ++i) {
+ MyMoneySplit split = m_transaction.splits()[i];
+ split.setValue(-split.value());
+ split.setShares(-split.shares());
+ m_transaction.modifySplit(split);
+ }
+ }
+
+ int rc;
+ do {
+ transactionsTable->setFocus();
+
+ // initialize the display
+ transactionsTable->setTransaction(m_transaction, m_split, m_account);
+ updateSums();
+
+ rc = KSplitTransactionDlgDecl::exec();
+
+ if(rc == QDialog::Accepted) {
+ if(!diffAmount().isZero()) {
+ KSplitCorrectionDlgDecl* corrDlg = new KSplitCorrectionDlgDecl(this, 0, true);
+
+ // add icons to buttons
+ corrDlg->okBtn->setGuiItem(KStdGuiItem::ok());
+ corrDlg->cancelBtn->setGuiItem(KStdGuiItem::cancel());
+
+ MyMoneySplit split = m_transaction.splits()[0];
+ QString total = (-split.value()).formatMoney("", m_precision);
+ QString sums = splitsValue().formatMoney("", m_precision);
+ QString diff = diffAmount().formatMoney("", m_precision);
+
+ // now modify the text items of the dialog to contain the correct values
+ QString q = i18n("The total amount of this transaction is %1 while "
+ "the sum of the splits is %2. The remaining %3 are "
+ "unassigned.")
+ .arg(total)
+ .arg(sums)
+ .arg(diff);
+ corrDlg->explanation->setText(q);
+
+ q = i18n("Change &total amount of transaction to %1.").arg(sums);
+ corrDlg->changeBtn->setText(q);
+
+ q = i18n("&Distribute difference of %1 among all splits.").arg(diff);
+ corrDlg->distributeBtn->setText(q);
+ // FIXME remove the following line once distribution among
+ // all splits is implemented
+ corrDlg->distributeBtn->hide();
+
+
+ // if we have only two splits left, we don't allow leaving sth. unassigned.
+ if(m_transaction.splitCount() < 3) {
+ q = i18n("&Leave total amount of transaction at %1.").arg(total);
+ } else {
+ q = i18n("&Leave %1 unassigned.").arg(diff);
+ }
+ corrDlg->leaveBtn->setText(q);
+
+ if((rc = corrDlg->exec()) == QDialog::Accepted) {
+ QButton* button = corrDlg->buttonGroup->selected();
+ if(button != 0) {
+ switch(corrDlg->buttonGroup->id(button)) {
+ case 0: // continue to edit
+ rc = QDialog::Rejected;
+ break;
+
+ case 1: // modify total
+ split.setValue(-splitsValue());
+ split.setShares(-splitsValue());
+ m_transaction.modifySplit(split);
+ break;
+
+ case 2: // distribute difference
+ qDebug("distribution of difference not yet supported in KSplitTransactionDlg::slotFinishClicked()");
+ break;
+
+ case 3: // leave unassigned
+ break;
+ }
+ }
+ }
+ delete corrDlg;
+ }
+ } else
+ break;
+
+ } while(rc != QDialog::Accepted);
+
+ // for deposits, we inverted the sign of all splits.
+ // now we revert it back, so that things are left correct
+ if(m_isDeposit) {
+ for(unsigned i = 0; i < m_transaction.splits().count(); ++i) {
+ MyMoneySplit split = m_transaction.splits()[i];
+ split.setValue(-split.value());
+ split.setShares(-split.shares());
+ m_transaction.modifySplit(split);
+ }
+ }
+
+ return rc;
+}
+
+void KSplitTransactionDlg::initSize(void)
+{
+ QDialog::resize(width(), height()+1);
+}
+
+void KSplitTransactionDlg::accept()
+{
+ transactionsTable->slotCancelEdit();
+ KSplitTransactionDlgDecl::accept();
+}
+
+void KSplitTransactionDlg::reject()
+{
+ // cancel any edit activity in the split register
+ transactionsTable->slotCancelEdit();
+ KSplitTransactionDlgDecl::reject();
+}
+
+void KSplitTransactionDlg::slotClearAllSplits(void)
+{
+ transactionsTable->slotEndEdit();
+ int answer;
+ answer = KMessageBox::warningContinueCancel (this,
+ i18n("You are about to delete all splits of this transaction. "
+ "Do you really want to continue?"),
+ i18n("KMyMoney"),
+ i18n("Continue")
+ );
+
+ if(answer == KMessageBox::Continue) {
+ transactionsTable->slotCancelEdit();
+ QValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ // clear all but the one referencing the account
+ for(it = list.begin(); it != list.end(); ++it) {
+ m_transaction.removeSplit(*it);
+ }
+
+ transactionsTable->setTransaction(m_transaction, m_split, m_account);
+ slotSetTransaction(m_transaction);
+ }
+}
+
+void KSplitTransactionDlg::slotClearUnusedSplits(void)
+{
+ transactionsTable->slotEndEdit();
+
+ QValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ try {
+ // remove all splits that don't have a value assigned
+ for(it = list.begin(); it != list.end(); ++it) {
+ if((*it).shares().isZero()) {
+ m_transaction.removeSplit(*it);
+ }
+ }
+
+ transactionsTable->setTransaction(m_transaction, m_split, m_account);
+ slotSetTransaction(m_transaction);
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+}
+
+void KSplitTransactionDlg::slotMergeSplits(void)
+{
+ transactionsTable->slotEndEdit();
+
+ QValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ try {
+ // collect all splits, merge them if needed and remove from transaction
+ QValueList<MyMoneySplit> splits;
+ for(it = list.begin(); it != list.end(); ++it) {
+ QValueList<MyMoneySplit>::iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ if((*it_s).accountId() == (*it).accountId()
+ && (*it_s).memo().isEmpty() && (*it).memo().isEmpty())
+ break;
+ }
+ if(it_s != splits.end()) {
+ (*it_s).setShares((*it).shares() + (*it_s).shares());
+ (*it_s).setValue((*it).value() + (*it_s).value());
+ } else {
+ splits << *it;
+ }
+ m_transaction.removeSplit(*it);
+ }
+
+ // now add them back to the transaction
+ QValueList<MyMoneySplit>::iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ (*it_s).clearId();
+ m_transaction.addSplit(*it_s);
+ }
+
+ transactionsTable->setTransaction(m_transaction, m_split, m_account);
+ slotSetTransaction(m_transaction);
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+}
+
+void KSplitTransactionDlg::slotSetTransaction(const MyMoneyTransaction& t)
+{
+ transactionsTable->slotCancelEdit();
+
+ m_transaction = t;
+ QValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ // check if we can merge splits or not, have zero splits or not
+ QMap<QString, int> splits;
+ bool haveZeroSplit = false;
+ for(it = list.begin(); it != list.end(); ++it) {
+ splits[(*it).accountId()]++;
+ if(((*it).id() != m_split.id()) && ((*it).shares().isZero()))
+ haveZeroSplit = true;
+ }
+ QMap<QString, int>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ if((*it_s) > 1)
+ break;
+ }
+ mergeBtn->setDisabled(it_s == splits.end());
+ clearZeroBtn->setEnabled(haveZeroSplit);
+
+ updateSums();
+}
+
+void KSplitTransactionDlg::updateSums(void)
+{
+ MyMoneyMoney splits(splitsValue());
+
+ if(m_amountValid == false) {
+ m_split.setValue(-splits);
+ m_transaction.modifySplit(m_split);
+ }
+
+ splitSum->setText("<b>" + splits.formatMoney("", m_precision) + " ");
+ splitUnassigned->setText("<b>" + diffAmount().formatMoney("", m_precision) + " ");
+ transactionAmount->setText("<b>" + (-m_split.value()).formatMoney("", m_precision) + " ");
+}
+
+MyMoneyMoney KSplitTransactionDlg::splitsValue(void)
+{
+ MyMoneyMoney splitsValue(m_calculatedValue);
+ QValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ // calculate the current sum of all split parts
+ for(it = list.begin(); it != list.end(); ++it) {
+ if((*it).value() != MyMoneyMoney::autoCalc)
+ splitsValue += (*it).value();
+ }
+
+ return splitsValue;
+}
+
+MyMoneyMoney KSplitTransactionDlg::diffAmount(void)
+{
+ MyMoneyMoney diff(0);
+
+ // if there is an amount specified in the transaction, we need to calculate the
+ // difference, otherwise we display the difference as 0 and display the same sum.
+ if(m_amountValid) {
+ MyMoneySplit split = m_transaction.splits()[0];
+
+ diff = -(splitsValue() + split.value());
+ }
+ return diff;
+}
+
+void KSplitTransactionDlg::slotCreateCategory(const QString& name, QString& id)
+{
+ MyMoneyAccount acc, parent;
+ acc.setName(name);
+
+ if(m_isDeposit)
+ parent = MyMoneyFile::instance()->income();
+ else
+ parent = MyMoneyFile::instance()->expense();
+
+ // TODO extract possible first part of a hierarchy and check if it is one
+ // of our top categories. If so, remove it and select the parent
+ // according to this information.
+
+ emit createCategory(acc, parent);
+
+ // return id
+ id = acc.id();
+}
+
+#include "ksplittransactiondlg.moc"
diff --git a/kmymoney2/dialogs/ksplittransactiondlg.h b/kmymoney2/dialogs/ksplittransactiondlg.h
new file mode 100644
index 0000000..67a5b92
--- /dev/null
+++ b/kmymoney2/dialogs/ksplittransactiondlg.h
@@ -0,0 +1,174 @@
+/***************************************************************************
+ ksplittransactiondlg.h - description
+ -------------------
+ begin : Thu Jan 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSPLITTRANSACTIONDLG_H
+#define KSPLITTRANSACTIONDLG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransaction.h>
+
+class kMyMoneyEdit;
+class kMyMoneyLineEdit;
+
+#include "../dialogs/ksplittransactiondlgdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KSplitTransactionDlg : public KSplitTransactionDlgDecl
+{
+ Q_OBJECT
+
+public:
+ KSplitTransactionDlg(const MyMoneyTransaction& t,
+ const MyMoneySplit& s,
+ const MyMoneyAccount& acc,
+ const bool amountValid,
+ const bool deposit,
+ const MyMoneyMoney& calculatedValue,
+ const QMap<QString, MyMoneyMoney>& priceInfo,
+ QWidget* parent = 0, const char* name = 0);
+
+ virtual ~KSplitTransactionDlg();
+
+ /**
+ * Using this method, an external object can retrieve the result
+ * of the dialog.
+ *
+ * @return MyMoneyTransaction based on the transaction passes during
+ * the construction of this object and modified using the
+ * dialog.
+ */
+ const MyMoneyTransaction& transaction(void) const { return m_transaction; };
+
+ /**
+ * This method calculates the difference between the split that references
+ * the account passed as argument to the constructor of this object and
+ * all the other splits shown in the register of this dialog.
+ *
+ * @return difference as MyMoneyMoney object
+ */
+ MyMoneyMoney diffAmount(void);
+
+ /**
+ * This method calculates the sum of the splits shown in the register
+ * of this dialog.
+ *
+ * @return sum of splits as MyMoneyMoney object
+ */
+ MyMoneyMoney splitsValue(void);
+
+private:
+ /**
+ * This method updates the display of the sums below the register
+ */
+ void updateSums(void);
+
+public slots:
+ int exec(void);
+
+protected slots:
+ void accept();
+ void reject();
+ void slotClearAllSplits(void);
+ void slotClearUnusedSplits(void);
+ void slotSetTransaction(const MyMoneyTransaction& t);
+ void slotCreateCategory(const QString& txt, QString& id);
+ void slotMergeSplits(void);
+
+ /// used internally to setup the initial size of all widgets
+ void initSize(void);
+
+signals:
+ /**
+ * This signal is sent out, when a new category needs to be created
+ * Depending on the setting of either a payment or deposit, the parent
+ * account will be preset to Expense or Income.
+ *
+ * @param account reference to account info. Will be filled by called slot
+ * @param parent reference to parent account
+ */
+ void createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent);
+
+ /**
+ * Signal is emitted, if any of the widgets enters (@a state equals @a true)
+ * or leaves (@a state equals @a false) object creation mode.
+ *
+ * @param state Enter (@a true) or leave (@a false) object creation
+ */
+ void objectCreation(bool state);
+
+private:
+ /**
+ * This member keeps a copy of the current selected transaction
+ */
+ MyMoneyTransaction m_transaction;
+
+ /**
+ * This member keeps a copy of the currently selected account
+ */
+ MyMoneyAccount m_account;
+
+ /**
+ * This member keeps a copy of the currently selected split
+ */
+ MyMoneySplit m_split;
+
+ /**
+ * This member keeps the precision for the values
+ */
+ int m_precision;
+
+ /**
+ * flag that shows that the amount specified in the constructor
+ * should be used as fix value (true) or if it can be changed (false)
+ */
+ bool m_amountValid;
+
+ /**
+ * This member keeps track if the current transaction is of type
+ * deposit (true) or withdrawal (false).
+ */
+ bool m_isDeposit;
+
+ /**
+ * This member keeps the amount that will be assigned to all the
+ * splits that are marked 'will be calculated'.
+ */
+ MyMoneyMoney m_calculatedValue;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/ksplittransactiondlgdecl.ui b/kmymoney2/dialogs/ksplittransactiondlgdecl.ui
new file mode 100644
index 0000000..72a19e3
--- /dev/null
+++ b/kmymoney2/dialogs/ksplittransactiondlgdecl.ui
@@ -0,0 +1,424 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSplitTransactionDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSplitTransactionDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>656</width>
+ <height>408</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Split transaction</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout61</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="kMyMoneySplitTable">
+ <property name="name">
+ <cstring>transactionsTable</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>5</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="cursor">
+ <cursor>0</cursor>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_sumFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout49</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>80</height>
+ </size>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>splitUnassigned</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>15</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;11,00&lt;b&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>transactionAmount</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>15</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;111,00&lt;b&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Unassigned</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Sum of splits</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>splitSum</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>15</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>100,00</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Transaction amount</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="Line" row="2" column="1">
+ <property name="name">
+ <cstring>Line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>15</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>80</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>mergeBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Merge</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Merges splits with the same category to one split</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>In case you have multiple split entries to the same category and you like to keep them as a single split, press this button. The amount for identical categories will be added and stored in a single split for that category.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>clearZeroBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Clear &amp;Zero</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Removes all splits that have a value of zero.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>clearAllBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Clear &amp;All</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer30</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>120</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>2</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>finishBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneySplitTable</class>
+ <header location="local">../dialogs/kmymoneysplittable.h</header>
+ <sizehint>
+ <width>330</width>
+ <height>390</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>3</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="256">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c749444154388dad55db1184200c4c180bb81a28c73aad811228c356f42b3792db3cc0db2fc724bb7901dc7b270f27ed17fa5fa9b117b7cd90211f4ba0ac906a7f1453b4d30ca917bb590681552af23f69bfc4ffa71519d2c8f62546ea5ea03738b1c18c33a4d156f0d13f43b61952e4af6d6e8fb3a408f080448419a433d6486d85052fdba892a295f5d45785cd8c51a9d6de6a814a8d2131da51f98e7a3b64ec9da04a8db53d43be3c3c0b22cacf17e4cdb5a931649ceddf34b190cf0aa019f03f1fd3e7457f03b5a66c9ed26e86130000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/kstartdlg.cpp b/kmymoney2/dialogs/kstartdlg.cpp
new file mode 100644
index 0000000..d0af8eb
--- /dev/null
+++ b/kmymoney2/dialogs/kstartdlg.cpp
@@ -0,0 +1,243 @@
+/***************************************************************************
+ KStartDlg.cpp - description
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qbuttongroup.h>
+#include <qabstractlayout.h>
+#include <qpixmap.h>
+#include <qtextview.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+
+#if QT_VERSION > 300
+#include <kstandarddirs.h>
+#else
+#include <kstddirs.h>
+#endif
+
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+#include <kfile.h>
+#include <kio/netaccess.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kstartdlg.h"
+#include "krecentfileitem.h"
+#include "../kmymoney2.h"
+
+#include <qtooltip.h>
+
+KStartDlg::KStartDlg(QWidget *parent, const char *name, bool modal) : KDialogBase(IconList,i18n("Start Dialog"),Help|Ok|Cancel,Ok, parent, name, modal, true)
+{
+ setPage_Template();
+ setPage_Documents();
+
+ isnewfile = false;
+ isopenfile = false;
+
+ readConfig();
+}
+
+KStartDlg::~KStartDlg()
+{
+}
+
+/** Set the font Page of the preferences dialog */
+void KStartDlg::setPage_Template()
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+ templateMainFrame = addVBoxPage( i18n("Templates"), i18n("Select templates"), DesktopIcon("wizard"));
+ view_wizard = new KIconView( templateMainFrame, "view_options" );
+ (void)new QIconViewItem( view_wizard, i18n("New KMyMoney document"), ic->loadIcon("mime_empty.png", KIcon::Desktop, KIcon::SizeLarge)/*QPixmap( locate("icon","hicolor/48x48/mimetypes/mime_empty.png") )*/ );
+ connect(view_wizard, SIGNAL(executed(QIconViewItem *) ), this, SLOT(slotTemplateClicked(QIconViewItem *) ) );
+ connect(view_wizard, SIGNAL(selectionChanged(QIconViewItem*)),
+ this, SLOT(slotTemplateSelectionChanged(QIconViewItem*)));
+ connect(this, SIGNAL(aboutToShowPage(QWidget*)), this, SLOT(slotAboutToShowPage(QWidget*)));
+}
+
+/** Set the Misc options Page of the preferences dialog */
+void KStartDlg::setPage_Documents()
+{
+ recentMainFrame = addPage( i18n("Open"), i18n("Open a KMyMoney document"), DesktopIcon("fileopen"));
+ QVBoxLayout *mainLayout = new QVBoxLayout( recentMainFrame );
+
+ kurlrequest = new KURLRequester( recentMainFrame, "kurlrequest" );
+
+ //allow user to select either a .kmy file, or any generic file.
+ kurlrequest->fileDialog()->setFilter( i18n("%1|KMyMoney files (*.kmy)\n" "%2|All files (*.*)").arg("*.kmy").arg("*.*") );
+ kurlrequest->fileDialog()->setMode(KFile::File || KFile::ExistingOnly);
+ kurlrequest->fileDialog()->setURL(KURL(kmymoney2->readLastUsedDir()));//kurlrequest->fileDialog()->setURL(KURL(KGlobalSettings::documentPath()));
+ mainLayout->addWidget( kurlrequest );
+
+ QLabel *label1 = new QLabel( recentMainFrame, "label1" );
+ label1->setText( i18n("Recent Files") );
+ mainLayout->addWidget( label1 );
+ view_recent = new KIconView( recentMainFrame, "view_recent" );
+ connect( view_recent, SIGNAL( executed(QIconViewItem *) ), this, SLOT( slotRecentClicked(QIconViewItem *) ) );
+ mainLayout->addWidget( view_recent );
+ view_recent->setArrangement(KIconView::LeftToRight/*TopToBottom*/);
+ view_recent->setItemTextPos(KIconView::Bottom);
+
+ connect(view_recent, SIGNAL(selectionChanged(QIconViewItem*)),
+ this, SLOT(slotRecentSelectionChanged(QIconViewItem*)));
+}
+
+void KStartDlg::slotTemplateClicked(QIconViewItem *item)
+{
+ if(!item) return;
+
+ // If the item is the blank document turn isnewfile variable true, else is template or wizard
+ if( item->text() == i18n("New KMyMoney document") )
+ isnewfile = true;
+ else
+ templatename = item->text();
+
+ isopenfile = false;
+ // Close the window if the user pressed an icon
+ slotOk();
+}
+
+/** Read config window */
+void KStartDlg::readConfig()
+{
+ QString value;
+ unsigned int i = 1;
+
+ KConfig *config = KGlobal::config();
+ KIconLoader *il = KGlobal::iconLoader();
+
+ // read file list
+ do {
+ // for some reason, I had to setup the group to get reasonable results
+ // after program startup. If the wizard was opened the second time,
+ // it does not make a difference, if you call setGroup() outside of
+ // this loop. The first time it does make a difference!
+ config->setGroup("Recent Files");
+ value = config->readEntry( QString( "File%1" ).arg( i ), QString::null );
+ if( !value.isNull() && fileExists(value) )
+ {
+ QString file_name = value.mid(value.findRev('/')+1);
+ (void)new KRecentFileItem( value, view_recent, file_name, il->loadIcon("kmy", KIcon::Desktop, KIcon::SizeLarge));
+ }
+ i++;
+ } while( !value.isNull() );
+
+ config->setGroup("Start Dialog");
+ QSize *defaultSize = new QSize(400,300);
+ this->resize( config->readSizeEntry("Geometry", defaultSize ) );
+
+ // Restore the last page viewed
+ // default to the recent files page if no entry exists but files have been found
+ // otherwise, default to template page
+ if(view_recent->count() > 0)
+ showPage(config->readNumEntry("LastPage", this->pageIndex(recentMainFrame)));
+ else {
+ showPage(config->readNumEntry("LastPage", this->pageIndex(templateMainFrame)));
+ slotAboutToShowPage(templateMainFrame);
+ }
+}
+
+/** Write config window */
+void KStartDlg::writeConfig()
+{
+ KConfig *config = KGlobal::config();
+
+ config->setGroup("Start Dialog");
+ config->writeEntry("Geometry", this->size() );
+ config->writeEntry("LastPage", this->activePageIndex());
+ config->sync();
+}
+
+/** slot to recent view */
+void KStartDlg::slotRecentClicked(QIconViewItem *item)
+{
+ KRecentFileItem *kitem = (KRecentFileItem*)item;
+ if(!kitem) return;
+
+ isopenfile = true;
+ kurlrequest->setURL( kitem->fileURL() );
+ // Close the window if the user press an icon
+ slotOk();
+}
+
+/** No descriptions */
+void KStartDlg::slotOk()
+{
+ writeConfig();
+ this->accept();
+}
+
+bool KStartDlg::fileExists(KURL url)
+{
+#if KDE_IS_VERSION(3,2,0)
+ return KIO::NetAccess::exists(url, true, this);
+#else
+ return KIO::NetAccess::exists(url);
+#endif
+}
+
+void KStartDlg::slotTemplateSelectionChanged(QIconViewItem* item)
+{
+ if(!item) return;
+
+ // Clear the other selection
+ view_recent->clearSelection();
+
+ // If the item is the blank document turn isnewfile
+ // variable true, else is template or wizard
+ if( item->text() == i18n("Blank Document") )
+ isnewfile = true;
+ else
+ templatename = item->text();
+
+ isopenfile = false;
+}
+
+void KStartDlg::slotRecentSelectionChanged(QIconViewItem* item)
+{
+ KRecentFileItem *kitem = (KRecentFileItem*)item;
+ if(!kitem) return;
+
+ // Clear the other selection
+ view_wizard->clearSelection();
+
+ isnewfile = false;
+ isopenfile = true;
+ kurlrequest->setURL( kitem->fileURL() );
+}
+
+void KStartDlg::slotAboutToShowPage(QWidget* page)
+{
+ enableButtonOK(page == recentMainFrame);
+}
+
+#include "kstartdlg.moc"
diff --git a/kmymoney2/dialogs/kstartdlg.h b/kmymoney2/dialogs/kstartdlg.h
new file mode 100644
index 0000000..a09f72d
--- /dev/null
+++ b/kmymoney2/dialogs/kstartdlg.h
@@ -0,0 +1,84 @@
+
+/***************************************************************************
+ kstartdlg.h - description
+ -------------------
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSTARTDLG_H
+#define KSTARTDLG_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <kdialogbase.h>
+
+#include <klocale.h>
+#include <kfontdialog.h>
+#include <kurlrequester.h>
+#include <kiconview.h>
+
+#include <qstring.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+
+/**KMyMoney 2 start dialog
+ */
+
+class KStartDlg : public KDialogBase {
+ Q_OBJECT
+public:
+ KStartDlg( QWidget *parent=0, const char *name=0, bool modal=true );
+ virtual ~KStartDlg();
+ bool isNewFile(void) const { return isnewfile; }
+ bool isOpenFile(void) const { return !kurlrequest->url().isEmpty(); }
+ const QString getURL(void) const { return kurlrequest->url(); }
+ QString getTemplateName(void) const { return templatename; }
+
+private: // Private methods
+ QString m_filename;
+ bool fileExists(KURL url);
+
+ void setPage_Template();
+ void setPage_Documents();
+ /** misc widgets */
+ /** Write config window */
+ void writeConfig();
+ /** Read config window */
+ void readConfig();
+ KIconView *view_wizard;
+ KIconView *view_recent;
+ KURLRequester *kurlrequest;
+ /** misc variables */
+ bool isnewfile;
+ bool isopenfile;
+ QString templatename;
+ QVBox *templateMainFrame;
+ QFrame *recentMainFrame;
+
+protected slots:
+ /** No descriptions */
+ void slotOk();
+private slots:
+ void slotTemplateClicked(QIconViewItem *item);
+ /** slot to recent view */
+ void slotRecentClicked(QIconViewItem *item);
+
+ /** Handle selections */
+ void slotTemplateSelectionChanged(QIconViewItem* item);
+ void slotRecentSelectionChanged(QIconViewItem* item);
+ void slotAboutToShowPage(QWidget* page);
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kupdatestockpricedlg.cpp b/kmymoney2/dialogs/kupdatestockpricedlg.cpp
new file mode 100644
index 0000000..05eee8a
--- /dev/null
+++ b/kmymoney2/dialogs/kupdatestockpricedlg.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+ kupdatestockpricedlg.cpp - description
+ -------------------
+ begin : Thu Feb 7 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kupdatestockpricedlg.h"
+#include "../widgets/kmymoneycurrencyselector.h"
+
+KUpdateStockPriceDlg::KUpdateStockPriceDlg(QWidget* parent, const char* name) :
+ kUpdateStockPriceDecl(parent, name, true)
+{
+ m_date->setDate(QDate::currentDate());
+ init();
+}
+
+KUpdateStockPriceDlg::~KUpdateStockPriceDlg()
+{
+}
+
+void KUpdateStockPriceDlg::init()
+{
+ m_okButton->setGuiItem(KStdGuiItem::ok());
+ m_cancelButton->setGuiItem(KStdGuiItem::cancel());
+
+ connect(m_okButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+ connect(m_security, SIGNAL(activated(int)), this, SLOT(slotCheckData()));
+ connect(m_currency, SIGNAL(activated(int)), this, SLOT(slotCheckData()));
+
+ // load initial values into the selection widgets
+ m_currency->update(QString());
+ m_security->update(QString());
+
+ slotCheckData();
+}
+
+int KUpdateStockPriceDlg::exec(void)
+{
+ slotCheckData();
+ return kUpdateStockPriceDecl::exec();
+}
+
+void KUpdateStockPriceDlg::slotCheckData(void)
+{
+ QString from = m_security->security().id();
+ QString to = m_currency->security().id();
+
+ m_okButton->setEnabled(!from.isEmpty() && !to.isEmpty() && from != to);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#include "kupdatestockpricedlg.moc"
diff --git a/kmymoney2/dialogs/kupdatestockpricedlg.h b/kmymoney2/dialogs/kupdatestockpricedlg.h
new file mode 100644
index 0000000..c7dd407
--- /dev/null
+++ b/kmymoney2/dialogs/kupdatestockpricedlg.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ kupdatestockpricedlg.h - description
+ -------------------
+ begin : Thu Feb 7 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KUPDATESTOCKPRICEDLG_H
+#define KUPDATESTOCKPRICEDLG_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdialogbase.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../dialogs/kupdatestockpricedlgdecl.h"
+
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+
+/**
+ * @author Kevin Tambascio
+ */
+class KUpdateStockPriceDlg : public kUpdateStockPriceDecl
+{
+ Q_OBJECT
+
+public:
+ KUpdateStockPriceDlg(QWidget* parent = NULL, const char* name = NULL);
+ ~KUpdateStockPriceDlg();
+
+ const QDate date() const { return m_date->date(); };
+ const MyMoneyMoney price(void) const;
+
+public slots:
+ int exec(void);
+
+protected slots:
+ void slotCheckData(void);
+
+private:
+ void init();
+
+};
+
+#endif
diff --git a/kmymoney2/dialogs/kupdatestockpricedlgdecl.ui b/kmymoney2/dialogs/kupdatestockpricedlgdecl.ui
new file mode 100644
index 0000000..d9770b2
--- /dev/null
+++ b/kmymoney2/dialogs/kupdatestockpricedlgdecl.ui
@@ -0,0 +1,257 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>kUpdateStockPriceDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>kUpdateStockPriceDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>457</width>
+ <height>194</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New price entry</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout38</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="1">
+ <property name="name">
+ <cstring>layout37</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_date</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer25</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout36</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneySecuritySelector">
+ <property name="name">
+ <cstring>m_currency</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer26</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblDate</cstring>
+ </property>
+ <property name="text">
+ <string>Date:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Security</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout35</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneySecuritySelector">
+ <property name="name">
+ <cstring>m_security</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer27</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line6</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_okButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>2</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/mymoneyqifprofileeditor.cpp b/kmymoney2/dialogs/mymoneyqifprofileeditor.cpp
new file mode 100644
index 0000000..cc43ced
--- /dev/null
+++ b/kmymoney2/dialogs/mymoneyqifprofileeditor.cpp
@@ -0,0 +1,483 @@
+/***************************************************************************
+ kqifprofileeditor.cpp - description
+ -------------------
+ begin : Tue Dec 24 2002
+ copyright : (C) 2002 by Thomas Baumgart
+ email : thb@net-bembel.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpushbutton.h>
+#include <qlistbox.h>
+#include <qlistview.h>
+#include <qcheckbox.h>
+#include <qtabwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+#include <klocale.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <klineedit.h>
+#include <kmessagebox.h>
+#include <kcombobox.h>
+#include <kurlrequester.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#if KDE_IS_VERSION(3,2,0)
+ #include <kinputdialog.h>
+#else
+ #include <klineeditdlg.h>
+#endif
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyqifprofileeditor.h"
+
+MyMoneyQifProfileNameValidator::MyMoneyQifProfileNameValidator(QObject *o, const char *name)
+ : QValidator(o, name)
+{
+}
+
+MyMoneyQifProfileNameValidator::~MyMoneyQifProfileNameValidator()
+{
+}
+
+QValidator::State MyMoneyQifProfileNameValidator::validate(QString& name, int&) const
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup("Profiles");
+ QStringList list = config->readListEntry("profiles");
+
+ // invalid character?
+ if(name.contains(",") != 0)
+ return QValidator::Invalid;
+
+ // would not work in this form (empty or existing name)
+ if(name.isEmpty() || list.contains(name))
+ return QValidator::Intermediate;
+
+ // is OK
+ return QValidator::Acceptable;
+}
+
+MyMoneyQifProfileEditor::MyMoneyQifProfileEditor(const bool edit, QWidget *parent, const char *name )
+ : MyMoneyQifProfileEditorDecl(parent,name),
+ m_inEdit(edit),
+ m_isDirty(false),
+ m_isAccepted(false),
+ m_selectedAmountType(0)
+{
+ // we don't need the date and amounts tab anymore, so we just hide them for now
+ profileTabs->removePage( tabMoney );
+ profileTabs->removePage( tabDate );
+
+ loadWidgets();
+ loadProfileListFromConfig();
+
+ // load button icons
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem newButtenItem( i18n( "&New" ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new profile"),
+ i18n("Use this to create a new QIF import/export profile"));
+ m_newButton->setGuiItem(newButtenItem);
+
+ connect(m_profileListBox, SIGNAL(highlighted(const QString&)), this, SLOT(slotLoadProfileFromConfig(const QString&)));
+ connect(m_resetButton, SIGNAL(clicked()), this, SLOT(slotReset()));
+ connect(m_okButton, SIGNAL(clicked()), this, SLOT(slotOk()));
+ connect(m_renameButton, SIGNAL(clicked()), this, SLOT(slotRename()));
+ connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDelete()));
+ connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNew()));
+ connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_helpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
+
+ connect(m_editDescription, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setProfileDescription(const QString&)));
+ connect(m_editType, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setProfileType(const QString&)));
+ connect(m_editOpeningBalance, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setOpeningBalanceText(const QString&)));
+ connect(m_editAccountDelimiter, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setAccountDelimiter(const QString&)));
+ connect(m_editVoidMark, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setVoidMark(const QString&)));
+
+ //connect(m_editDateFormat, SIGNAL(highlighted(const QString&)), &m_profile, SLOT(setDateFormat(const QString&)));
+ connect(m_editApostrophe, SIGNAL(highlighted(const QString&)), &m_profile, SLOT(setApostropheFormat(const QString&)));
+
+ connect(m_editAmounts, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotAmountTypeSelected(QListViewItem*)));
+ connect(m_decimalBox, SIGNAL(activated(const QString&)), this, SLOT(slotDecimalChanged(const QString&)));
+ connect(m_thousandsBox, SIGNAL(activated(const QString&)), this, SLOT(slotThousandsChanged(const QString&)));
+
+ connect(m_editInputFilterLocation, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setFilterScriptImport(const QString&)));
+ connect(m_editInputFilterLocation, SIGNAL(urlSelected(const QString&)), m_editInputFilterLocation, SLOT(setURL(const QString&)));
+
+ connect(m_editInputFilterFileType, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setFilterFileType(const QString&)));
+
+ connect(m_editOutputFilterLocation, SIGNAL(textChanged(const QString&)), &m_profile, SLOT(setFilterScriptExport(const QString&)));
+ connect(m_editOutputFilterLocation, SIGNAL(urlSelected(const QString&)), m_editOutputFilterLocation, SLOT(setURL(const QString&)));
+
+ connect(m_attemptMatch, SIGNAL(toggled(bool)), &m_profile, SLOT(setAttemptMatchDuplicates(bool)));
+}
+
+MyMoneyQifProfileEditor::~MyMoneyQifProfileEditor()
+{
+ if(m_inEdit && m_isDirty && m_isAccepted) {
+ KConfig* config = KGlobal::config();
+ config->sync();
+ } else {
+ slotReset();
+ }
+ delete tabMoney;
+ delete tabDate;
+}
+
+void MyMoneyQifProfileEditor::loadWidgets(void)
+{
+ if(m_inEdit)
+ setCaption(i18n("QIF Profile Editor"));
+ else
+ setCaption(i18n("QIF Profile Selector"));
+
+ m_editDateFormat->clear();
+ m_editDateFormat->insertItem( "%d/%m/%yy" );
+ m_editDateFormat->insertItem( "%d/%mmm/%yy" );
+ m_editDateFormat->insertItem( "%d/%m/%yyyy" );
+ m_editDateFormat->insertItem( "%d/%mmm/%yyyy" );
+ m_editDateFormat->insertItem( "%d/%m%yy" );
+ m_editDateFormat->insertItem( "%d/%mmm%yy" );
+ m_editDateFormat->insertItem( "%d.%m.%yy" );
+ m_editDateFormat->insertItem( "%d.%m.%yyyy" );
+ m_editDateFormat->insertItem( "%m.%d.%yy" );
+ m_editDateFormat->insertItem( "%m.%d.%yyyy" );
+ m_editDateFormat->insertItem( "%m/%d/%yy" );
+ m_editDateFormat->insertItem( "%mmm/%d/%yy" );
+ m_editDateFormat->insertItem( "%m/%d/%yyyy" );
+ m_editDateFormat->insertItem( "%m-%d-%yyyy" );
+ m_editDateFormat->insertItem( "%mmm/%d/%yyyy" );
+ m_editDateFormat->insertItem( "%m%d%yy" );
+ m_editDateFormat->insertItem( "%mmm/%d%yy" );
+ m_editDateFormat->insertItem( "%yyyy-%mm-%dd" );
+ m_editDateFormat->insertItem( "%m/%d'%yyyy" );
+
+ m_editApostrophe->clear();
+ m_editApostrophe->insertItem( "1900-1949" );
+ m_editApostrophe->insertItem( "1900-1999" );
+ m_editApostrophe->insertItem( "2000-2099" );
+
+ m_editAmounts->setColumnAlignment(1, Qt::AlignCenter);
+ m_editAmounts->setColumnAlignment(2, Qt::AlignCenter);
+ m_editAmounts->setColumnAlignment(3, Qt::AlignCenter);
+
+ m_editAmounts->setColumnWidth(4, 0);
+ m_editAmounts->setColumnWidthMode(4, QListView::Manual);
+ m_editAmounts->setSorting(4);
+ m_editAmounts->sort();
+
+ m_decimalBox->insertItem( " " );
+ m_decimalBox->insertItem( "," );
+ m_decimalBox->insertItem( "." );
+
+ m_thousandsBox->insertItem( " " );
+ m_thousandsBox->insertItem( "," );
+ m_thousandsBox->insertItem( "." );
+
+ m_editDescription->setEnabled(m_inEdit);
+ m_editType->setEnabled(m_inEdit);
+ m_editDateFormat->setEnabled(m_inEdit);
+ m_editApostrophe->setEnabled(m_inEdit);
+ m_editAmounts->setEnabled(m_inEdit);
+ m_decimalBox->setEnabled(m_inEdit);
+ m_thousandsBox->setEnabled(m_inEdit);
+ m_editOpeningBalance->setEnabled(m_inEdit);
+ m_editAccountDelimiter->setEnabled(m_inEdit);
+ m_editVoidMark->setEnabled(m_inEdit);
+ m_editInputFilterLocation->setEnabled(m_inEdit);
+ m_editOutputFilterLocation->setEnabled(m_inEdit);
+ m_editInputFilterFileType->setEnabled(m_inEdit);
+
+ if(!m_inEdit) {
+ m_renameButton->hide();
+ m_deleteButton->hide();
+ m_resetButton->hide();
+ m_newButton->hide();
+ }
+}
+
+void MyMoneyQifProfileEditor::loadProfileListFromConfig(void)
+{
+ QFontMetrics fontMetrics(m_profileListBox->font());
+ int w = 100; // minimum is 100 pixels width for the list box
+
+ if(m_profile.isDirty()) {
+ m_profile.saveProfile();
+ m_isDirty = true;
+ }
+
+ m_profileListBox->clear();
+
+ QStringList list;
+ KConfig* config = KGlobal::config();
+ config->setGroup("Profiles");
+ list = config->readListEntry("profiles");
+
+ if(list.count() == 0) {
+ m_profile.clear();
+ m_profile.setProfileDescription(i18n("The default QIF profile"));
+ addProfile("Default");
+
+ config->setGroup("Profiles");
+ list = config->readListEntry("profiles");
+ }
+
+ list.sort();
+
+ m_profileListBox->insertStringList(list);
+ if(list.count() > 0) {
+ m_profileListBox->setSelected(0, true);
+ slotLoadProfileFromConfig(list[0]);
+ }
+ for(unsigned int i = 0; i < list.count(); ++i) {
+ int nw = fontMetrics.width(list[i]) + 10;
+ w = QMAX( w, nw );
+ }
+ w = QMIN(w, 200);
+ m_profileListBox->setMinimumWidth(w);
+}
+
+void MyMoneyQifProfileEditor::slotLoadProfileFromConfig(const QString& profile)
+{
+ QString profileName = profile;
+
+ if(m_profile.isDirty()) {
+ m_profile.saveProfile();
+ m_isDirty = true;
+ }
+
+ if(m_profileListBox->findItem(profileName, Qt::ExactMatch | Qt::CaseSensitive) == NULL) {
+ profileName = m_profileListBox->text(0);
+ }
+
+ m_profile.loadProfile("Profile-" + profileName);
+
+ QListBoxItem *lbi = m_profileListBox->findItem(profileName, Qt::ExactMatch | Qt::CaseSensitive);
+ int idx = m_profileListBox->index(lbi);
+ showProfile();
+ if(idx >= 0) {
+ m_profileListBox->setSelected(idx, true);
+ }
+}
+
+void MyMoneyQifProfileEditor::showProfile(void)
+{
+ m_editDescription->setText(m_profile.profileDescription());
+ m_editType->setText(m_profile.profileType());
+ m_editOpeningBalance->setText(m_profile.openingBalanceText());
+ m_editAccountDelimiter->setText(m_profile.accountDelimiter());
+ m_editVoidMark->setText(m_profile.voidMark());
+ m_editInputFilterLocation->setURL(m_profile.filterScriptImport());
+ m_editOutputFilterLocation->setURL(m_profile.filterScriptExport());
+ m_editInputFilterFileType->setText(m_profile.filterFileType());
+
+ m_editDateFormat->setCurrentText(m_profile.outputDateFormat());
+ m_editApostrophe->setCurrentText(m_profile.apostropheFormat());
+
+ m_attemptMatch->setChecked(m_profile.attemptMatchDuplicates());
+
+ QListViewItem* item;
+ QListViewItemIterator it(m_editAmounts);
+
+ while((item = it.current()) != 0) {
+ QChar key = item->text(1)[0];
+ item->setText(2, m_profile.amountDecimal(key));
+ item->setText(3, m_profile.amountThousands(key));
+ if(m_selectedAmountType == 0 && key == 'T' && m_inEdit) {
+ m_editAmounts->setSelected(item, true);
+ slotAmountTypeSelected(item);
+ } else if(item == m_selectedAmountType) {
+ slotAmountTypeSelected(item);
+ }
+ ++it;
+ }
+}
+
+void MyMoneyQifProfileEditor::deleteProfile(const QString& name)
+{
+ KConfig* config = KGlobal::config();
+
+ config->deleteGroup("Profile-" + name);
+
+ config->setGroup("Profiles");
+ QStringList list = config->readListEntry("profiles");
+ list.remove(name);
+
+ config->writeEntry("profiles", list);
+ m_isDirty = true;
+}
+
+void MyMoneyQifProfileEditor::addProfile(const QString& name)
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup("Profiles");
+ QStringList list = config->readListEntry("profiles");
+
+ list += name;
+ list.sort();
+ config->writeEntry("profiles", list);
+
+ m_profile.setProfileName("Profile-" + name);
+ m_profile.saveProfile();
+
+ m_isDirty = true;
+}
+
+void MyMoneyQifProfileEditor::slotOk(void)
+{
+ if(m_profile.isDirty())
+ m_isDirty = true;
+
+ m_profile.saveProfile();
+
+ KConfig* config = KGlobal::config();
+ config->sync();
+
+ m_isAccepted = true;
+ accept();
+}
+
+void MyMoneyQifProfileEditor::slotReset(void)
+{
+ // first flush any changes
+ m_profile.saveProfile();
+
+ KConfig* config = KGlobal::config();
+ config->rollback();
+ config->reparseConfiguration();
+
+ QString currentProfile = m_profile.profileName().mid(8);
+ loadProfileListFromConfig();
+ slotLoadProfileFromConfig(currentProfile);
+ m_isDirty = false;
+}
+
+void MyMoneyQifProfileEditor::slotRename(void)
+{
+ bool ok;
+ QString newName = enterName(ok);
+
+ if(ok == true) {
+ deleteProfile(m_profile.profileName().mid(8));
+ addProfile(newName);
+ loadProfileListFromConfig();
+ slotLoadProfileFromConfig(newName);
+ }
+}
+
+void MyMoneyQifProfileEditor::slotNew(void)
+{
+ bool ok;
+ QString newName = enterName(ok);
+
+ if(ok == true) {
+ m_profile.clear();
+ addProfile(newName);
+ loadProfileListFromConfig();
+ slotLoadProfileFromConfig(newName);
+ }
+}
+
+const QString MyMoneyQifProfileEditor::enterName(bool& ok)
+{
+ MyMoneyQifProfileNameValidator val(this, "Validator");
+#if KDE_IS_VERSION(3,2,0)
+ return KInputDialog::getText(i18n("QIF Profile Editor"),
+ i18n("Enter new profile name"),
+ QString::null,
+ &ok,
+ this,
+ 0,
+ &val,
+ 0);
+#else
+ QString rc;
+
+ // the blank in the next line as the value for the edit box is
+ // there on purpose, so that with the following call to validateAndSet
+ // the state is changed and the OK-Button is greyed
+ KLineEditDlg* dlg = new KLineEditDlg(i18n("Enter new profile name"), " ", this);
+ dlg->lineEdit()->setValidator(&val);
+ dlg->lineEdit()->validateAndSet("", 0, 0, 0);
+
+ ok = false;
+ if(dlg->exec()) {
+ ok = true;
+ }
+ rc = dlg->lineEdit()->text();
+ delete dlg;
+
+ return rc;
+#endif
+}
+
+void MyMoneyQifProfileEditor::slotDelete(void)
+{
+ QString profile = m_profile.profileName().mid(8);
+
+ if(KMessageBox::questionYesNo(this, i18n("Do you really want to delete profile '%1'?").arg(profile)) == KMessageBox::Yes) {
+ int idx = m_profileListBox->currentItem();
+ m_profile.saveProfile();
+ deleteProfile(profile);
+ loadProfileListFromConfig();
+ if(idx >= static_cast<int> (m_profileListBox->count()))
+ idx = m_profileListBox->count() - 1;
+
+ slotLoadProfileFromConfig(m_profileListBox->text(idx));
+ }
+}
+
+void MyMoneyQifProfileEditor::slotHelp(void)
+{
+ kapp->invokeHelp("details.impexp.qifimp.profile");
+}
+
+void MyMoneyQifProfileEditor::slotAmountTypeSelected(QListViewItem* item)
+{
+ m_decimalBox->setCurrentText(item->text(2));
+ m_thousandsBox->setCurrentText(item->text(3));
+ m_selectedAmountType = item;
+}
+
+void MyMoneyQifProfileEditor::slotDecimalChanged(const QString& val)
+{
+ if(m_selectedAmountType != 0) {
+ QChar key = m_selectedAmountType->text(1)[0];
+ m_profile.setAmountDecimal(key, val[0]);
+ m_selectedAmountType->setText(2, val);
+ }
+}
+
+void MyMoneyQifProfileEditor::slotThousandsChanged(const QString& val)
+{
+ if(m_selectedAmountType != 0) {
+ QChar key = m_selectedAmountType->text(1)[0];
+ m_profile.setAmountThousands(key, val[0]);
+ m_selectedAmountType->setText(3, val);
+ }
+}
+
+const QString MyMoneyQifProfileEditor::selectedProfile() const
+{
+ return m_profileListBox->currentText();
+}
+
+#include "mymoneyqifprofileeditor.moc"
diff --git a/kmymoney2/dialogs/mymoneyqifprofileeditor.h b/kmymoney2/dialogs/mymoneyqifprofileeditor.h
new file mode 100644
index 0000000..ce95c9a
--- /dev/null
+++ b/kmymoney2/dialogs/mymoneyqifprofileeditor.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ kqifprofileeditor.h - description
+ -------------------
+ begin : Tue Dec 24 2002
+ copyright : (C) 2002 by Thomas Baumgart
+ email : thb@net-bembel.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYQIFPROFILEEDITOR_H
+#define MYMONEYQIFPROFILEEDITOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qvalidator.h>
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyqifprofileeditordecl.h"
+#include "../converter/mymoneyqifprofile.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class MyMoneyQifProfileNameValidator : public QValidator
+{
+ Q_OBJECT
+
+public:
+ MyMoneyQifProfileNameValidator(QObject *o, const char *name);
+ virtual ~MyMoneyQifProfileNameValidator();
+
+ QValidator::State validate(QString&, int&) const;
+};
+
+
+class MyMoneyQifProfileEditor : public MyMoneyQifProfileEditorDecl
+{
+ Q_OBJECT
+
+public:
+ MyMoneyQifProfileEditor(const bool edit = false, QWidget *parent=0, const char *name=0);
+ virtual ~MyMoneyQifProfileEditor();
+
+ /**
+ * This method returns the currently selected profile in the list box.
+ */
+ const QString selectedProfile() const;
+
+public slots:
+ void slotOk(void);
+
+protected slots:
+ void slotLoadProfileFromConfig(const QString& name);
+ void slotReset(void);
+ void slotRename(void);
+ void slotDelete(void);
+ void slotNew(void);
+ void slotAmountTypeSelected(QListViewItem*);
+ void slotDecimalChanged(const QString& val);
+ void slotThousandsChanged(const QString& val);
+ void slotHelp(void);
+
+private:
+ void loadProfileListFromConfig(void);
+ void loadWidgets(void);
+ void showProfile(void);
+ void addProfile(const QString& name);
+ void deleteProfile(const QString& name);
+ const QString enterName(bool& ok);
+
+private:
+ bool m_inEdit;
+ MyMoneyQifProfile m_profile;
+ bool m_isDirty;
+ bool m_isAccepted;
+ QListViewItem* m_selectedAmountType;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/mymoneyqifprofileeditordecl.ui b/kmymoney2/dialogs/mymoneyqifprofileeditordecl.ui
new file mode 100644
index 0000000..43e56fa
--- /dev/null
+++ b/kmymoney2/dialogs/mymoneyqifprofileeditordecl.ui
@@ -0,0 +1,905 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>MyMoneyQifProfileEditorDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>MyMoneyQifProfileEditorDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>736</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>QIF Profile Editor</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox">
+ <item>
+ <property name="text">
+ <string></string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_profileListBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="variableWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>profileTabs</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tabGeneral</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2_3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Void mark</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Opening Balance text</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_editOpeningBalance</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Type field text</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>m_editAccountDelimiter</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_editVoidMark</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Account delimiter</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_editType</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_editDescription</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_attemptMatch</cstring>
+ </property>
+ <property name="text">
+ <string>Attempt to match similar transactions</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tabDate</cstring>
+ </property>
+ <attribute name="title">
+ <string>Date</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout43</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout36</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_editDateFormat</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The format of the dates in the QIF file.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Date Format</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The format of the dates in the QIF file.</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_editApostrophe</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If a QIF file contains date entries with years represented with two digits then either an apostrophe or a slash may be used to delimit the year in the dates for certain centuries. This enables 1905 to be distinguished from 2005. Specify here which range of years will have year delimited by an apostrophe (eg. for Quicken this is usually 1900-1949).</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Apostrophe Handling</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If a QIF file contains date entries with years represented with two digits then either an apostrophe or a slash may be used to delimit the year in the dates for certain centuries. This enables 1905 to be distinguished from 2005. Specify here which range of years will have year delimited by an apostrophe (eg. for Quicken this is usually 1900-1949).</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>90</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>80</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tabMoney</cstring>
+ </property>
+ <attribute name="title">
+ <string>Amounts</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Field</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>QIF-Record</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Decimal Symbol</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Thousand Delimiter</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>SortColumnInvisible</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <item>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ <property name="text">
+ <string>T</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Split-Value</string>
+ </property>
+ <property name="text">
+ <string>$</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Commission</string>
+ </property>
+ <property name="text">
+ <string>O</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string>2</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ <property name="text">
+ <string>I</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string>3</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Quantity</string>
+ </property>
+ <property name="text">
+ <string>Q</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="text">
+ <string>4</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_editAmounts</cstring>
+ </property>
+ <property name="hScrollBarMode">
+ <enum>AlwaysOff</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout41</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout40</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_thousandsBox</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Decimal Symbol</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Thousands Separator</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_decimalBox</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>100</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tabFilter</cstring>
+ </property>
+ <attribute name="title">
+ <string>Filter</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel1_4_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Output filter location</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>m_editInputFilterLocation</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>m_editOutputFilterLocation</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_4_3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Input filter file type</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_editInputFilterFileType</cstring>
+ </property>
+ <property name="text">
+ <string>*.qif</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_4</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Input filter location</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer9_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>90</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout14</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_helpButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>11</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_newButton</cstring>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Delete</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>22</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_renameButton</cstring>
+ </property>
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>104</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_resetButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Reset</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>21</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_okButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>2</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>m_profileListBox</tabstop>
+ <tabstop>profileTabs</tabstop>
+ <tabstop>m_editDescription</tabstop>
+ <tabstop>m_editType</tabstop>
+ <tabstop>m_editOpeningBalance</tabstop>
+ <tabstop>m_editAccountDelimiter</tabstop>
+ <tabstop>m_editVoidMark</tabstop>
+ <tabstop>m_helpButton</tabstop>
+ <tabstop>m_newButton</tabstop>
+ <tabstop>m_deleteButton</tabstop>
+ <tabstop>m_renameButton</tabstop>
+ <tabstop>m_resetButton</tabstop>
+ <tabstop>m_okButton</tabstop>
+ <tabstop>m_cancelButton</tabstop>
+ <tabstop>m_editDateFormat</tabstop>
+ <tabstop>m_editApostrophe</tabstop>
+ <tabstop>m_decimalBox</tabstop>
+ <tabstop>m_thousandsBox</tabstop>
+ <tabstop>m_editAmounts</tabstop>
+ <tabstop>m_editInputFilterLocation</tabstop>
+ <tabstop>m_editOutputFilterLocation</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/Makefile.am b/kmymoney2/dialogs/settings/Makefile.am
new file mode 100644
index 0000000..f296c11
--- /dev/null
+++ b/kmymoney2/dialogs/settings/Makefile.am
@@ -0,0 +1,25 @@
+noinst_LIBRARIES = libsettings.a
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+
+libsettings_a_METASOURCES = AUTO
+
+libsettings_a_SOURCES = ksettingsgeneraldecl.ui ksettingsgeneral.cpp \
+ ksettingsregisterdecl.ui ksettingsregister.cpp \
+ ksettingsgpgdecl.ui ksettingsgpg.cpp \
+ ksettingscolorsdecl.ui ksettingscolors.cpp \
+ ksettingsfontsdecl.ui ksettingsfonts.cpp \
+ ksettingsschedulesdecl.ui ksettingsschedules.cpp \
+ ksettingsonlinequotesdecl.ui ksettingsonlinequotes.cpp \
+ ksettingshomedecl.ui ksettingshome.cpp \
+ ksettingsforecastdecl.ui ksettingsforecast.cpp \
+ ksettingsplugins.cpp
+
+EXTRA_DIST = ksettingsgeneraldecl.ui ksettingsregisterdecl.ui ksettingsgpgdecl.ui ksettingscolorsdecl.ui ksettingsfontsdecl.ui ksettingsschedulesdecl.ui ksettingsonlinequotesdecl.ui ksettingshomedecl.ui ksettingsforecastdecl.ui
+
+DISTCLEANFILES= ksettingsgeneraldecl.cpp ksettingsgeneraldecl.h ksettingsregisterdecl.cpp ksettingsregisterdecl.h ksettingsgpgdecl.cpp ksettingsgpgdecl.h ksettingscolorsdecl.cpp ksettingscolorsdecl.h ksettingsfontsdecl.cpp ksettingsfontsdecl.h ksettingsschedulesdecl.cpp ksettingsschedulesdecl.h ksettingsonlinequotesdecl.cpp ksettingsonlinequotesdecl.h ksettingshomedecl.cpp ksettingshomedecl.h ksettingsforecastdecl.cpp ksettingsforecastdecl.h
+
+noinst_HEADERS = ksettingsgeneral.h ksettingsregister.h ksettingsgpg.h ksettingscolors.h ksettingsfonts.h ksettingsschedules.h ksettingsonlinequotes.h ksettingshome.h ksettingsforecast.h ksettingsplugins.h
+
+messages: rc.cpp
diff --git a/kmymoney2/dialogs/settings/ksettingscolors.cpp b/kmymoney2/dialogs/settings/ksettingscolors.cpp
new file mode 100644
index 0000000..727241c
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingscolors.cpp
@@ -0,0 +1,37 @@
+/***************************************************************************
+ ksettingscolors.cpp
+ --------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingscolors.h"
+
+KSettingsColors::KSettingsColors(QWidget* parent, const char* name) :
+ KSettingsColorsDecl(parent, name)
+{
+}
+
+KSettingsColors::~KSettingsColors()
+{
+}
+
+#include "ksettingscolors.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingscolors.h b/kmymoney2/dialogs/settings/ksettingscolors.h
new file mode 100644
index 0000000..896ad85
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingscolors.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ ksettingscolors.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSCOLORS_H
+#define KSETTINGSCOLORS_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingscolorsdecl.h"
+
+class KSettingsColors : public KSettingsColorsDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsColors(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsColors();
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingscolorsdecl.ui b/kmymoney2/dialogs/settings/ksettingscolorsdecl.ui
new file mode 100644
index 0000000..2d4d15b
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingscolorsdecl.ui
@@ -0,0 +1,406 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsColorsDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsColorsDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>453</width>
+ <height>402</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Color settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Foreground</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Text colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Grid color</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Erronous transaction</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Value with missing conversion rate</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_listMissingConversionRate</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>0</red>
+ <green>0</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_listNegativeValueColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Negative value</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_listErronousTransactionColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_listGridColor</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>154</red>
+ <green>154</green>
+ <blue>154</blue>
+ </color>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Background</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_useSystemColors</cstring>
+ </property>
+ <property name="text">
+ <string>Use system colors</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_individualColorFrame</cstring>
+ </property>
+ <property name="title">
+ <string>List background colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Normal</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Alternate</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_listColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>240</red>
+ <green>240</green>
+ <blue>240</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_listBGColor</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Special background colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>Ledger group separator</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_groupMarkerColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>170</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Required field</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_requiredFieldColor</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>221</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Imported transaction</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_importedTransactionColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Matched transaction</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_matchedTransactionColor</cstring>
+ </property>
+ <property name="paletteBackgroundColor">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>221</blue>
+ </color>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>152</red>
+ <green>251</green>
+ <blue>152</blue>
+ </color>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kcfg_useSystemColors</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_individualColorFrame</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsfonts.cpp b/kmymoney2/dialogs/settings/ksettingsfonts.cpp
new file mode 100644
index 0000000..a4aef71
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsfonts.cpp
@@ -0,0 +1,37 @@
+/***************************************************************************
+ ksettingsfonts.cpp
+ --------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingsfonts.h"
+
+KSettingsFonts::KSettingsFonts(QWidget* parent, const char* name) :
+ KSettingsFontsDecl(parent, name)
+{
+}
+
+KSettingsFonts::~KSettingsFonts()
+{
+}
+
+#include "ksettingsfonts.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsfonts.h b/kmymoney2/dialogs/settings/ksettingsfonts.h
new file mode 100644
index 0000000..40cb9de
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsfonts.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ ksettingsfonts.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSFONTS_H
+#define KSETTINGSFONTS_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsfontsdecl.h"
+
+class KSettingsFonts : public KSettingsFontsDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsFonts(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsFonts();
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingsfontsdecl.ui b/kmymoney2/dialogs/settings/ksettingsfontsdecl.ui
new file mode 100644
index 0000000..cbaefeb
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsfontsdecl.ui
@@ -0,0 +1,131 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsFontsDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsFontsDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>222</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Font settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_useSystemFont</cstring>
+ </property>
+ <property name="text">
+ <string>Use system fonts</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_individualFontsFrame</cstring>
+ </property>
+ <property name="title">
+ <string>Individual font settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KFontRequester" row="0" column="2">
+ <property name="name">
+ <cstring>kcfg_listCellFont</cstring>
+ </property>
+ </widget>
+ <widget class="KFontRequester" row="1" column="2">
+ <property name="name">
+ <cstring>kcfg_listHeaderFont</cstring>
+ </property>
+ </widget>
+ <spacer row="0" column="1">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>110</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>100</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Cell font</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Header font</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kcfg_useSystemFont</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_individualFontsFrame</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsforecast.cpp b/kmymoney2/dialogs/settings/ksettingsforecast.cpp
new file mode 100644
index 0000000..0a74252
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsforecast.cpp
@@ -0,0 +1,37 @@
+/***************************************************************************
+ ksettingsforecast.cpp
+ --------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingsforecast.h"
+
+KSettingsForecast::KSettingsForecast(QWidget* parent, const char* name) :
+ KSettingsForecastDecl(parent, name)
+{
+}
+
+KSettingsForecast::~KSettingsForecast()
+{
+}
+
+#include "ksettingsforecast.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsforecast.h b/kmymoney2/dialogs/settings/ksettingsforecast.h
new file mode 100644
index 0000000..7195eee
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsforecast.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ ksettingsforecast.h
+ -------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSFORECAST_H
+#define KSETTINGSFORECAST_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsforecastdecl.h"
+
+class KSettingsForecast : public KSettingsForecastDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsForecast(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsForecast();
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingsforecastdecl.ui b/kmymoney2/dialogs/settings/ksettingsforecastdecl.ui
new file mode 100644
index 0000000..c412f81
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsforecastdecl.ui
@@ -0,0 +1,268 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsForecastDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsForecastDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>497</width>
+ <height>379</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Forecast Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_forecastAccountCycle</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Number of Days of Account Cycle:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_forecastDays</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Day of Month to start Forecast:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_beginForecastDay</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Number of Days to Forecast:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="0" column="1">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>133</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0">
+ <property name="name">
+ <cstring>kcfg_forecastMethod</cstring>
+ </property>
+ <property name="title">
+ <string>Forecast Method</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton9</cstring>
+ </property>
+ <property name="text">
+ <string>Scheduled and Future Transactions</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton10</cstring>
+ </property>
+ <property name="text">
+ <string>History-based</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>History-based settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Number of Cycles to use in Forecast:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>kcfg_forecastCycles</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>130</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ <widget class="QButtonGroup" row="1" column="0">
+ <property name="name">
+ <cstring>kcfg_historyMethod</cstring>
+ </property>
+ <property name="title">
+ <string>History Forecast Method</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton11</cstring>
+ </property>
+ <property name="text">
+ <string>Simple Moving Average</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton12</cstring>
+ </property>
+ <property name="text">
+ <string>Weighted Moving Average</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton13</cstring>
+ </property>
+ <property name="text">
+ <string>Linear Regression</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsgeneral.cpp b/kmymoney2/dialogs/settings/ksettingsgeneral.cpp
new file mode 100644
index 0000000..5acdd08
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsgeneral.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+ ksettingsgeneral.cpp
+ --------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klineedit.h>
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneydateinput.h>
+#include "ksettingsgeneral.h"
+
+KSettingsGeneral::KSettingsGeneral(QWidget* parent, const char* name) :
+ KSettingsGeneralDecl(parent, name)
+{
+ // hide the internally used date field
+ kcfg_StartDate->hide();
+ kcfg_hiddenViews->hide();
+
+ // for now, we don't show the widgets for view selection
+ m_viewLabel->hide();
+ m_viewList->hide();
+
+ // setup connections, so that the sort optios get loaded once the edit fields are filled
+ connect(kcfg_StartDate, SIGNAL(valueChanged(const QDate&)), this, SLOT(slotLoadStartDate(const QDate&)));
+
+ // setup connections, so that changes by the user are forwarded to the (hidden) edit fields
+ connect(m_startDateEdit, SIGNAL(dateChanged(const QDate&)), kcfg_StartDate, SLOT(setDate(const QDate&)));
+}
+
+KSettingsGeneral::~KSettingsGeneral()
+{
+}
+
+void KSettingsGeneral::slotLoadStartDate(const QDate&)
+{
+ // only need this once
+ disconnect(kcfg_StartDate, SIGNAL(valueChanged(const QDate&)), this, SLOT(slotLoadStartDate(const QDate&)));
+ m_startDateEdit->setDate(kcfg_StartDate->date());
+}
+
+#include "ksettingsgeneral.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsgeneral.h b/kmymoney2/dialogs/settings/ksettingsgeneral.h
new file mode 100644
index 0000000..3bd0992
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsgeneral.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ ksettingsgeneral.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSGENERAL_H
+#define KSETTINGSGENERAL_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsgeneraldecl.h"
+
+class KSettingsGeneral : public KSettingsGeneralDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsGeneral(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsGeneral();
+
+protected slots:
+ void slotLoadStartDate(const QDate&);
+
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingsgeneraldecl.ui b/kmymoney2/dialogs/settings/ksettingsgeneraldecl.ui
new file mode 100644
index 0000000..9eeb181
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsgeneraldecl.ui
@@ -0,0 +1,646 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsGeneralDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsGeneralDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>614</width>
+ <height>438</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>General Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Global</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_StartLastViewSelected</cstring>
+ </property>
+ <property name="title">
+ <string>Startup page options</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Start with homepage</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Start with last selected view</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Precision settings</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Price precision</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>kcfg_PricePrecision</cstring>
+ </property>
+ <property name="maxValue">
+ <number>10</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>digits</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Autosave options</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_AutoSaveFile</cstring>
+ </property>
+ <property name="text">
+ <string>Autosave periodically</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_periodFrame</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>kcfg_AutoSavePeriod</cstring>
+ </property>
+ <property name="maxValue">
+ <number>60</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>minutes</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>354</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="title">
+ <string>Fiscal Year</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Your fiscal year starts on</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kcfg_FiscalYearBeginDay</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>January</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>February</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>March</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>April</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>May</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>June</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>July</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>August</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>September</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>October</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>November</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>December</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_FiscalYearBegin</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>90</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Views</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_syncLedgerInvestment</cstring>
+ </property>
+ <property name="text">
+ <string>Synchronize account selection of ledger and investment view</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kcfg_hiddenViews</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_viewLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Check the views you want to enable, uncheck those you want to hide, because you don't need the functionality.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>m_viewList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>2</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_iconSize</cstring>
+ </property>
+ <property name="title">
+ <string>Icon size of navigation bar</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radioButton3</cstring>
+ </property>
+ <property name="text">
+ <string>Micro (16px)</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radioButton4</cstring>
+ </property>
+ <property name="text">
+ <string>Small (32px)</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>radioButton5</cstring>
+ </property>
+ <property name="text">
+ <string>Normal (48px)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="1">
+ <property name="name">
+ <cstring>radioButton6</cstring>
+ </property>
+ <property name="text">
+ <string>Large (64px)</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_showTitleBar</cstring>
+ </property>
+ <property name="text">
+ <string>Show title bar on each page</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Filter</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Accounts / Categories</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_HideUnusedCategory</cstring>
+ </property>
+ <property name="text">
+ <string>Don't show unused categories</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option hides all categories in the categories view that are not used in at least a single transaction. They are still shown in the category selection lists.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_HideClosedAccounts</cstring>
+ </property>
+ <property name="text">
+ <string>Don't show closed accounts</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option hides all accounts that have been closed by the user in views and selection lists.
+
+You can use &lt;b&gt;View/Show all accounts&lt;/b&gt; to temporarily show hidden accounts in the views.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ExpertMode</cstring>
+ </property>
+ <property name="text">
+ <string>Show equity accounts</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Schedules</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_HideFinishedSchedules</cstring>
+ </property>
+ <property name="text">
+ <string>Don't show finished schedules</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option hides all finished schedules in the schedules view.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Transactions</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Don't show transactions prior to</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_startDateEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QDateEdit">
+ <property name="name">
+ <cstring>kcfg_StartDate</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>63</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_HideReconciledTransactions</cstring>
+ </property>
+ <property name="text">
+ <string>Don't show reconciled transactions</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option hides all reconciled transactions in the ledger view.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>kcfg_AutoSaveFile</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_periodFrame</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsgpg.cpp b/kmymoney2/dialogs/settings/ksettingsgpg.cpp
new file mode 100644
index 0000000..2dba83e
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsgpg.cpp
@@ -0,0 +1,200 @@
+/***************************************************************************
+ ksettingsgpg.cpp
+ --------------------
+ copyright : (C) 2005, 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kled.h>
+#include <klineedit.h>
+#include <keditlistbox.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingsgpg.h"
+#include <kmymoney/kgpgfile.h>
+
+#define RECOVER_KEY_ID "0xD2B08440"
+#define RECOVER_KEY_ID_FULL "59B0F826D2B08440"
+
+KSettingsGpg::KSettingsGpg(QWidget* parent, const char* name) :
+ KSettingsGpgDecl(parent, name),
+ m_checkCount(0),
+ m_needCheckList(true),
+ m_listOk(false)
+{
+ setEnabled(KGPGFile::GPGAvailable());
+
+ // don't show the widget in which the master key is actually kept
+ kcfg_GpgRecipient->hide();
+
+ connect(kcfg_WriteDataEncrypted, SIGNAL(toggled(bool)), this, SLOT(slotStatusChanged(bool)));
+ connect(m_masterKeyCombo, SIGNAL(activated(int)), this, SLOT(slotIdChanged()));
+ connect(kcfg_GpgRecipientList, SIGNAL(changed()), this, SLOT(slotIdChanged()));
+ connect(kcfg_GpgRecipientList, SIGNAL(added(const QString&)), this, SLOT(slotKeyListChanged()));
+ connect(kcfg_GpgRecipientList, SIGNAL(removed(const QString&)), this, SLOT(slotKeyListChanged()));
+
+ // Initial state setup
+ slotStatusChanged(kcfg_WriteDataEncrypted->isChecked());
+}
+
+KSettingsGpg::~KSettingsGpg()
+{
+}
+
+void KSettingsGpg::slotKeyListChanged(void)
+{
+ m_needCheckList = true;
+ slotIdChanged();
+}
+
+void KSettingsGpg::slotIdChanged(void)
+{
+ // this looks a bit awkward. Here's why: KGPGFile::keyAvailable() starts
+ // an external task and processes UI events while it waits for the external
+ // process to finish. Thus, the first time we get here, the external process
+ // is started and the user may press a second key which calls this routine
+ // again.
+ //
+ // The second invocation is counted, but the check is not started until the
+ // first one finishes. Once the external process finishes, we check if we
+ // were called in the meantime and restart the check.
+ if(++m_checkCount == 1) {
+ while(1) {
+ // first we check the current edit field if filled
+ bool keysOk = true;
+ if(!kcfg_GpgRecipientList->currentText().isEmpty()) {
+ keysOk = KGPGFile::keyAvailable(kcfg_GpgRecipientList->currentText());
+ }
+
+ // if it is available, then scan the current list if we need to
+ if(keysOk) {
+ if(m_needCheckList) {
+ QStringList keys = kcfg_GpgRecipientList->items();
+ QStringList::const_iterator it_s;
+ for(it_s = keys.begin(); keysOk && it_s != keys.end(); ++it_s) {
+ if(!KGPGFile::keyAvailable(*it_s))
+ keysOk = false;
+ }
+ m_listOk = keysOk;
+ m_needCheckList = false;
+
+ } else {
+ keysOk = m_listOk;
+ }
+ }
+
+ // did we receive some more requests to check?
+ if(m_checkCount > 1) {
+ m_checkCount = 1;
+ continue;
+ }
+
+ // if we have a master key, we store it in the hidden widget
+ if(m_masterKeyCombo->currentItem() != 0) {
+ QRegExp keyExp(".* \\((.*)\\)");
+ if(keyExp.search(m_masterKeyCombo->currentText()) != -1) {
+ kcfg_GpgRecipient->setText(keyExp.cap(1));
+ }
+ }
+
+ m_userKeysFound->setState(static_cast<KLed::State>(keysOk && (kcfg_GpgRecipientList->items().count() != 0) ? KLed::On : KLed::Off));
+ break;
+ }
+
+ --m_checkCount;
+ }
+}
+
+void KSettingsGpg::show(void)
+{
+ QString masterKey;
+
+ if(m_masterKeyCombo->currentItem() != 0) {
+ QRegExp keyExp(".* \\((.*)\\)");
+ if(keyExp.search(m_masterKeyCombo->currentText()) != -1) {
+ masterKey = keyExp.cap(1);
+ }
+ } else
+ masterKey = kcfg_GpgRecipient->text();
+
+ // fill the secret key combobox with a fresh list
+ m_masterKeyCombo->clear();
+ QStringList keyList;
+ KGPGFile::secretKeyList(keyList);
+
+ for(QStringList::iterator it = keyList.begin(); it != keyList.end(); ++it) {
+ QStringList fields = QStringList::split(":", *it);
+ if(fields[0] != RECOVER_KEY_ID_FULL) {
+ // replace parenthesis in name field with brackets
+ QString name = fields[1];
+ name.replace('(', "[");
+ name.replace(')', "]");
+ name = QString("%1 (0x%2)").arg(name).arg(fields[0]);
+ m_masterKeyCombo->insertItem(name);
+ if(name.contains(masterKey))
+ m_masterKeyCombo->setCurrentItem(name);
+ }
+ }
+
+ // if we don't have at least one secret key, we turn off encryption
+ if(keyList.isEmpty()) {
+ setEnabled(false);
+ kcfg_WriteDataEncrypted->setChecked(false);
+ }
+
+ slotStatusChanged(kcfg_WriteDataEncrypted->isChecked());
+ KSettingsGpgDecl::show();
+}
+
+void KSettingsGpg::slotStatusChanged(bool state)
+{
+ static bool oncePerSession = true;
+ if(state && !KGPGFile::GPGAvailable())
+ state = false;
+
+ if((state == true) && (oncePerSession == true) && isVisible()) {
+ KMessageBox::information(this, QString("<qt>%1</qt>").arg(i18n("You have turned on the GPG encryption support. This means, that new files will be stored encrypted. Existing files will not be encrypted automatically. To achieve encryption of existing files, please use the <b>File/Save as...</b> feature and store the file under a different name. Once confident with the result, feel free to delete the old file and rename the encrypted one to the old name.")), i18n("GPG encryption activated"), "GpgEncryptionActivated");
+ oncePerSession = false;
+ }
+
+ m_idGroup->setEnabled(state);
+ kcfg_EncryptRecover->setEnabled(state);
+ m_masterKeyCombo->setEnabled(state);
+ kcfg_GpgRecipientList->setEnabled(state);
+
+ if(state) {
+ m_recoverKeyFound->setState((KLed::State) (KGPGFile::keyAvailable(RECOVER_KEY_ID) ? KLed::On : KLed::Off));
+ kcfg_EncryptRecover->setEnabled(m_recoverKeyFound->state() == KLed::On);
+ slotIdChanged();
+
+ } else {
+ m_recoverKeyFound->setState(KLed::Off);
+ m_userKeysFound->setState(KLed::Off);
+ }
+}
+
+#include "ksettingsgpg.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsgpg.h b/kmymoney2/dialogs/settings/ksettingsgpg.h
new file mode 100644
index 0000000..ecea6ab
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsgpg.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ ksettingsgpg.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSGPG_H
+#define KSETTINGSGPG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsgpgdecl.h"
+
+class KSettingsGpg : public KSettingsGpgDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsGpg(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsGpg();
+
+public slots:
+ void show(void);
+
+protected slots:
+ void slotStatusChanged(bool state);
+ void slotIdChanged(void);
+ void slotKeyListChanged(void);
+
+private:
+ int m_checkCount;
+ bool m_needCheckList;
+ bool m_listOk;
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingsgpgdecl.ui b/kmymoney2/dialogs/settings/ksettingsgpgdecl.ui
new file mode 100644
index 0000000..15d3bbe
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsgpgdecl.ui
@@ -0,0 +1,238 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsGpgDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsGpgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>601</width>
+ <height>418</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>GPG encryption settings</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This page allows you to set the parameters for encrypted file storage of your &lt;b&gt;KMyMoney&lt;/b&gt; data based on &lt;b&gt;GPG&lt;/b&gt;.&lt;p&gt;
+Access to the settings is disabled if &lt;b&gt;GPG&lt;/b&gt; could not be detected on your system. In this case, please make sure that &lt;b&gt;GPG&lt;/b&gt; is working properly for the current user.&lt;p&gt;
+The &lt;i&gt;additional recovery encryption&lt;/i&gt; is only accessible, if the necessary key for &lt;b&gt;kmymoney-recover@users.sourceforge.net&lt;/b&gt; with id 0x8AFDDC8E is found in your keyring.</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_WriteDataEncrypted</cstring>
+ </property>
+ <property name="text">
+ <string>Use GPG encryption</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_idGroup</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>GPG encryption</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Your key</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>m_masterKeyCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This combo box lists all the secret keys you have in your keyring. Select the one you want to use for encryption when saving to a file.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kcfg_GpgRecipient</cstring>
+ </property>
+ </widget>
+ <widget class="KEditListBox">
+ <property name="name">
+ <cstring>kcfg_GpgRecipientList</cstring>
+ </property>
+ <property name="title">
+ <string>Additonal keys</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="buttons">
+ <set>Remove|Add</set>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the id of the key you want to use for data encryption. This can either be an e-mail address or the hexadecimal key id. In case of the key id don't forget the leading 0x.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLed">
+ <property name="name">
+ <cstring>m_userKeysFound</cstring>
+ </property>
+ <property name="shape">
+ <enum>Circular</enum>
+ </property>
+ <property name="look">
+ <enum>Sunken</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This symbol denotes, if the key for the given user id has been found in your keyring. It is green when found, dark otherwise.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Keys for all of the above user ids found</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLed">
+ <property name="name">
+ <cstring>m_recoverKeyFound</cstring>
+ </property>
+ <property name="shape">
+ <enum>Circular</enum>
+ </property>
+ <property name="look">
+ <enum>Sunken</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This symbol denotes, if the KMyMoney recovery key has been found in your keyring. It is green when found, dark otherwise.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Recover Key available in keyring</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_EncryptRecover</cstring>
+ </property>
+ <property name="text">
+ <string>Also encrypt with KMyMoney's recover key</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>You can specify to encrypt the data also with the KMyMoney recover key. Only the core KMyMoney developers are in posession of the respective private key required to read back such encrypted data.&lt;p&gt;
+
+This mechanism is provided for the case that you have lost your key and cannot access your data anymore. With this option activated, the KMyMoney developers can decrypt the data and supply you with it in a readable form. Please be prepared, that you have to answer a few detailed questions about the contents of your data before we will send it out..</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingshome.cpp b/kmymoney2/dialogs/settings/ksettingshome.cpp
new file mode 100644
index 0000000..d2f471b
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingshome.cpp
@@ -0,0 +1,173 @@
+/***************************************************************************
+ ksettingshome.cpp
+ --------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+#include <qheader.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+#include <kpushbutton.h>
+#include <kglobalsettings.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <ktextedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingshome.h"
+#include "kmymoney2/kmymoneyglobalsettings.h"
+#include "kmymoney2/kmymoneyutils.h"
+
+KSettingsHome::KSettingsHome(QWidget* parent, const char* name) :
+ KSettingsHomeDecl(parent, name),
+ m_noNeedToUpdateList(false)
+{
+ m_homePageList->addColumn("");
+ m_homePageList->setSorting(-1);
+ m_homePageList->header()->hide();
+ m_homePageList->setAllColumnsShowFocus(true);
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem upButtonItem( i18n( "&Up" ),
+ QIconSet(il->loadIcon("up", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Move selected item up"),
+ i18n("Use this to move the selected item up by one position in the list."));
+ KGuiItem downButtonItem( i18n( "&Down" ),
+ QIconSet(il->loadIcon("down", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Move selected item down"),
+ i18n("Use this to move the selected item down by one position in the list."));
+
+ m_upButton->setGuiItem(upButtonItem);
+ m_upButton->setEnabled(false);
+ m_downButton->setGuiItem(downButtonItem);
+ m_downButton->setEnabled(false);
+
+ // connect this, so that the list gets loaded once the edit field is filled
+ connect(kcfg_ItemList, SIGNAL(textChanged()), this, SLOT(slotLoadItems()));
+
+ connect(m_homePageList, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotSelectHomePageItem(QListViewItem *)));
+ connect(m_homePageList, SIGNAL(pressed(QListViewItem*)), this, SLOT(slotUpdateItemList()));
+
+ connect(m_upButton, SIGNAL(clicked()), this, SLOT(slotMoveUp()));
+ connect(m_downButton, SIGNAL(clicked()), this, SLOT(slotMoveDown()));
+
+ // Don't show it to the user, we only need it to load and save the settings
+ kcfg_ItemList->hide();
+}
+
+KSettingsHome::~KSettingsHome()
+{
+}
+
+void KSettingsHome::slotLoadItems(void)
+{
+ if(m_noNeedToUpdateList)
+ return;
+
+ QStringList list = KMyMoneyGlobalSettings::itemList();
+ QStringList::ConstIterator it;
+ int w = 0;
+ m_homePageList->clear();
+ QCheckListItem *sel = 0;
+
+ QFontMetrics fm( KGlobalSettings::generalFont());
+ QCheckListItem* last = 0;
+
+ for(it = list.begin(); it != list.end(); ++it) {
+ int idx = (*it).toInt();
+ // skip over unknown item entries
+ if(idx == 0)
+ continue;
+ bool enabled = idx > 0;
+ if(!enabled) idx = -idx;
+ QCheckListItem* item = new QCheckListItem(m_homePageList, KMyMoneyUtils::homePageItemToString(idx), QCheckListItem::CheckBox);
+ if(last)
+ item->moveItem(last);
+
+ // qDebug("Adding %s", item->text(0).latin1());
+ item->setOn(enabled);
+ if(item->width(fm, m_homePageList, 0) > w)
+ w = item->width(fm, m_homePageList, 0);
+
+ if(sel == 0)
+ sel = item;
+ last = item;
+ }
+
+ if(sel) {
+ m_homePageList->setSelected(sel, true);
+ slotSelectHomePageItem(sel);
+ }
+}
+
+void KSettingsHome::slotUpdateItemList(void)
+{
+ QString list;
+ QListViewItem *it;
+
+ for(it = m_homePageList->firstChild(); it; ) {
+ int item = KMyMoneyUtils::stringToHomePageItem(it->text(0));
+ if(!(static_cast<QCheckListItem*>(it)->isOn()))
+ item = -item;
+ list += QString::number(item);
+ it = it->nextSibling();
+ if(it)
+ list += ",";
+ }
+
+ // don't update the list
+ m_noNeedToUpdateList = true;
+ kcfg_ItemList->setText(list);
+ m_noNeedToUpdateList = false;
+}
+
+void KSettingsHome::slotSelectHomePageItem(QListViewItem *item)
+{
+ m_upButton->setEnabled(m_homePageList->firstChild() != item);
+ m_downButton->setEnabled(item->nextSibling());
+}
+
+void KSettingsHome::slotMoveUp(void)
+{
+ QListViewItem *item = m_homePageList->currentItem();
+ QListViewItem *prev = item->itemAbove();
+ if(prev) {
+ prev->moveItem(item);
+ slotSelectHomePageItem(item);
+ slotUpdateItemList();
+ }
+}
+
+void KSettingsHome::slotMoveDown(void)
+{
+ QListViewItem *item = m_homePageList->currentItem();
+ QListViewItem *next = item->nextSibling();
+ if(next) {
+ item->moveItem(next);
+ slotSelectHomePageItem(item);
+ slotUpdateItemList();
+ }
+}
+
+#include "ksettingshome.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingshome.h b/kmymoney2/dialogs/settings/ksettingshome.h
new file mode 100644
index 0000000..c461210
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingshome.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ ksettingshome.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSHOME_H
+#define KSETTINGSHOME_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingshomedecl.h"
+
+class KSettingsHome : public KSettingsHomeDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsHome(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsHome();
+
+protected slots:
+ void slotLoadItems(void);
+ void slotUpdateItemList(void);
+ void slotSelectHomePageItem(QListViewItem *);
+ void slotMoveUp(void);
+ void slotMoveDown(void);
+
+private:
+ bool m_noNeedToUpdateList;
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingshomedecl.ui b/kmymoney2/dialogs/settings/ksettingshomedecl.ui
new file mode 100644
index 0000000..49f6251
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingshomedecl.ui
@@ -0,0 +1,231 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsHomeDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsHomeDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>659</width>
+ <height>414</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Homepage Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="2">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_upButton</cstring>
+ </property>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_downButton</cstring>
+ </property>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>70</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <spacer row="0" column="3">
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Selected entries are shown on the home page of the application.&lt;p&gt;
+Use the buttons and checkboxes to customize the layout of the home page.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="KTextEdit" row="0" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>kcfg_ItemList</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KListView" row="0" column="1" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>m_homePageList</cstring>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupbox</cstring>
+ </property>
+ <property name="title">
+ <string>Homepage/Summary page font scaling</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>percentageLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Percentage of default font size:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kcfg_RememberFontSize</cstring>
+ </property>
+ <property name="text">
+ <string>Remember font size when leaving the program if manually changed with mouse-wheel</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_FontSizePercentage</cstring>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>1000</number>
+ </property>
+ </widget>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupbox2</cstring>
+ </property>
+ <property name="title">
+ <string>Information display</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kcfg_ShowLimitInfo</cstring>
+ </property>
+ <property name="text">
+ <string>Show Account Limit Information</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsonlinequotes.cpp b/kmymoney2/dialogs/settings/ksettingsonlinequotes.cpp
new file mode 100644
index 0000000..db4dc1e
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsonlinequotes.cpp
@@ -0,0 +1,219 @@
+/***************************************************************************
+ kmymoneyonlinequoteconfig.cpp - description
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregexp.h>
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingsonlinequotes.h"
+#include "kmymoney2/converter/webpricequote.h"
+
+KSettingsOnlineQuotes::KSettingsOnlineQuotes(QWidget *parent, const char *name )
+ : KSettingsOnlineQuotesDecl(parent, name)
+{
+ QStringList groups = WebPriceQuote::quoteSources();
+
+ loadList(true /*updateResetList*/);
+
+ m_updateButton->setEnabled(false);
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem updateButtenItem( i18n("&Update" ),
+ QIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Accepts the entered data and stores it"),
+ i18n("Use this to accept the modified data."));
+ m_updateButton->setGuiItem(updateButtenItem);
+
+ KGuiItem deleteButtenItem( i18n( "&Delete" ),
+ QIconSet(il->loadIcon("editdelete", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Delete the selected source entry"),
+ i18n("Use this to delete the selected online source entry"));
+ m_deleteButton->setGuiItem(deleteButtenItem);
+
+ KGuiItem newButtenItem( i18n( "&New..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new source entry for online quotes"),
+ i18n("Use this to create a new entry for online quotes"));
+ m_newButton->setGuiItem(newButtenItem);
+
+ connect(m_updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateEntry()));
+ connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewEntry()));
+
+ connect(m_quoteSourceList, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotLoadWidgets(QListViewItem*)));
+ connect(m_quoteSourceList, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotLoadWidgets(QListViewItem*)));
+ connect(m_quoteSourceList, SIGNAL(itemRenamed(QListViewItem*,const QString&,int)), this, SLOT(slotEntryRenamed(QListViewItem*,const QString&,int)));
+
+ connect(m_editURL, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editSymbol, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editDate, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editDateFormat, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editPrice, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_skipStripping, SIGNAL(toggled(bool)), this, SLOT(slotEntryChanged()));
+
+ // FIXME deleting a source is not yet implemented
+ m_deleteButton->setEnabled(false);
+}
+
+void KSettingsOnlineQuotes::loadList(const bool updateResetList)
+{
+ QStringList groups = WebPriceQuote::quoteSources();
+
+ if(updateResetList)
+ m_resetList.clear();
+ m_quoteSourceList->clear();
+ QStringList::Iterator it;
+ for(it = groups.begin(); it != groups.end(); ++it) {
+ new QListViewItem(m_quoteSourceList, *it);
+ if(updateResetList)
+ m_resetList += WebPriceQuoteSource(*it);
+ }
+
+ QListViewItem* first = m_quoteSourceList->firstChild();
+ if(first)
+ m_quoteSourceList->setSelected(first, true);
+ slotLoadWidgets(first);
+
+ m_newButton->setEnabled(m_quoteSourceList->findItem(i18n("New Quote Source"), 0) == 0);
+}
+
+void KSettingsOnlineQuotes::resetConfig(void)
+{
+ QStringList::ConstIterator it;
+ QStringList groups = WebPriceQuote::quoteSources();
+
+ // delete all currently defined entries
+ for(it = groups.begin(); it != groups.end(); ++it) {
+ WebPriceQuoteSource(*it).remove();
+ }
+
+ // and write back the one's from the reset list
+ QValueList<WebPriceQuoteSource>::ConstIterator itr;
+ for(itr = m_resetList.begin(); itr != m_resetList.end(); ++itr) {
+ (*itr).write();
+ }
+
+ loadList();
+}
+
+void KSettingsOnlineQuotes::slotLoadWidgets(QListViewItem* item)
+{
+ m_editURL->setEnabled(true);
+ m_editSymbol->setEnabled(true);
+ m_editPrice->setEnabled(true);
+ m_editDate->setEnabled(true);
+ m_editDateFormat->setEnabled(true);
+ m_skipStripping->setEnabled(true);
+ m_editURL->setText(QString());
+ m_editSymbol->setText(QString());
+ m_editPrice->setText(QString());
+ m_editDate->setText(QString());
+ m_editDateFormat->setText(QString());
+
+ if(item) {
+ m_currentItem = WebPriceQuoteSource(item->text(0));
+ m_editURL->setText(m_currentItem.m_url);
+ m_editSymbol->setText(m_currentItem.m_sym);
+ m_editPrice->setText(m_currentItem.m_price);
+ m_editDate->setText(m_currentItem.m_date);
+ m_editDateFormat->setText(m_currentItem.m_dateformat);
+ m_skipStripping->setChecked(m_currentItem.m_skipStripping);
+ } else {
+ m_editURL->setEnabled(false);
+ m_editSymbol->setEnabled(false);
+ m_editPrice->setEnabled(false);
+ m_editDate->setEnabled(false);
+ m_editDateFormat->setEnabled(false);
+ m_skipStripping->setEnabled(false);
+ }
+
+ m_updateButton->setEnabled(false);
+
+}
+
+void KSettingsOnlineQuotes::slotEntryChanged(void)
+{
+ bool modified = m_editURL->text() != m_currentItem.m_url
+ || m_editSymbol->text() != m_currentItem.m_sym
+ || m_editDate->text() != m_currentItem.m_date
+ || m_editDateFormat->text() != m_currentItem.m_dateformat
+ || m_editPrice->text() != m_currentItem.m_price
+ || m_skipStripping->isChecked() != m_currentItem.m_skipStripping;
+
+ m_updateButton->setEnabled(modified);
+}
+
+void KSettingsOnlineQuotes::slotUpdateEntry(void)
+{
+ m_currentItem.m_url = m_editURL->text();
+ m_currentItem.m_sym = m_editSymbol->text();
+ m_currentItem.m_date = m_editDate->text();
+ m_currentItem.m_dateformat = m_editDateFormat->text();
+ m_currentItem.m_price = m_editPrice->text();
+ m_currentItem.m_skipStripping = m_skipStripping->isChecked();
+ m_currentItem.write();
+ slotEntryChanged();
+}
+
+void KSettingsOnlineQuotes::slotNewEntry(void)
+{
+ WebPriceQuoteSource newSource(i18n("New Quote Source"));
+ newSource.write();
+ loadList();
+ QListViewItem* item = m_quoteSourceList->findItem(i18n("New Quote Source"), 0);
+ if(item) {
+ m_quoteSourceList->setSelected(item, true);
+ slotLoadWidgets(item);
+ }
+}
+
+void KSettingsOnlineQuotes::slotEntryRenamed(QListViewItem* item, const QString& text, int /* col */)
+{
+ int nameCount = 0;
+ QListViewItemIterator it(m_quoteSourceList);
+ while(it.current()) {
+ if(it.current()->text(0) == text)
+ ++nameCount;
+ ++it;
+ }
+
+ // Make sure we get a non-empty and unique name
+ if(text.length() > 0 && nameCount == 1) {
+ m_currentItem.rename(text);
+ } else {
+ item->setText(0, m_currentItem.m_name);
+ }
+ m_newButton->setEnabled(m_quoteSourceList->findItem(i18n("New Quote Source"), 0) == 0);
+}
+
+#include "ksettingsonlinequotes.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsonlinequotes.h b/kmymoney2/dialogs/settings/ksettingsonlinequotes.h
new file mode 100644
index 0000000..8c0b6f0
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsonlinequotes.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ kmymoneyonlinequoteconfig.h - description
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSONLINEQUOTES_H
+#define KSETTINGSONLINEQUOTES_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsonlinequotesdecl.h"
+#include "kmymoney2/converter/webpricequote.h"
+
+class KSettingsOnlineQuotes : public KSettingsOnlineQuotesDecl
+{
+ Q_OBJECT
+public:
+ KSettingsOnlineQuotes(QWidget* parent = 0, const char *name = 0);
+ virtual ~KSettingsOnlineQuotes() {}
+
+ void writeConfig(void) {}
+ void readConfig(void) {}
+ void resetConfig(void);
+
+protected slots:
+ void slotUpdateEntry(void);
+ void slotLoadWidgets(QListViewItem* item);
+ void slotEntryChanged(void);
+ void slotNewEntry(void);
+ void slotEntryRenamed(QListViewItem* item, const QString& text, int col);
+
+protected:
+ void loadList(const bool updateResetList = false);
+
+private:
+ QValueList<WebPriceQuoteSource> m_resetList;
+ WebPriceQuoteSource m_currentItem;
+};
+
+#endif
diff --git a/kmymoney2/dialogs/settings/ksettingsonlinequotesdecl.ui b/kmymoney2/dialogs/settings/ksettingsonlinequotesdecl.ui
new file mode 100644
index 0000000..3077b78
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsonlinequotesdecl.ui
@@ -0,0 +1,234 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsOnlineQuotesDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsOnlineQuotesDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>512</width>
+ <height>442</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Online Quotes</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_quoteSourceList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ <property name="itemsRenameable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupParsing</cstring>
+ </property>
+ <property name="title">
+ <string>Details</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;i&gt;Enter regular expressions which can be used to parse the data returned from the URL entered above. The symbol, price, and date must be found in the quote data to be usable. You may also try the KMyMoney user's mailinglist at &lt;a href="mailto:kmymoney2-user@lists.sourceforge.net"&gt;kmymoney2-user@lists.sourceforge.net&lt;/a&gt; to find what settings work for other users in your country.&lt;/i&gt;</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Symbol</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editSymbol</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the symbol from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editPrice</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the price from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editURL</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>URL to be used to download the quote</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the URL from which stock quotes will be fetched. &lt;b&gt;%1&lt;/b&gt; will be replaced with the symbol for the security being quoted. For currency conversions, &lt;b&gt;%2&lt;/b&gt; will be replaced with the currency to be quoted and &lt;b&gt;%1&lt;/b&gt; with the currency the quote is based on.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editDate</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the date from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Date Format</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_editDateFormat</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the date from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="2">
+ <property name="name">
+ <cstring>m_skipStripping</cstring>
+ </property>
+ <property name="text">
+ <string>Skip HTML stripping</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;For easier processing of the data returned by the online source, KMyMoney usually strips unused parts before it is parsed with the regular expressions. If matching of the fields relies on those items, then use this option to turn stripping off.&lt;/p&gt;
+
+&lt;p&gt;The following items are usually removed by stripping:
+
+&lt;ul&gt;
+&lt;li&gt;HTML tags such as &lt;b&gt;&amp;lt;tag&amp;gt;&lt;/b&gt;&lt;/li&gt;
+&lt;li&gt;&amp; encoded characters such as &lt;b&gt;&amp;amp;nbsp;&lt;/b&gt;&lt;/li&gt;
+&lt;li&gt;duplicate whitespace&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_newButton</cstring>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>240</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_updateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Update</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsplugins.cpp b/kmymoney2/dialogs/settings/ksettingsplugins.cpp
new file mode 100644
index 0000000..0887315
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsplugins.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ ksettingsplugins.cpp
+ -------------------
+ begin : Thu Feb 12 2009
+ copyright : (C) 2009 Cristian Onet
+ email : onet.cristian@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qstring.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kpluginselector.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/plugins/pluginloader.h"
+#include "ksettingsplugins.h"
+
+KSettingsPlugins::KSettingsPlugins(QWidget* parent)
+ : QWidget(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget()->reparent(this, QPoint());
+ layout->addWidget(KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget());
+ layout->setSpacing(KDialog::spacingHint());
+}
+
+KSettingsPlugins::~KSettingsPlugins()
+{
+}
+
+void KSettingsPlugins::slotLoadPlugins()
+{
+ KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget()->load();
+}
+
+void KSettingsPlugins::slotSavePlugins()
+{
+ KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget()->save();
+}
+
+void KSettingsPlugins::slotDefaultsPlugins()
+{
+ KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget()->defaults();
+}
+
+#include "ksettingsplugins.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsplugins.h b/kmymoney2/dialogs/settings/ksettingsplugins.h
new file mode 100644
index 0000000..9c36f67
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsplugins.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ ksettingsplugins.h
+ -------------------
+ begin : Thu Feb 12 2009
+ copyright : (C) 2009 Cristian Onet
+ email : onet.cristian@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSPLUGINS_H
+#define KSETTINGSPLUGINS_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KSettingsPlugins : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ KSettingsPlugins(QWidget* parent = 0);
+ ~KSettingsPlugins();
+
+public slots:
+ void slotLoadPlugins();
+ void slotSavePlugins();
+ void slotDefaultsPlugins();
+};
+
+#endif // KSETTINGSPLUGINS_H
diff --git a/kmymoney2/dialogs/settings/ksettingsregister.cpp b/kmymoney2/dialogs/settings/ksettingsregister.cpp
new file mode 100644
index 0000000..9f1fda2
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsregister.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+ ksettingsregister.cpp
+ --------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <ktextedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingsregister.h"
+#include <kmymoney/transactionsortoption.h>
+
+KSettingsRegister::KSettingsRegister(QWidget* parent, const char* name) :
+ KSettingsRegisterDecl(parent, name)
+{
+ // hide the internally used text fields
+ kcfg_sortNormalView->hide();
+ kcfg_sortReconcileView->hide();
+ kcfg_sortSearchView->hide();
+
+ // setup connections, so that the sort optios get loaded once the edit fields are filled
+ connect(kcfg_sortNormalView, SIGNAL(textChanged()), this, SLOT(slotLoadNormal()));
+ connect(kcfg_sortReconcileView, SIGNAL(textChanged()), this, SLOT(slotLoadReconcile()));
+ connect(kcfg_sortSearchView, SIGNAL(textChanged()), this, SLOT(slotLoadSearch()));
+
+ // setup connections, so that changes by the user are forwarded to the (hidden) edit fields
+ connect(m_sortNormalView, SIGNAL(settingsChanged(const QString&)), kcfg_sortNormalView, SLOT(setText(const QString&)));
+ connect(m_sortReconcileView, SIGNAL(settingsChanged(const QString&)), kcfg_sortReconcileView, SLOT(setText(const QString&)));
+ connect(m_sortSearchView, SIGNAL(settingsChanged(const QString&)), kcfg_sortSearchView, SLOT(setText(const QString&)));
+}
+
+KSettingsRegister::~KSettingsRegister()
+{
+}
+
+void KSettingsRegister::slotLoadNormal(void)
+{
+ // only need this once
+ disconnect(kcfg_sortNormalView, SIGNAL(textChanged()), this, SLOT(slotLoadNormal()));
+ m_sortNormalView->setSettings(kcfg_sortNormalView->text());
+}
+
+void KSettingsRegister::slotLoadReconcile(void)
+{
+ // only need this once
+ disconnect(kcfg_sortReconcileView, SIGNAL(textChanged()), this, SLOT(slotLoadReconcile()));
+ m_sortReconcileView->setSettings(kcfg_sortReconcileView->text());
+}
+
+void KSettingsRegister::slotLoadSearch(void)
+{
+ // only need this once
+ disconnect(kcfg_sortSearchView, SIGNAL(textChanged()), this, SLOT(slotLoadSearch()));
+ m_sortSearchView->setSettings(kcfg_sortSearchView->text());
+}
+
+#include "ksettingsregister.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsregister.h b/kmymoney2/dialogs/settings/ksettingsregister.h
new file mode 100644
index 0000000..bcad7eb
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsregister.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ ksettingsregister.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSREGISTER_H
+#define KSETTINGSREGISTER_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsregisterdecl.h"
+
+class KSettingsRegister : public KSettingsRegisterDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsRegister(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsRegister();
+
+protected slots:
+ void slotLoadNormal(void);
+ void slotLoadReconcile(void);
+ void slotLoadSearch(void);
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingsregisterdecl.ui b/kmymoney2/dialogs/settings/ksettingsregisterdecl.ui
new file mode 100644
index 0000000..c03807e
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsregisterdecl.ui
@@ -0,0 +1,549 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsRegisterDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsRegisterDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>632</width>
+ <height>403</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Register settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Display</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowGrid</cstring>
+ </property>
+ <property name="text">
+ <string>Show a grid in the register</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_LedgerLens</cstring>
+ </property>
+ <property name="text">
+ <string>Use the ledger lens</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Using the ledger lens shows the details for the transaction that has focus in the ledger. Usually, when using the transaction form, only a one line summary is displayed for each transaction as the details are shown in the form.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_TransactionForm</cstring>
+ </property>
+ <property name="text">
+ <string>Show transaction form</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_AlwaysShowNrField</cstring>
+ </property>
+ <property name="text">
+ <string>Always show a No. field</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowFancyMarker</cstring>
+ </property>
+ <property name="text">
+ <string>Show group header between transactions</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Draws a larger header above each group of transaction. The grouping depends on the current sort order.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowFiscalMarker</cstring>
+ </property>
+ <property name="text">
+ <string>Show header for the previous and current fiscal year</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>sorting</cstring>
+ </property>
+ <attribute name="title">
+ <string>Sorting</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget3</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Normal view</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>kcfg_sortNormalView</cstring>
+ </property>
+ </widget>
+ <widget class="TransactionSortOption">
+ <property name="name">
+ <cstring>m_sortNormalView</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Reconciliation view</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>kcfg_sortReconcileView</cstring>
+ </property>
+ </widget>
+ <widget class="TransactionSortOption">
+ <property name="name">
+ <cstring>m_sortReconcileView</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Search view</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>kcfg_sortSearchView</cstring>
+ </property>
+ </widget>
+ <widget class="TransactionSortOption">
+ <property name="name">
+ <cstring>m_sortSearchView</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </widget>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Use the &lt;i&gt;left&lt;/i&gt; and &lt;i&gt;right&lt;/i&gt; buttons to add and remove sort options. Use the &lt;i&gt;up&lt;/i&gt; and &lt;i&gt;down&lt;/i&gt; buttons to modify the sort order. Double-Click a selected entry to toggle the sort order between &lt;i&gt;ascending&lt;/i&gt; and &lt;i&gt;descending&lt;/i&gt;.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Data entry</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_CopyTypeToNr</cstring>
+ </property>
+ <property name="text">
+ <string>Insert transaction type into No. field for new transactions</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_AutoIncCheckNumber</cstring>
+ </property>
+ <property name="text">
+ <string>Auto increment check number</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_FocusChangeIsEnter</cstring>
+ </property>
+ <property name="text">
+ <string>Keep changes when selecting a different transaction/split</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_EnterMovesBetweenFields</cstring>
+ </property>
+ <property name="text">
+ <string>Use Enter to move between fields</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_stringMatchFromStart</cstring>
+ </property>
+ <property name="text">
+ <string>Match names from start</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Mark this option, if you always want to match names e.g. for payees from the start. If unset, any substring is matched.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Default reconciliation state</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>Not reconciled</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Cleared</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Reconciled</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_defaultReconciliationState</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Default reconciliation state for transactions entered during reconciliation of an account</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_AutoFillTransaction</cstring>
+ </property>
+ <property name="title">
+ <string>Autofill</string>
+ </property>
+ <property name="exclusive">
+ <bool>false</bool>
+ </property>
+ <property name="selectedId" stdset="0">
+ <number>-1</number>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton1</cstring>
+ </property>
+ <property name="text">
+ <string>No Autofill</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Don't do autofill of transaction data at all.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Same transaction if amount differs less than</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Collect all transactions for the given payee. Treat all transactions that refer to the same category and have an amount with +/- X % as identical. If more than one transaction is found, a list of them is presented to the user.
+
+Selecting 0% will list all transactions.</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kcfg_AutoFillDifference</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Two transactions are usually treated identical for autofill, if they refer the same accounts. They are treated as different transactions though, when their amount varies by more than the percentage given here.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>percent.</string>
+ <comment>Same transaction if amount differs less than percent.</comment>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton3</cstring>
+ </property>
+ <property name="text">
+ <string>with previously most often used transaction for the payee</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The data of the last transaction assigned to the category used most often for this payee is autofilled into the transaction editor.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Import</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Match transactions within days</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kcfg_matchInterval</cstring>
+ </property>
+ <property name="buttonSymbols">
+ <enum>UpDownArrows</enum>
+ </property>
+ <property name="maxValue">
+ <number>99</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>4</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Search for matching transactions within the range of the posting date of the imported transaction +/- the number of given days.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_askForPayeeCategory</cstring>
+ </property>
+ <property name="text">
+ <string>Ask for a new payee's default category</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Whenever a new payee is detected during import of a statement, the user will be asked to assign a default category for this user when this option is selected.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/settings/ksettingsschedules.cpp b/kmymoney2/dialogs/settings/ksettingsschedules.cpp
new file mode 100644
index 0000000..6f9a77c
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsschedules.cpp
@@ -0,0 +1,37 @@
+/***************************************************************************
+ ksettingsschedules.cpp
+ --------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ksettingsschedules.h"
+
+KSettingsSchedules::KSettingsSchedules(QWidget* parent, const char* name) :
+ KSettingsSchedulesDecl(parent, name)
+{
+}
+
+KSettingsSchedules::~KSettingsSchedules()
+{
+}
+
+#include "ksettingsschedules.moc"
diff --git a/kmymoney2/dialogs/settings/ksettingsschedules.h b/kmymoney2/dialogs/settings/ksettingsschedules.h
new file mode 100644
index 0000000..caa7d33
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsschedules.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ ksettingsschedules.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSETTINGSSCHEDULES_H
+#define KSETTINGSSCHEDULES_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2/dialogs/settings/ksettingsschedulesdecl.h"
+
+class KSettingsSchedules : public KSettingsSchedulesDecl
+{
+ Q_OBJECT
+
+public:
+ KSettingsSchedules(QWidget* parent = 0, const char* name = 0);
+ ~KSettingsSchedules();
+};
+#endif
+
diff --git a/kmymoney2/dialogs/settings/ksettingsschedulesdecl.ui b/kmymoney2/dialogs/settings/ksettingsschedulesdecl.ui
new file mode 100644
index 0000000..fca9aa9
--- /dev/null
+++ b/kmymoney2/dialogs/settings/ksettingsschedulesdecl.ui
@@ -0,0 +1,145 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSettingsSchedulesDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSettingsSchedulesDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>482</width>
+ <height>236</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Schedule Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="title">
+ <string>Startup options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_CheckSchedule</cstring>
+ </property>
+ <property name="text">
+ <string>Check schedules on startup</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_dayCountFrame</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Enter transactions this number of days in advance</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>kcfg_CheckSchedulePreview</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Number of days to preview schedules in ledger</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kcfg_SchedulePreview</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>kcfg_CheckSchedule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_dayCountFrame</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/dialogs/transactioneditor.cpp b/kmymoney2/dialogs/transactioneditor.cpp
new file mode 100644
index 0000000..c53d3c6
--- /dev/null
+++ b/kmymoney2/dialogs/transactioneditor.cpp
@@ -0,0 +1,2156 @@
+/***************************************************************************
+ transactioneditor.cpp
+ ----------
+ begin : Wed Jun 07 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qtooltip.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <ktextedit.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+#include <kstdguiitem.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneyaccountcompletion.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyutils.h>
+#include <kmymoney/transactionform.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "../dialogs/ksplittransactiondlg.h"
+#include "../dialogs/kcurrencycalculator.h"
+#include "../dialogs/kselecttransactionsdlg.h"
+
+using namespace KMyMoneyRegister;
+using namespace KMyMoneyTransactionForm;
+
+TransactionEditor::TransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) :
+ m_transactions(list),
+ m_regForm(regForm),
+ m_item(item),
+ m_transaction(item->transaction()),
+ m_split(item->split()),
+ m_lastPostDate(lastPostDate),
+ m_openEditSplits(false)
+{
+ m_item->startEditMode();
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotUpdateAccount()));
+}
+
+TransactionEditor::~TransactionEditor()
+{
+ // Make sure the widgets do not send out signals to the editor anymore
+ // After all, the editor is about to die
+ QMap<QString, QWidget*>::iterator it_w;
+ for(it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) {
+ (*it_w)->disconnect(this);
+ }
+
+ m_regForm->removeEditWidgets(m_editWidgets);
+ m_item->leaveEditMode();
+ emit finishEdit(m_transactions);
+}
+
+void TransactionEditor::slotUpdateAccount(const QString& id)
+{
+ m_account = MyMoneyFile::instance()->account(id);
+ setupPrecision();
+}
+
+void TransactionEditor::slotUpdateAccount(void)
+{
+ // reload m_account as it might have been changed
+ m_account = MyMoneyFile::instance()->account(m_account.id());
+ setupPrecision();
+}
+
+void TransactionEditor::setupPrecision(void)
+{
+ const int prec = (m_account.id().isEmpty()) ? 2 : MyMoneyMoney::denomToPrec(m_account.fraction());
+ QStringList widgets = QStringList::split(",", "amount,deposit,payment");
+ QStringList::const_iterator it_w;
+ for(it_w = widgets.begin(); it_w != widgets.end(); ++it_w) {
+ QWidget * w;
+ if((w = haveWidget(*it_w)) != 0) {
+ dynamic_cast<kMyMoneyEdit*>(w)->setPrecision(prec);
+ }
+ }
+}
+
+void TransactionEditor::setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account, KMyMoneyRegister::Action action)
+{
+ m_account = account;
+ m_initialAction = action;
+ createEditWidgets();
+ m_regForm->arrangeEditWidgets(m_editWidgets, m_item);
+ m_regForm->tabOrder(tabOrderWidgets, m_item);
+ QWidget* w = haveWidget("tabbar");
+ if(w)
+ tabOrderWidgets.append(w);
+ loadEditWidgets(action);
+ m_editWidgets.removeOrphans();
+ clearFinalWidgets();
+ setupFinalWidgets();
+ slotUpdateButtonState();
+}
+
+void TransactionEditor::clearFinalWidgets(void)
+{
+ m_finalEditWidgets.clear();
+}
+
+void TransactionEditor::addFinalWidget(const QWidget* w)
+{
+ if(w) {
+ m_finalEditWidgets << w;
+ }
+}
+
+void TransactionEditor::slotReloadEditWidgets(void)
+{
+}
+
+bool TransactionEditor::eventFilter(QObject* o, QEvent* e)
+{
+ bool rc = false;
+ if(o == haveWidget("number")) {
+ if(e->type() == QEvent::MouseButtonDblClick) {
+ emit assignNumber();
+ rc = true;
+ }
+ }
+
+ // if the object is a widget, the event is a key press event and
+ // the object is one of our edit widgets, then ....
+ if(o->isWidgetType()
+ && (e->type() == QEvent::KeyPress)
+ && m_editWidgets.values().contains(dynamic_cast<QWidget*>(o))) {
+ QKeyEvent* k = dynamic_cast<QKeyEvent*>(e);
+ if((k->state() & Qt::KeyButtonMask) == 0) {
+ bool isFinal = false;
+ QValueList<const QWidget*>::const_iterator it_w;
+ switch(k->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ // we check, if the object is one of the m_finalEditWidgets and if it's
+ // a kMyMoneyEdit object that the value is not 0. If any of that is the
+ // case, it's the final object. In other cases, we convert the enter
+ // key into a TAB key to move between the fields. Of course, we only need
+ // to do this as long as the appropriate option is set. In all other cases,
+ // we treat the return/enter key as such.
+ if(KMyMoneyGlobalSettings::enterMovesBetweenFields()) {
+ for(it_w = m_finalEditWidgets.begin(); !isFinal && it_w != m_finalEditWidgets.end(); ++it_w) {
+ if(*it_w == o) {
+ if(dynamic_cast<const kMyMoneyEdit*>(*it_w)) {
+ isFinal = !(dynamic_cast<const kMyMoneyEdit*>(*it_w)->value().isZero());
+ } else
+ isFinal = true;
+ }
+ }
+ } else
+ isFinal = true;
+
+ // for the non-final objects, we treat the return key as a TAB
+ if(!isFinal) {
+ QKeyEvent evt(e->type(),
+ Key_Tab, 0, k->state(), QString::null,
+ k->isAutoRepeat(), k->count());
+
+ QApplication::sendEvent( o, &evt );
+ // in case of a category item and the split button is visible
+ // send a second event so that we get passed the button.
+ if(dynamic_cast<KMyMoneyCategory*>(o) && dynamic_cast<KMyMoneyCategory*>(o)->splitButton())
+ QApplication::sendEvent( o, &evt );
+
+ } else {
+ QTimer::singleShot(0, this, SIGNAL(returnPressed()));
+ }
+ // don't process any further
+ rc = true;
+ break;
+
+ case Qt::Key_Escape:
+ QTimer::singleShot(0, this, SIGNAL(escapePressed()));
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+void TransactionEditor::slotNumberChanged(const QString& txt)
+{
+ kMyMoneyLineEdit* number = dynamic_cast<kMyMoneyLineEdit*>(haveWidget("number"));
+
+ if(number) {
+ if(MyMoneyFile::instance()->checkNoUsed(m_account.id(), txt)) {
+ if(KMessageBox::questionYesNo(m_regForm, QString("<qt>")+i18n("The number <b>%1</b> has already been used in account <b>%2</b>. Do you want to replace it with the next available number?").arg(txt).arg(m_account.name())+QString("</qt>"), i18n("Duplicate number")) == KMessageBox::Yes) {
+ number->loadText(KMyMoneyUtils::nextCheckNumber(m_account));
+ }
+ }
+ }
+}
+
+void TransactionEditor::slotUpdateButtonState(void)
+{
+ QString reason;
+ emit transactionDataSufficient(isComplete(reason));
+}
+
+QWidget* TransactionEditor::haveWidget(const QString& name) const
+{
+ return m_editWidgets.haveWidget(name);
+}
+
+int TransactionEditor::slotEditSplits(void)
+{
+ return QDialog::Rejected;
+}
+
+#if 0
+ // If we deal with multiple currencies we make sure, that for
+ // transactions with two splits, the transaction's commodity is the
+ // currency of the currently selected account. This saves us from a
+ // lot of grieve later on.
+ // Editing a transaction which has more than two splits and a commodity
+ // that differs from the currency of the current selected account is
+ // not a good idea. We will warn the user and give him a hint if there
+ // is an account where he can perfom the edit operation much better.
+ if(m_transaction.commodity() != m_account.currencyId()) {
+ if(m_transaction.splitCount() == 2) {
+ // in case of two splits, it's easy. We just have to switch the
+ // transactions commodity. Let's assume the following scenario:
+ // - transactions commodity is CA
+ // - account's currencyId is CB
+ // - second split is of course in CA (otherwise we have a real problem)
+ // - Value is V in both splits
+ // - Shares in this account's split is SB
+ // - Shares in the other account's split is SA (and equal to V)
+ //
+ // We do the following:
+ // - change transactions commodity to CB
+ // - set V in both splits to SB
+ // - modify the splits in the transaction
+ try {
+ MyMoneySplit split = m_transaction.splitByAccount(m_account.id(), false);
+ m_transaction.setCommodity(m_account.currencyId());
+ m_split.setValue(m_split.shares());
+ split.setValue(-m_split.shares());
+ m_transaction.modifySplit(m_split);
+ m_transaction.modifySplit(split);
+
+ if(m_transactionPtr) {
+ KMyMoneyTransaction k(m_transaction);
+ k.setSplitId(m_split.id());
+ *m_transactionPtr = k;
+ }
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to update commodity to second splits currency in %s: '%s'", m_transaction.id().data(), e->what().data());
+ delete e;
+ }
+
+ } else {
+ // Find a suitable account
+ MyMoneySecurity sec = MyMoneyFile::instance()->currency(m_transaction.commodity());
+ MyMoneyAccount acc;
+ for(it = m_transaction.splits().begin(); it != m_transaction.splits().end(); ++it) {
+ if((*it).id() == m_split.id())
+ continue;
+ acc = MyMoneyFile::instance()->account((*it).accountId());
+ if((acc.accountGroup() == MyMoneyAccount::Asset
+ || acc.accountGroup() == MyMoneyAccount::Liability)
+ && acc.accountType() != MyMoneyAccount::Stock) {
+ if(m_transaction.commodity() == acc.currencyId())
+ break;
+ }
+ acc = MyMoneyAccount();
+ }
+ QString msg;
+ msg = QString("<p>")+i18n("This transaction has more than two splits and is based on a different currency (%1). Using this account to modify the transaction is currently not very well supported by KMyMoney and may result in false results.").arg(sec.name())+QString(" ");
+ if(acc.id().isEmpty()) {
+ msg += i18n("KMyMoney was not able to find a more appropriate account to edit this transaction. Nevertheless, you are allowed to modify the transaction. If you don't want to edit this transaction, please cancel from editing next.");
+ } else {
+ msg += i18n("Using e.g. <b>%1</b> to edit this transaction is a better choice. Nevertheless, you are allowed to modify the transaction. If you want to use the suggested account instead, please cancel from editing next and change the view to the suggested account.").arg(acc.name());
+ }
+ KMessageBox::information(0, msg);
+ }
+ }
+#endif
+
+void TransactionEditor::setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s)
+{
+ m_transaction = t;
+ m_split = s;
+ loadEditWidgets();
+}
+
+bool TransactionEditor::fixTransactionCommodity(const MyMoneyAccount& account)
+{
+ bool rc = true;
+ bool firstTimeMultiCurrency = true;
+ m_account = account;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // determine the max fraction for this account
+ MyMoneySecurity sec = file->security(m_account.currencyId());
+ int fract = m_account.fraction();
+
+ // scan the list of selected transactions
+ KMyMoneyRegister::SelectedTransactions::iterator it_t;
+ for(it_t = m_transactions.begin(); (rc == true) && (it_t != m_transactions.end()); ++it_t) {
+ // there was a time when the schedule editor did not setup the transaction commodity
+ // let's give a helping hand here for those old schedules
+ if((*it_t).transaction().commodity().isEmpty())
+ (*it_t).transaction().setCommodity(m_account.currencyId());
+ // we need to check things only if a different commodity is used
+ if(m_account.currencyId() != (*it_t).transaction().commodity()) {
+ MyMoneySecurity osec = file->security((*it_t).transaction().commodity());
+ switch((*it_t).transaction().splitCount()) {
+ case 0:
+ // new transaction, guess nothing's here yet ;)
+ break;
+
+ case 1:
+ try {
+ // make sure, that the value is equal to the shares, don't forget our own copy
+ MyMoneySplit& splitB = (*it_t).split(); // reference usage wanted here
+ if(m_split == splitB)
+ m_split.setValue(splitB.shares());
+ splitB.setValue(splitB.shares());
+ (*it_t).transaction().modifySplit(splitB);
+
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to update commodity to second splits currency in %s: '%s'", (*it_t).transaction().id().data(), e->what().data());
+ delete e;
+ }
+ break;
+
+ case 2:
+ // If we deal with multiple currencies we make sure, that for
+ // transactions with two splits, the transaction's commodity is the
+ // currency of the currently selected account. This saves us from a
+ // lot of grieve later on. We just have to switch the
+ // transactions commodity. Let's assume the following scenario:
+ // - transactions commodity is CA
+ // - splitB and account's currencyId is CB
+ // - splitA is of course in CA (otherwise we have a real problem)
+ // - Value is V in both splits
+ // - Shares in splitB is SB
+ // - Shares in splitA is SA (and equal to V)
+ //
+ // We do the following:
+ // - change transactions commodity to CB
+ // - set V in both splits to SB
+ // - modify the splits in the transaction
+ try {
+ // retrieve the splits
+ MyMoneySplit& splitB = (*it_t).split(); // reference usage wanted here
+ MyMoneySplit splitA = (*it_t).transaction().splitByAccount(m_account.id(), false);
+
+ // - set V in both splits to SB. Don't forget our own copy
+ if(m_split == splitB) {
+ m_split.setValue(splitB.shares());
+ }
+ splitB.setValue(splitB.shares());
+ splitA.setValue(-splitB.shares());
+ (*it_t).transaction().modifySplit(splitA);
+ (*it_t).transaction().modifySplit(splitB);
+
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to update commodity to second splits currency in %s: '%s'", (*it_t).transaction().id().data(), e->what().data());
+ delete e;
+ }
+ break;
+
+ default:
+ // TODO: use new logic by adjusting all splits by the price
+ // extracted from the selected split. Inform the user that
+ // this will happen and allow him to stop the processing (rc = false)
+
+ try {
+ QString msg;
+ if(firstTimeMultiCurrency) {
+ firstTimeMultiCurrency = false;
+ if(!isMultiSelection()) {
+ msg = i18n("This transaction has more than two splits and is originally based on a different currency (%1). Using this account to modify the transaction may result in rounding errors. Do you want to continue?").arg(osec.name());
+ } else {
+ msg = i18n("At least one of the selected transactions has more than two splits and is originally based on a different currency (%1). Using this account to modify the transactions may result in rounding errors. Do you want to continue?").arg(osec.name());
+ }
+
+ if(KMessageBox::warningContinueCancel(0, QString("<qt>%1</qt>").arg(msg)) == KMessageBox::Cancel) {
+ rc = false;
+ }
+ }
+
+ if(rc == true) {
+ MyMoneyMoney price;
+ if(!(*it_t).split().shares().isZero() && !(*it_t).split().value().isZero())
+ price = (*it_t).split().shares() / (*it_t).split().value();
+ QValueList<MyMoneySplit>::iterator it_s;
+ MyMoneySplit& mySplit = (*it_t).split();
+ for(it_s = (*it_t).transaction().splits().begin(); it_s != (*it_t).transaction().splits().end(); ++it_s) {
+ MyMoneySplit s = (*it_s);
+ if(s == mySplit) {
+ s.setValue(s.shares());
+ if(mySplit == m_split) {
+ m_split = s;
+ }
+ mySplit = s;
+ } else {
+ s.setValue((s.value() * price).convert(fract));
+ }
+ (*it_t).transaction().modifySplit(s);
+ }
+ }
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to update commodity of split currency in %s: '%s'", (*it_t).transaction().id().data(), e->what().data());
+ delete e;
+ }
+ break;
+ }
+
+ // set the transaction's ommodity to this account's currency
+ (*it_t).transaction().setCommodity(m_account.currencyId());
+
+ // update our copy of the transaction that has the focus
+ if((*it_t).transaction().id() == m_transaction.id()) {
+ m_transaction = (*it_t).transaction();
+ }
+ }
+ }
+ return rc;
+}
+
+void TransactionEditor::assignNextNumber(void)
+{
+ if(canAssignNumber()) {
+ kMyMoneyLineEdit* number = dynamic_cast<kMyMoneyLineEdit*>(haveWidget("number"));
+ number->loadText(KMyMoneyUtils::nextCheckNumber(m_account));
+ }
+}
+
+bool TransactionEditor::canAssignNumber(void) const
+{
+ kMyMoneyLineEdit* number = dynamic_cast<kMyMoneyLineEdit*>(haveWidget("number"));
+ return (number != 0) && (number->text().isEmpty());
+}
+
+void TransactionEditor::setupCategoryWidget(KMyMoneyCategory* category, const QValueList<MyMoneySplit>& splits, QString& categoryId, const char* splitEditSlot, bool /* allowObjectCreation */)
+{
+ disconnect(category, SIGNAL(focusIn()), this, splitEditSlot);
+#if 0
+ // FIXME must deal with the logic that suppressObjectCreation is
+ // automatically turned off when the createItem() signal is connected
+ if(allowObjectCreation)
+ category->setSuppressObjectCreation(false);
+#endif
+
+ switch(splits.count()) {
+ case 0:
+ categoryId = QString();
+ if(!category->currentText().isEmpty()) {
+ category->setCurrentText();
+ // make sure, we don't see the selector
+ category->completion()->hide();
+ }
+ category->completion()->setSelected(QString());
+ break;
+
+ case 1:
+ categoryId = splits[0].accountId();
+ category->completion()->setSelected(categoryId);
+ category->slotItemSelected(categoryId);
+ break;
+
+ default:
+ categoryId = QString();
+ category->setSplitTransaction();
+ connect(category, SIGNAL(focusIn()), this, splitEditSlot);
+#if 0
+ // FIXME must deal with the logic that suppressObjectCreation is
+ // automatically turned off when the createItem() signal is connected
+ if(allowObjectCreation)
+ category->setSuppressObjectCreation(true);
+#endif
+ break;
+ }
+}
+
+bool TransactionEditor::enterTransactions(QString& newId, bool askForSchedule, bool suppressBalanceWarnings)
+{
+ newId = QString();
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // make sure to run through all stuff that is tied to 'focusout events'.
+ m_regForm->parentWidget()->setFocus();
+ QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 10);
+
+ // we don't need to update our widgets anymore, so we just disconnect the signal
+ disconnect(file, SIGNAL(dataChanged()), this, SLOT(slotReloadEditWidgets()));
+
+ KMyMoneyRegister::SelectedTransactions::iterator it_t;
+ MyMoneyTransaction t;
+ bool newTransactionCreated = false;
+
+ // make sure, that only a single new transaction can be created.
+ // we need to update m_transactions to contain the new transaction
+ // which is then stored in the variable t when we leave the loop.
+ // m_transactions will be sent out in finishEdit() and forces
+ // the new transaction to be selected in the ledger view
+
+ // collect the transactions to be stored in the engine in a local
+ // list first, so that the user has a chance to interrupt the storage
+ // process
+ QValueList<MyMoneyTransaction> list;
+ bool storeTransactions = true;
+
+ // collect transactions
+ for(it_t = m_transactions.begin(); storeTransactions && !newTransactionCreated && it_t != m_transactions.end(); ++it_t) {
+ storeTransactions = createTransaction(t, (*it_t).transaction(), (*it_t).split());
+ // if the transaction was created successfully, append it to the list
+ if(storeTransactions)
+ list.append(t);
+
+ // if we created a new transaction keep that in mind
+ if(t.id().isEmpty())
+ newTransactionCreated = true;
+ }
+
+ // if not interrupted by user, continue to store them in the engine
+ if(storeTransactions) {
+ int i = 0;
+ emit statusMsg(i18n("Storing transactions"));
+ emit statusProgress(0, list.count());
+
+ MyMoneyFileTransaction ft;
+
+ try {
+ QValueList<MyMoneyTransaction>::iterator it_ts;
+ QMap<QString, bool> minBalanceEarly;
+ QMap<QString, bool> minBalanceAbsolute;
+ QMap<QString, bool> maxCreditEarly;
+ QMap<QString, bool> maxCreditAbsolute;
+ QMap<QString, bool> accountIds;
+
+ for(it_ts = list.begin(); it_ts != list.end(); ++it_ts) {
+ // if we have a categorization, make sure we remove
+ // the 'imported' flag automagically
+ if((*it_ts).splitCount() > 1)
+ (*it_ts).setImported(false);
+
+ // create information about min and max balances
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = (*it_ts).splits().begin(); it_s != (*it_ts).splits().end(); ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ accountIds[acc.id()] = true;
+ MyMoneyMoney balance = file->balance(acc.id());
+ if(!acc.value("minBalanceEarly").isEmpty()) {
+ minBalanceEarly[acc.id()] = balance < MyMoneyMoney(acc.value("minBalanceEarly"));
+ }
+ if(!acc.value("minBalanceAbsolute").isEmpty()) {
+ minBalanceAbsolute[acc.id()] = balance < MyMoneyMoney(acc.value("minBalanceAbsolute"));
+ minBalanceEarly[acc.id()] = false;
+ }
+ if(!acc.value("maxCreditEarly").isEmpty()) {
+ maxCreditEarly[acc.id()] = balance < MyMoneyMoney(acc.value("maxCreditEarly"));
+ }
+ if(!acc.value("maxCreditAbsolute").isEmpty()) {
+ maxCreditAbsolute[acc.id()] = balance < MyMoneyMoney(acc.value("maxCreditAbsolute"));
+ maxCreditEarly[acc.id()] = false;
+ }
+ }
+
+ if((*it_ts).id().isEmpty()) {
+ bool enter = true;
+ if(askForSchedule && (*it_ts).postDate() > QDate::currentDate()) {
+ KGuiItem enterItem;
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem enterButton( i18n("&Enter" ),
+ QIconSet(il->loadIcon("kontact_journal", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Accepts the entered data and stores it"),
+ i18n("Use this to enter the transaction into the ledger."));
+ KGuiItem scheduleButton( i18n("&Schedule" ),
+ QIconSet(il->loadIcon("kontact_date", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Accepts the entered data and stores it as schedule"),
+ i18n("Use this to schedule the transaction for later entry into the ledger."));
+
+ enter = KMessageBox::questionYesNo(m_regForm, QString("<qt>%1</qt>").arg(i18n("The transaction you are about to enter has a post date in the future.<br/><br/>Do you want to enter it in the ledger or add it to the schedules?")), i18n("Dialog caption for 'Enter or schedule' dialog", "Enter or schedule?"), enterButton, scheduleButton, "EnterOrScheduleTransactionInFuture") == KMessageBox::Yes;
+ }
+ if(enter) {
+ // add new transaction
+ file->addTransaction(*it_ts);
+ // pass the newly assigned id on to the caller
+ newId = (*it_ts).id();
+ // refresh account and transaction object because they might have changed
+ m_account = file->account(m_account.id());
+ t = (*it_ts);
+
+ // if a new transaction has a valid number, keep it with the account
+ QString number = (*it_ts).splits()[0].number();
+ if(!number.isEmpty()) {
+ m_account.setValue("lastNumberUsed", number);
+ file->modifyAccount(m_account);
+ }
+
+ } else {
+ // turn object creation on, so that moving the focus does
+ // not screw up the dialog that might be popping up
+ emit objectCreation(true);
+ emit scheduleTransaction(*it_ts, MyMoneySchedule::OCCUR_ONCE);
+ emit objectCreation(false);
+
+ newTransactionCreated = false;
+ }
+
+ // send out the post date of this transaction
+ emit lastPostDateUsed((*it_ts).postDate());
+ } else {
+ // modify existing transaction
+ file->modifyTransaction(*it_ts);
+ }
+ }
+ emit statusProgress(i++, 0);
+
+ // update m_transactions to contain the newly created transaction so that
+ // it is selected as the current one
+ // we need to do that before we commit the transaction to the engine
+ // as we need it during the update of the views that is caused by committing already.
+ if(newTransactionCreated) {
+ m_transactions.clear();
+ MyMoneySplit s;
+ // a transaction w/o a single split should not exist and adding it
+ // should throw an exception in MyMoneyFile::addTransaction, but we
+ // remain on the save side of things to check for it
+ if(t.splitCount() > 0)
+ s = t.splits()[0];
+ KMyMoneyRegister::SelectedTransaction st(t, s);
+ m_transactions.append(st);
+ }
+
+ ft.commit();
+
+ // now analyse the balances and spit out warnings to the user
+ QMap<QString, bool>::const_iterator it_a;
+
+ if(!suppressBalanceWarnings) {
+ for(it_a = accountIds.begin(); it_a != accountIds.end(); ++it_a) {
+ QString msg;
+ MyMoneyAccount acc = file->account(it_a.key());
+ MyMoneyMoney balance = file->balance(acc.id());
+ const MyMoneySecurity& sec = file->security(acc.currencyId());
+ QString key;
+ key = "minBalanceEarly";
+ if(!acc.value(key).isEmpty()) {
+ if(minBalanceEarly[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) {
+ msg = QString("<qt>%1</qt>").arg(i18n("The balance of account <b>%1</b> dropped below the warning balance of %2.").arg(acc.name(), MyMoneyMoney(acc.value(key)).formatMoney(acc, sec)));
+ }
+ }
+ key = "minBalanceAbsolute";
+ if(!acc.value(key).isEmpty()) {
+ if(minBalanceAbsolute[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) {
+ msg = QString("<qt>%1</qt>").arg(i18n("The balance of account <b>%1</b> dropped below the minimum balance of %2.").arg(acc.name(), MyMoneyMoney(acc.value(key)).formatMoney(acc, sec)));
+ }
+ }
+ key = "maxCreditEarly";
+ if(!acc.value(key).isEmpty()) {
+ if(maxCreditEarly[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) {
+ msg = QString("<qt>%1</qt>").arg(i18n("The balance of account <b>%1</b> dropped below the maximum credit warning limit of %2.").arg(acc.name(), MyMoneyMoney(acc.value(key)).formatMoney(acc, sec)));
+ }
+ }
+ key = "maxCreditAbsolute";
+ if(!acc.value(key).isEmpty()) {
+ if(maxCreditAbsolute[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) {
+ msg = QString("<qt>%1</qt>").arg(i18n("The balance of account <b>%1</b> dropped below the maximum credit limit of %2.").arg(acc.name(), MyMoneyMoney(acc.value(key)).formatMoney(acc, sec)));
+ }
+ }
+
+ if(!msg.isEmpty()) {
+ emit balanceWarning(m_regForm, acc, msg);
+ }
+ }
+ }
+ } catch(MyMoneyException * e) {
+ qDebug("Unable to store transaction within engine: %s", e->what().latin1());
+ delete e;
+ newTransactionCreated = false;
+ }
+
+ emit statusProgress(-1, -1);
+ emit statusMsg(QString());
+
+ }
+ return storeTransactions;
+}
+
+
+StdTransactionEditor::StdTransactionEditor()
+{
+}
+
+StdTransactionEditor::StdTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) :
+ TransactionEditor(regForm, item, list, lastPostDate),
+ m_inUpdateVat(false)
+{
+}
+
+StdTransactionEditor::~StdTransactionEditor()
+{
+ KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast<KMyMoneyTransactionForm::TransactionForm*>(m_regForm);
+ if(form) {
+ form->enableTabBar(true);
+ }
+}
+
+bool StdTransactionEditor::eventFilter(QObject* o, QEvent* e)
+{
+ bool rc = TransactionEditor::eventFilter(o, e);
+
+#if 0
+ // this is sofar dead code here, as the focus out event for Comboboxes
+ // never comes along here. I don't know why (ipwizard - 2009-10-03)
+ if((e->type() == QEvent::FocusOut)
+ && (haveWidget("payee") == dynamic_cast<QWidget*>(o))) {
+ // loosing the focus on the payee widget?
+ qDebug("Loosing focus on payee");
+ KMyMoneyPayeeCombo* p = dynamic_cast<KMyMoneyPayeeCombo*>(haveWidget("payee"));
+ if(!p->selectedItem().isEmpty())
+ slotUpdatePayee(p->selectedItem());
+ }
+#endif
+ return rc;
+}
+
+void StdTransactionEditor::createEditWidgets(void)
+{
+ KMyMoneyCategory* account = new KMyMoneyCategory;
+ account->setHint(i18n("Account"));
+ m_editWidgets["account"] = account;
+ connect(account, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(account, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateAccount(const QString&)));
+
+ KMyMoneyPayeeCombo* payee = new KMyMoneyPayeeCombo;
+ payee->setHint(i18n("Payer/Receiver"));
+ m_editWidgets["payee"] = payee;
+ connect(payee, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(payee, SIGNAL(createItem(const QString&, QString&)), this, SIGNAL(createPayee(const QString&, QString&)));
+ connect(payee, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+ connect(payee, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdatePayee(const QString&)));
+
+ KMyMoneyCategory* category = new KMyMoneyCategory(0, 0, true);
+ category->setHint(i18n("Category/Account"));
+ m_editWidgets["category"] = category;
+ connect(category, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateCategory(const QString&)));
+ connect(category, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+ connect(category, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateCategory(const QString&, QString&)));
+ connect(category, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+ connect(category->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditSplits()));
+ category->splitButton()->setDisabled(true);
+
+ KTextEdit* memo = new KTextEdit;
+ memo->setTabChangesFocus(true);
+ m_editWidgets["memo"] = memo;
+
+ bool showNumberField = true;
+ switch(m_account.accountType()) {
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::Loan:
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Equity:
+ showNumberField = KMyMoneyGlobalSettings::alwaysShowNrField();
+ break;
+
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ showNumberField = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if(showNumberField) {
+ kMyMoneyLineEdit* number = new kMyMoneyLineEdit;
+ number->setHint(i18n("Number"));
+ m_editWidgets["number"] = number;
+ connect(number, SIGNAL(lineChanged(const QString&)), this, SLOT(slotNumberChanged(const QString&)));
+ // number->installEventFilter(this);
+ }
+
+ m_editWidgets["postdate"] = new kMyMoneyDateInput;
+ connect(m_editWidgets["postdate"], SIGNAL(dateChanged(const QDate&)), this, SLOT(slotUpdateButtonState()));
+
+ kMyMoneyEdit* value = new kMyMoneyEdit;
+ m_editWidgets["amount"] = value;
+ value->setResetButtonVisible(false);
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateAmount(const QString&)));
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+
+ value = new kMyMoneyEdit;
+ m_editWidgets["payment"] = value;
+ value->setResetButtonVisible(false);
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdatePayment(const QString&)));
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+
+ value = new kMyMoneyEdit;
+ m_editWidgets["deposit"] = value;
+ value->setResetButtonVisible(false);
+ connect(value, SIGNAL(valueChanged(const QString&)), this, SLOT(slotUpdateDeposit(const QString&)));
+ connect(value, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateButtonState()));
+
+ KMyMoneyCashFlowCombo* cashflow = new KMyMoneyCashFlowCombo(0, 0, m_account.accountGroup());
+ m_editWidgets["cashflow"] = cashflow;
+ connect(cashflow, SIGNAL(directionSelected(KMyMoneyRegister::CashFlowDirection)), this, SLOT(slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection)));
+ connect(cashflow, SIGNAL(directionSelected(KMyMoneyRegister::CashFlowDirection)), this, SLOT(slotUpdateButtonState()));
+
+ KMyMoneyReconcileCombo* reconcile = new KMyMoneyReconcileCombo;
+ m_editWidgets["status"] = reconcile;
+ connect(reconcile, SIGNAL(itemSelected(const QString&)), this, SLOT(slotUpdateButtonState()));
+
+ KMyMoneyRegister::QWidgetContainer::iterator it_w;
+ for(it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) {
+ (*it_w)->installEventFilter(this);
+ }
+ // if we don't have more than 1 selected transaction, we don't need
+ // the "don't change" item in some of the combo widgets
+ if(!isMultiSelection()) {
+ reconcile->removeDontCare();
+ cashflow->removeDontCare();
+ }
+
+ QLabel* label;
+ m_editWidgets["category-label"] = label = new QLabel(i18n("Category"), 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+
+ // create a copy of tabbar above the form (if we are created for a form)
+ KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast<KMyMoneyTransactionForm::TransactionForm*>(m_regForm);
+ if(form) {
+ form->enableTabBar(false);
+ KMyMoneyTransactionForm::TabBar* tabbar = new KMyMoneyTransactionForm::TabBar;
+ m_editWidgets["tabbar"] = tabbar;
+ tabbar->copyTabs(form->tabBar());
+ connect(tabbar, SIGNAL(tabSelected(int)), this, SLOT(slotUpdateAction(int)));
+ }
+
+ label = new QLabel(i18n("Date"), 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["date-label"] = label;
+
+ label = new QLabel(i18n("Number"), 0);
+ label->setAlignment(Qt::AlignVCenter | Qt::DontClip);
+ m_editWidgets["number-label"] = label;
+
+ setupPrecision();
+}
+
+void StdTransactionEditor::setupCategoryWidget(QString& categoryId)
+{
+ TransactionEditor::setupCategoryWidget(dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]), m_splits, categoryId, SLOT(slotEditSplits()));
+
+ if(m_splits.count() == 1)
+ m_shares = m_splits[0].shares();
+}
+
+bool StdTransactionEditor::isTransfer(const QString& accId1, const QString& accId2) const
+{
+ if(accId1.isEmpty() || accId2.isEmpty())
+ return false;
+
+ return MyMoneyFile::instance()->account(accId1).isIncomeExpense() == MyMoneyFile::instance()->account(accId2).isIncomeExpense();
+}
+
+void StdTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action action)
+{
+ // don't kick off VAT processing from here
+ m_inUpdateVat = true;
+
+ QMap<QString, QWidget*>::const_iterator it_w;
+ QWidget* w;
+ AccountSet aSet;
+
+ // load the account widget
+ KMyMoneyCategory* account = dynamic_cast<KMyMoneyCategory*>(haveWidget("account"));
+ if(account) {
+ aSet.addAccountGroup(MyMoneyAccount::Asset);
+ aSet.addAccountGroup(MyMoneyAccount::Liability);
+ aSet.removeAccountType(MyMoneyAccount::AssetLoan);
+ aSet.removeAccountType(MyMoneyAccount::CertificateDep);
+ aSet.removeAccountType(MyMoneyAccount::Investment);
+ aSet.removeAccountType(MyMoneyAccount::Stock);
+ aSet.removeAccountType(MyMoneyAccount::MoneyMarket);
+ aSet.removeAccountType(MyMoneyAccount::Loan);
+ aSet.load(account->selector());
+ account->completion()->setSelected(m_account.id());
+ account->slotItemSelected(m_account.id());
+ }
+
+ // load the payee widget
+ KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(m_editWidgets["payee"]);
+ payee->loadPayees(MyMoneyFile::instance()->payeeList());
+
+ // load the category widget
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ disconnect(category, SIGNAL(focusIn()), this, SLOT(slotEditSplits()));
+
+ // check if the current transaction has a reference to an equity account
+ bool haveEquityAccount = false;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = m_transaction.splits().begin(); !haveEquityAccount && it_s != m_transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.accountType() == MyMoneyAccount::Equity)
+ haveEquityAccount = true;
+ }
+
+ aSet.clear();
+ aSet.addAccountGroup(MyMoneyAccount::Asset);
+ aSet.addAccountGroup(MyMoneyAccount::Liability);
+ aSet.addAccountGroup(MyMoneyAccount::Income);
+ aSet.addAccountGroup(MyMoneyAccount::Expense);
+ if(KMyMoneyGlobalSettings::expertMode() || haveEquityAccount)
+ aSet.addAccountGroup(MyMoneyAccount::Equity);
+
+ aSet.removeAccountType(MyMoneyAccount::CertificateDep);
+ aSet.removeAccountType(MyMoneyAccount::Investment);
+ aSet.removeAccountType(MyMoneyAccount::Stock);
+ aSet.removeAccountType(MyMoneyAccount::MoneyMarket);
+ aSet.load(category->selector());
+
+ // if an account is specified then remove it from the widget so that the user
+ // cannot create a transfer with from and to account being the same account
+ if(!m_account.id().isEmpty())
+ category->selector()->removeItem(m_account.id());
+
+ if(!isMultiSelection()) {
+ dynamic_cast<KTextEdit*>(m_editWidgets["memo"])->setText(m_split.memo());
+ if(m_transaction.postDate().isValid())
+ dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"])->setDate(m_transaction.postDate());
+ else if(m_lastPostDate.isValid())
+ dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"])->setDate(m_lastPostDate);
+ else
+ dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"])->setDate(QDate::currentDate());
+
+ if((w = haveWidget("number")) != 0) {
+ dynamic_cast<kMyMoneyLineEdit*>(w)->loadText(m_split.number());
+ if(m_transaction.id().isEmpty() // new transaction
+ && dynamic_cast<kMyMoneyLineEdit*>(w)->text().isEmpty() // no number filled in
+ && m_account.accountType() == MyMoneyAccount::Checkings // checkings account
+ && KMyMoneyGlobalSettings::autoIncCheckNumber()) { // and auto inc number turned on?
+ assignNextNumber();
+ }
+ }
+ dynamic_cast<KMyMoneyReconcileCombo*>(m_editWidgets["status"])->setState(m_split.reconcileFlag());
+
+ QString payeeId = m_split.payeeId();
+ if(!payeeId.isEmpty()) {
+ payee->setSelectedItem(payeeId);
+ }
+
+ m_splits.clear();
+ if(m_transaction.splitCount() < 2) {
+ category->completion()->setSelected(QString());
+ } else {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = m_transaction.splits().begin(); it_s != m_transaction.splits().end(); ++it_s) {
+ if((*it_s) == m_split)
+ continue;
+ m_splits.append(*it_s);
+ }
+ }
+ QString categoryId;
+ setupCategoryWidget(categoryId);
+
+ if((w = haveWidget("cashflow")) != 0) {
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(w);
+ cashflow->setDirection(m_split.value().isNegative() ? KMyMoneyRegister::Payment : KMyMoneyRegister::Deposit);
+ }
+
+ if((w = haveWidget("category-label")) != 0) {
+ QLabel *categoryLabel = dynamic_cast<QLabel*>(w);
+ if(isTransfer(m_split.accountId(), categoryId)) {
+ if(m_split.value().isPositive())
+ categoryLabel->setText(i18n("Transfer from"));
+ else
+ categoryLabel->setText(i18n("Transfer to"));
+ }
+ }
+
+ MyMoneyMoney value = m_split.shares();
+
+ if(haveWidget("deposit")) {
+ if(m_split.shares().isNegative()) {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->loadText("");
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->setValue(value.abs());
+ } else {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->setValue(value.abs());
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->loadText("");
+ }
+ }
+ if((w = haveWidget("amount")) != 0) {
+ dynamic_cast<kMyMoneyEdit*>(w)->setValue(value.abs());
+ }
+
+ slotUpdateCategory(categoryId);
+
+ // try to preset for specific action if a new transaction is being started
+ if(m_transaction.id().isEmpty()) {
+ if((w = haveWidget("category-label")) != 0) {
+ TabBar* tabbar = dynamic_cast<TabBar*>(haveWidget("tabbar"));
+ if(action == KMyMoneyRegister::ActionNone) {
+ if(tabbar) {
+ action = static_cast<KMyMoneyRegister::Action>(tabbar->currentTab());
+ }
+ }
+ if(action != KMyMoneyRegister::ActionNone) {
+ QLabel *categoryLabel = dynamic_cast<QLabel*>(w);
+ if(action == KMyMoneyRegister::ActionTransfer) {
+ if(m_split.value().isPositive())
+ categoryLabel->setText(i18n("Transfer from"));
+ else
+ categoryLabel->setText(i18n("Transfer to"));
+ }
+ if((w = haveWidget("cashflow")) != 0) {
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(w);
+ if(action == KMyMoneyRegister::ActionDeposit || (action == KMyMoneyRegister::ActionTransfer && m_split.value().isPositive()))
+ cashflow->setDirection(KMyMoneyRegister::Deposit);
+ else
+ cashflow->setDirection(KMyMoneyRegister::Payment);
+ }
+ if(tabbar) {
+ tabbar->setCurrentTab(action);
+ }
+ }
+ }
+ } else {
+ TabBar* tabbar = dynamic_cast<TabBar*>(haveWidget("tabbar"));
+ if(tabbar) {
+ if(!isTransfer(m_split.accountId(), categoryId)) {
+ tabbar->setCurrentTab(m_split.value().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit);
+ } else {
+ tabbar->setCurrentTab(KMyMoneyRegister::ActionTransfer);
+ }
+ }
+ }
+
+ } else {
+ dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"])->loadDate(QDate());
+ dynamic_cast<KMyMoneyReconcileCombo*>(m_editWidgets["status"])->setState(MyMoneySplit::Unknown);
+ if(haveWidget("deposit")) {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->loadText("");
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->setAllowEmpty();
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->loadText("");
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->setAllowEmpty();
+ }
+ if((w = haveWidget("amount")) != 0) {
+ dynamic_cast<kMyMoneyEdit*>(w)->loadText("");
+ dynamic_cast<kMyMoneyEdit*>(w)->setAllowEmpty();
+ }
+
+ if((w = haveWidget("cashflow")) != 0) {
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(w);
+ cashflow->setDirection(KMyMoneyRegister::Unknown);
+ }
+ if((w = haveWidget("tabbar")) != 0) {
+ w->setEnabled(false);
+ }
+
+ category->completion()->setSelected(QString());
+ }
+
+ // allow kick off VAT processing again
+ m_inUpdateVat = false;
+}
+
+QWidget* StdTransactionEditor::firstWidget(void) const
+{
+ QWidget* w = 0;
+ if(m_initialAction != KMyMoneyRegister::ActionNone)
+ w = haveWidget("payee");
+ return w;
+}
+
+void StdTransactionEditor::slotReloadEditWidgets(void)
+{
+ // reload category widget
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ QString categoryId = category->selectedItem();
+
+ AccountSet aSet;
+ aSet.addAccountGroup(MyMoneyAccount::Asset);
+ aSet.addAccountGroup(MyMoneyAccount::Liability);
+ aSet.addAccountGroup(MyMoneyAccount::Income);
+ aSet.addAccountGroup(MyMoneyAccount::Expense);
+ if(KMyMoneyGlobalSettings::expertMode())
+ aSet.addAccountGroup(MyMoneyAccount::Equity);
+ aSet.load(category->selector());
+
+ // if an account is specified then remove it from the widget so that the user
+ // cannot create a transfer with from and to account being the same account
+ if(!m_account.id().isEmpty())
+ category->selector()->removeItem(m_account.id());
+
+ if(!categoryId.isEmpty())
+ category->setSelectedItem(categoryId);
+
+
+ // reload payee widget
+ KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(m_editWidgets["payee"]);
+ QString payeeId = payee->selectedItem();
+
+ payee->loadPayees(MyMoneyFile::instance()->payeeList());
+
+ if(!payeeId.isEmpty()) {
+ payee->setSelectedItem(payeeId);
+ }
+}
+
+void StdTransactionEditor::slotUpdatePayee(const QString& payeeId)
+{
+ // we have a new payee assigned to this transaction.
+ // retrieve some information about the state of the category widget
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ QStringList list;
+ category->selectedItems(list);
+
+ // If payee has associated default account (category), set that now if
+ // category is not filled
+ const MyMoneyPayee& payeeObj = MyMoneyFile::instance()->payee(payeeId);
+ if (payeeObj.defaultAccountEnabled() && list.isEmpty()) {
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ category->slotItemSelected(payeeObj.defaultAccountId());
+ return;
+ }
+
+ // in case there is no category assigned, no value entered and no
+ // memo available, we search for the last transaction of this payee
+ // in the account.
+ if(m_transaction.id().isEmpty()
+ && m_splits.count() == 0
+ && KMyMoneyGlobalSettings::autoFillTransaction() != 0
+ && list.isEmpty()) {
+ // check if memo is empty
+ KTextEdit* memo = dynamic_cast<KTextEdit*>(m_editWidgets["memo"]);
+ if(memo && !memo->text().isEmpty())
+ return;
+
+ // check if all value fields are empty
+ kMyMoneyEdit* amount;
+ QStringList fields;
+ fields << "amount" << "payment" << "deposit";
+ QStringList::const_iterator it_f;
+ for(it_f = fields.begin(); it_f != fields.end(); ++it_f) {
+ amount = dynamic_cast<kMyMoneyEdit*>(haveWidget(*it_f));
+ if(amount && !amount->value().isZero())
+ return;
+ }
+
+#if 0
+ // Tony mentioned, that autofill does not work when he changed the date. Well,
+ // that certainly makes sense when you enter transactions in register mode as
+ // opposed to form mode, because the date field is located prior to the date
+ // field in the tab order of the widgets and the user might have already
+ // changed it.
+ //
+ // So I commented out the code that checks the date but left it in for reference.
+ // (ipwizard, 2008-04-07)
+
+ // check if date has been altered by user
+ kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"]);
+ if((m_lastPostDate.isValid() && (postDate->date() != m_lastPostDate))
+ || (!m_lastPostDate.isValid() && (postDate->date() != QDate::currentDate())))
+ return;
+#endif
+
+ // if we got here, we have to autofill
+ autoFill(payeeId);
+ }
+}
+
+MyMoneyMoney StdTransactionEditor::shares(const MyMoneyTransaction& t) const
+{
+ MyMoneyMoney result;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).accountId() == m_account.id()) {
+ result += (*it_s).shares();
+ }
+ }
+ return result;
+}
+
+struct uniqTransaction {
+ const MyMoneyTransaction* t;
+ int cnt;
+};
+
+void StdTransactionEditor::autoFill(const QString& payeeId)
+{
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> > list;
+ MyMoneyTransactionFilter filter(m_account.id());
+ filter.addPayee(payeeId);
+ MyMoneyFile::instance()->transactionList(list, filter);
+ if(!list.empty()) {
+ // ok, we found at least one previous transaction. now we clear out
+ // what we have collected so far and add those splits from
+ // the previous transaction.
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::const_iterator it_t;
+ QMap<QString, struct uniqTransaction> uniqList;
+
+ // collect the transactions and see if we have any duplicates
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ QString key = (*it_t).first.accountSignature();
+ int cnt = 0;
+ QMap<QString, struct uniqTransaction>::iterator it_u;
+ do {
+ QString ukey = QString("%1-%2").arg(key).arg(cnt);
+ it_u = uniqList.find(ukey);
+ if(it_u == uniqList.end()) {
+ uniqList[ukey].t = &((*it_t).first);
+ uniqList[ukey].cnt = 1;
+ } else if (KMyMoneyGlobalSettings::autoFillTransaction() == 1) {
+ // we already have a transaction with this signature. we must
+ // now check, if we should really treat it as a duplicate according
+ // to the value comparison delta.
+ MyMoneyMoney s1 = shares(*((*it_u).t));
+ MyMoneyMoney s2 = shares((*it_t).first);
+ if(s2.abs() > s1.abs()) {
+ MyMoneyMoney t(s1);
+ s1 = s2;
+ s2 = t;
+ }
+ MyMoneyMoney diff;
+ if(s2.isZero())
+ diff = s1.abs();
+ else
+ diff = ((s1 - s2) / s2).convert(10000);
+ if(diff.isPositive() && diff <= MyMoneyMoney(KMyMoneyGlobalSettings::autoFillDifference(),100)) {
+ uniqList[ukey].t = &((*it_t).first);
+ break; // end while loop
+ }
+ } else if (KMyMoneyGlobalSettings::autoFillTransaction() == 2) {
+ (*it_u).cnt++;
+ break; // end while loop
+ }
+ ++cnt;
+ } while(it_u != uniqList.end());
+
+ }
+
+ MyMoneyTransaction t;
+ if (KMyMoneyGlobalSettings::autoFillTransaction() != 2) {
+#if 0
+ // I removed this code to allow cancellation of an autofill if
+ // it does not match even if there is only a single matching
+ // transaction for the payee in question. In case, we want to revert
+ // to the old behavior, don't forget to uncomment the closing
+ // brace further down in the code as well. (ipwizard 2009-01-16)
+ if(uniqList.count() == 1) {
+ t = list.last().first;
+ } else {
+#endif
+ KSelectTransactionsDlg dlg(m_account, m_regForm);
+ dlg.setCaption(i18n("Select autofill transaction"));
+
+ QMap<QString, struct uniqTransaction>::const_iterator it_u;
+ for(it_u = uniqList.begin(); it_u != uniqList.end(); ++it_u) {
+ dlg.addTransaction(*(*it_u).t);
+ }
+
+ // setup sort order
+ dlg.m_register->setSortOrder("1,-9,-4");
+ // sort the transactions according to the sort setting
+ dlg.m_register->sortItems();
+
+ // and select the last item
+ if(dlg.m_register->lastItem())
+ dlg.m_register->selectItem(dlg.m_register->lastItem());
+
+ if(dlg.exec() == QDialog::Accepted) {
+ t = dlg.transaction();
+ }
+#if 0
+ }
+#endif
+ } else {
+ int maxCnt = 0;
+ QMap<QString, struct uniqTransaction>::const_iterator it_u;
+ for(it_u = uniqList.begin(); it_u != uniqList.end(); ++it_u) {
+ if((*it_u).cnt > maxCnt) {
+ t = *(*it_u).t;
+ maxCnt = (*it_u).cnt;
+ }
+ }
+ }
+
+ if(t != MyMoneyTransaction()) {
+ m_transaction.removeSplits();
+ m_split = MyMoneySplit();
+ MyMoneySplit otherSplit;
+ QValueList<MyMoneySplit>::ConstIterator it;
+ for(it = t.splits().begin(); it != t.splits().end(); ++it) {
+ MyMoneySplit s(*it);
+ s.setReconcileFlag(MyMoneySplit::NotReconciled);
+ s.setReconcileDate(QDate());
+ s.clearId();
+ s.setBankID(QString());
+ // older versions of KMyMoney used to set the action
+ // we don't need this anymore
+ if(s.action() != MyMoneySplit::ActionAmortization
+ && s.action() != MyMoneySplit::ActionInterest) {
+ s.setAction(QString());
+ }
+
+ // FIXME update check number. The old comment contained
+ //
+ // <quote>
+ // If a check number is already specified by the user it is
+ // used. If the input field is empty and the previous transaction
+ // contains a checknumber, the next usuable check no will be assigned
+ // to the transaction.
+ // </quote>
+
+ kMyMoneyLineEdit* editNr = dynamic_cast<kMyMoneyLineEdit*>(haveWidget("number"));
+ if(editNr && !editNr->text().isEmpty()) {
+ s.setNumber(editNr->text());
+ } else if(!s.number().isEmpty()) {
+ s.setNumber(KMyMoneyUtils::nextCheckNumber(m_account));
+ }
+
+ // if the transaction has exactly two splits, remove
+ // the memo text of the split that does not reference
+ // the current account. This allows the user to change
+ // the autofilled memo text which will then also be used
+ // in this split. See createTransaction() for this logic.
+ if(s.accountId() != m_account.id() && t.splitCount() == 2)
+ s.setMemo(QString());
+
+ m_transaction.addSplit(s);
+ if(s.accountId() == m_account.id() && m_split == MyMoneySplit()) {
+ m_split = s;
+ } else {
+ otherSplit = s;
+ }
+ }
+
+ // make sure to extract the right action
+ KMyMoneyRegister::Action action;
+ action = m_split.shares().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit;
+
+ if(m_transaction.splitCount() == 2) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(otherSplit.accountId());
+ if(acc.isAssetLiability())
+ action = KMyMoneyRegister::ActionTransfer;
+ }
+
+ // now setup the widgets with the new data but keep the date
+ QDate date = dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"])->date();
+ loadEditWidgets(action);
+ dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"])->setDate(date);
+ }
+ }
+
+ // focus jumps into the category field
+ QWidget* w;
+ if((w = haveWidget("payee")) != 0) {
+ w->setFocus();
+ }
+}
+
+void StdTransactionEditor::slotUpdateAction(int action)
+{
+ TabBar* tabbar = dynamic_cast<TabBar*>(haveWidget("tabbar"));
+ if(tabbar) {
+ QLabel* categoryLabel = dynamic_cast<QLabel*>(haveWidget("category-label"));
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(m_editWidgets["cashflow"]);
+ switch(action) {
+ case KMyMoneyRegister::ActionDeposit:
+ categoryLabel->setText(i18n("Category"));
+ cashflow->setDirection(KMyMoneyRegister::Deposit);
+ break;
+ case KMyMoneyRegister::ActionTransfer:
+ categoryLabel->setText(i18n("Transfer from"));
+ slotUpdateCashFlow(cashflow->direction());
+ break;
+ case KMyMoneyRegister::ActionWithdrawal:
+ categoryLabel->setText(i18n("Category"));
+ cashflow->setDirection(KMyMoneyRegister::Payment);
+ break;
+ }
+ }
+}
+
+void StdTransactionEditor::slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection dir)
+{
+ QLabel* categoryLabel = dynamic_cast<QLabel*>(haveWidget("category-label"));
+
+ // qDebug("Update cashflow to %d", dir);
+ if(categoryLabel) {
+ TabBar* tabbar = dynamic_cast<TabBar*>(haveWidget("tabbar"));
+ if(categoryLabel->text() != i18n("Category")) {
+ tabbar->setCurrentTab(KMyMoneyRegister::ActionTransfer);
+ if(dir == KMyMoneyRegister::Deposit) {
+ categoryLabel->setText(i18n("Transfer from"));
+ } else {
+ categoryLabel->setText(i18n("Transfer to"));
+ }
+ } else {
+ if(dir == KMyMoneyRegister::Deposit)
+ tabbar->setCurrentTab(KMyMoneyRegister::ActionDeposit);
+ else
+ tabbar->setCurrentTab(KMyMoneyRegister::ActionWithdrawal);
+ }
+ }
+}
+
+void StdTransactionEditor::slotUpdateCategory(const QString& id)
+{
+ QLabel *categoryLabel = dynamic_cast<QLabel*>(haveWidget("category-label"));
+ // qDebug("Update category to %s", id.data());
+
+ if(categoryLabel) {
+ TabBar* tabbar = dynamic_cast<TabBar*>(haveWidget("tabbar"));
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(m_editWidgets["amount"]);
+ MyMoneyMoney val = amount->value();
+
+ if(categoryLabel->text() == i18n("Transfer from")) {
+ val = -val;
+ } else {
+ val = val.abs();
+ }
+
+ if(tabbar) {
+ tabbar->tab(KMyMoneyRegister::ActionTransfer)->setEnabled(true);
+ tabbar->tab(KMyMoneyRegister::ActionDeposit)->setEnabled(true);
+ tabbar->tab(KMyMoneyRegister::ActionWithdrawal)->setEnabled(true);
+ }
+
+ if(!id.isEmpty()) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(id);
+ if(acc.isAssetLiability()
+ || acc.accountGroup() == MyMoneyAccount::Equity) {
+ if(tabbar) {
+ tabbar->tab(KMyMoneyRegister::ActionDeposit)->setEnabled(false);
+ tabbar->tab(KMyMoneyRegister::ActionWithdrawal)->setEnabled(false);
+ }
+ // only change the label if an amount is already filled in
+ if(!val.isZero()) {
+ if(val.isNegative())
+ categoryLabel->setText(i18n("Transfer from"));
+ else
+ categoryLabel->setText(i18n("Transfer to"));
+ }
+ } else {
+ if(tabbar)
+ tabbar->tab(KMyMoneyRegister::ActionTransfer)->setEnabled(false);
+ categoryLabel->setText(i18n("Category"));
+ }
+ updateAmount(val.abs());
+ } else {
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ if(!category->currentText().isEmpty() && tabbar)
+ tabbar->tab(KMyMoneyRegister::ActionTransfer)->setEnabled(false);
+ categoryLabel->setText(i18n("Category"));
+ }
+ if(tabbar)
+ tabbar->update();
+ }
+ updateVAT(false);
+}
+
+void StdTransactionEditor::slotUpdatePayment(const QString& txt)
+{
+ MyMoneyMoney val(txt);
+
+ if(val.isNegative()) {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->setValue(val.abs());
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->clearText();
+ } else {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->clearText();
+ }
+ updateVAT();
+}
+
+void StdTransactionEditor::slotUpdateDeposit(const QString& txt)
+{
+ MyMoneyMoney val(txt);
+ if(val.isNegative()) {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->setValue(val.abs());
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"])->clearText();
+ } else {
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"])->clearText();
+ }
+ updateVAT();
+}
+
+void StdTransactionEditor::slotUpdateAmount(const QString& txt)
+{
+ // qDebug("Update amount to %s", txt.data());
+ MyMoneyMoney val(txt);
+ updateAmount(val);
+ updateVAT(true);
+}
+
+void StdTransactionEditor::updateAmount(const MyMoneyMoney& val)
+{
+ QLabel *categoryLabel = dynamic_cast<QLabel*>(haveWidget("category-label"));
+ if(categoryLabel) {
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(m_editWidgets["cashflow"]);
+
+ if(val.isNegative()) {
+ if(categoryLabel->text() != i18n("Category")) {
+ if(categoryLabel->text() == i18n("Transfer from")) {
+ categoryLabel->setText(i18n("Transfer to"));
+ cashflow->setDirection(KMyMoneyRegister::Payment);
+ } else {
+ categoryLabel->setText(i18n("Transfer from"));
+ cashflow->setDirection(KMyMoneyRegister::Deposit);
+ }
+ } else {
+ if(cashflow->direction() == KMyMoneyRegister::Deposit)
+ cashflow->setDirection(KMyMoneyRegister::Payment);
+ else
+ cashflow->setDirection(KMyMoneyRegister::Deposit);
+ slotUpdateCashFlow(cashflow->direction());
+ }
+ dynamic_cast<kMyMoneyEdit*>(m_editWidgets["amount"])->setValue(val.abs());
+ }
+ }
+}
+
+void StdTransactionEditor::updateVAT(bool amountChanged)
+{
+ // make sure that we don't do this recursively
+ if(m_inUpdateVat)
+ return;
+
+ // we don't do anything if we have multiple transactions selected
+ if(isMultiSelection())
+ return;
+
+ // if auto vat assignment for this account is turned off
+ // we don't care about taxes
+ if(m_account.value("NoVat") == "Yes")
+ return;
+
+ // more splits than category and tax are not supported
+ if(m_splits.count() > 2)
+ return;
+
+ // in order to do anything, we need an amount
+ MyMoneyMoney amount, newAmount;
+ bool amountOk;
+ amount = amountFromWidget(&amountOk);
+ if(!amountOk)
+ return;
+
+ // If the transaction has a tax and a category split, remove the tax split
+ if(m_splits.count() == 2) {
+ newAmount = removeVatSplit();
+ if(m_splits.count() == 2) // not removed?
+ return;
+
+ } else {
+ // otherwise, we need a category
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ if(category->selectedItem().isEmpty())
+ return;
+
+ // if no VAT account is associated with this category/account, then we bail out
+ MyMoneyAccount cat = MyMoneyFile::instance()->account(category->selectedItem());
+ if(cat.value("VatAccount").isEmpty())
+ return;
+
+ newAmount = amount;
+ }
+
+ // seems we have everything we need
+ if(amountChanged)
+ newAmount = amount;
+
+ MyMoneyTransaction transaction;
+ if(createTransaction(transaction, m_transaction, m_split)) {
+ if(addVatSplit(transaction, newAmount)) {
+ m_transaction = transaction;
+ m_split = m_transaction.splits()[0];
+
+ loadEditWidgets();
+
+ // if we made this a split transaction, then move the
+ // focus to the memo field
+ if(qApp->focusWidget() == haveWidget("category")) {
+ QWidget* w = haveWidget("memo");
+ if(w)
+ w->setFocus();
+ }
+ }
+ }
+}
+
+bool StdTransactionEditor::addVatSplit(MyMoneyTransaction& tr, const MyMoneyMoney& amount)
+{
+ if(tr.splitCount() != 2)
+ return false;
+
+ bool rc = false;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ try {
+ MyMoneySplit cat; // category
+ MyMoneySplit tax; // tax
+
+ // extract the category split from the transaction
+ MyMoneyAccount category = file->account(tr.splitByAccount(m_account.id(), false).accountId());
+ if(category.value("VatAccount").isEmpty())
+ return false;
+ MyMoneyAccount vatAcc = file->account(category.value("VatAccount").latin1());
+ const MyMoneySecurity& asec = file->security(m_account.currencyId());
+ const MyMoneySecurity& csec = file->security(category.currencyId());
+ const MyMoneySecurity& vsec = file->security(vatAcc.currencyId());
+ if(asec.id() != csec.id() || asec.id() != vsec.id()) {
+ qDebug("Auto VAT assignment only works if all three accounts use the same currency.");
+ return false;
+ }
+
+ MyMoneyMoney vatRate(vatAcc.value("VatRate"));
+ MyMoneyMoney gv, nv; // gross value, net value
+ int fract = m_account.fraction();
+
+ if(!vatRate.isZero()) {
+
+ tax.setAccountId(vatAcc.id());
+
+ // qDebug("vat amount is '%s'", category.value("VatAmount").latin1());
+ if(category.value("VatAmount").lower() != QString("net")) {
+ // split value is the gross value
+ gv = amount;
+ nv = gv / (MyMoneyMoney(1,1) + vatRate);
+ MyMoneySplit catSplit = tr.splitByAccount(m_account.id(), false);
+ catSplit.setShares(-nv.convert(fract));
+ catSplit.setValue(catSplit.shares());
+ tr.modifySplit(catSplit);
+
+ } else {
+ // split value is the net value
+ nv = amount;
+ gv = nv * (MyMoneyMoney(1,1) + vatRate);
+ MyMoneySplit accSplit = tr.splitByAccount(m_account.id());
+ accSplit.setValue(gv.convert(fract));
+ accSplit.setShares(accSplit.value());
+ tr.modifySplit(accSplit);
+ }
+
+ tax.setValue(-(gv - nv).convert(fract));
+ tax.setShares(tax.value());
+ tr.addSplit(tax);
+ rc = true;
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ return rc;
+}
+
+MyMoneyMoney StdTransactionEditor::removeVatSplit(void)
+{
+ // we only deal with splits that have three splits
+ if(m_splits.count() != 2)
+ return amountFromWidget();
+
+ MyMoneySplit c; // category split
+ MyMoneySplit t; // tax split
+
+ bool netValue = false;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = m_splits.begin(); it_s != m_splits.end(); ++it_s) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(!acc.value("VatAccount").isEmpty()) {
+ netValue = (acc.value("VatAmount").lower() == "net");
+ c = (*it_s);
+ } else if(!acc.value("VatRate").isEmpty()) {
+ t = (*it_s);
+ }
+ }
+
+ // bail out if not all splits are setup
+ if(c.id().isEmpty() || t.id().isEmpty())
+ return amountFromWidget();
+
+ MyMoneyMoney amount;
+ // reduce the splits
+ if(netValue) {
+ amount = -c.shares();
+ } else {
+ amount = -(c.shares() + t.shares());
+ }
+
+ // remove tax split from the list, ...
+ m_splits.clear();
+ m_splits.append(c);
+
+ // ... make sure that the widget is updated ...
+ // block the signals to avoid popping up the split editor dialog
+ // for nothing
+ m_editWidgets["category"]->blockSignals(true);
+ QString id;
+ setupCategoryWidget(id);
+ m_editWidgets["category"]->blockSignals(false);
+
+ // ... and return the updated amount
+ return amount;
+}
+
+bool StdTransactionEditor::isComplete(QString& reason) const
+{
+ reason = QString();
+ // reason.clear(); // for Qt4
+
+ QMap<QString, QWidget*>::const_iterator it_w;
+ kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"]);
+ if(postDate) {
+ postDate->markAsBadDate();
+ QToolTip::remove(postDate);
+ if(postDate->date().isValid() && (postDate->date() < m_account.openingDate())) {
+ postDate->markAsBadDate(true, KMyMoneyGlobalSettings::listNegativeValueColor());
+ reason = i18n("Cannot enter transaction with postdate prior to account's opening date.");
+ QToolTip::add(postDate, reason);
+ return false;
+ }
+ }
+
+ for(it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) {
+ KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(*it_w);
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(*it_w);
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(*it_w);
+ KMyMoneyReconcileCombo* reconcile = dynamic_cast<KMyMoneyReconcileCombo*>(*it_w);
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(*it_w);
+
+ if(payee && !(payee->currentText().isEmpty()))
+ break;
+
+ if(category && !category->lineEdit()->text().isEmpty())
+ break;
+
+ if(amount && !(amount->value().isZero()))
+ break;
+
+ // the following two widgets are only checked if we are editing multiple transactions
+ if(isMultiSelection()) {
+ if(reconcile && reconcile->state() != MyMoneySplit::Unknown)
+ break;
+
+ if(cashflow && cashflow->direction() != KMyMoneyRegister::Unknown)
+ break;
+ }
+ }
+ return it_w != m_editWidgets.end();
+}
+
+void StdTransactionEditor::slotCreateCategory(const QString& name, QString& id)
+{
+ MyMoneyAccount acc, parent;
+ acc.setName(name);
+
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(haveWidget("cashflow"));
+ if(cashflow) {
+ // form based input
+ if(cashflow->direction() == KMyMoneyRegister::Deposit)
+ parent = MyMoneyFile::instance()->income();
+ else
+ parent = MyMoneyFile::instance()->expense();
+
+ } else if(haveWidget("deposit")) {
+ // register based input
+ kMyMoneyEdit* deposit = dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"]);
+ if(deposit->value().isPositive())
+ parent = MyMoneyFile::instance()->income();
+ else
+ parent = MyMoneyFile::instance()->expense();
+
+ } else
+ parent = MyMoneyFile::instance()->expense();
+
+ // TODO extract possible first part of a hierarchy and check if it is one
+ // of our top categories. If so, remove it and select the parent
+ // according to this information.
+
+ emit createCategory(acc, parent);
+
+ // return id
+ id = acc.id();
+}
+
+int StdTransactionEditor::slotEditSplits(void)
+{
+ int rc = QDialog::Rejected;
+
+ if(!m_openEditSplits) {
+ // only get in here in a single instance
+ m_openEditSplits = true;
+
+ // force focus change to update all data
+ QWidget* w = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"])->splitButton();
+ if(w)
+ w->setFocus();
+
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(haveWidget("amount"));
+ kMyMoneyEdit* deposit = dynamic_cast<kMyMoneyEdit*>(haveWidget("deposit"));
+ kMyMoneyEdit* payment = dynamic_cast<kMyMoneyEdit*>(haveWidget("payment"));
+ KMyMoneyCashFlowCombo* cashflow = 0;
+ KMyMoneyRegister::CashFlowDirection dir = KMyMoneyRegister::Unknown;
+ bool isValidAmount = false;
+
+ if(amount) {
+ isValidAmount = amount->lineedit()->text().length() != 0;
+ cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(haveWidget("cashflow"));
+ if(cashflow)
+ dir = cashflow->direction();
+
+ } else {
+ if(deposit) {
+ if (deposit->lineedit()->text().length() != 0) {
+ isValidAmount = true;
+ dir = KMyMoneyRegister::Deposit;
+ }
+ }
+ if(payment) {
+ if (payment->lineedit()->text().length() != 0) {
+ isValidAmount = true;
+ dir = KMyMoneyRegister::Payment;
+ }
+ }
+ if(!deposit || !payment) {
+ qDebug("Internal error: deposit(%p) & payment(%p) widgets not found but required", deposit, payment);
+ return rc;
+ }
+ }
+
+ if(dir == KMyMoneyRegister::Unknown)
+ dir = KMyMoneyRegister::Payment;
+
+ MyMoneyTransaction transaction;
+ if(createTransaction(transaction, m_transaction, m_split)) {
+ MyMoneyMoney value;
+
+ KSplitTransactionDlg* dlg = new KSplitTransactionDlg(transaction,
+ transaction.splits()[0],
+ m_account,
+ isValidAmount,
+ dir == KMyMoneyRegister::Deposit,
+ 0,
+ m_priceInfo,
+ m_regForm);
+ connect(dlg, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool)));
+ connect(dlg, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)), this, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)));
+
+ if((rc = dlg->exec()) == QDialog::Accepted) {
+ m_transaction = dlg->transaction();
+ m_split = m_transaction.splits()[0];
+ loadEditWidgets();
+ }
+
+ delete dlg;
+ }
+
+ // focus jumps into the memo field
+ if((w = haveWidget("memo")) != 0) {
+ w->setFocus();
+ }
+
+ m_openEditSplits = false;
+ }
+
+ return rc;
+}
+
+void StdTransactionEditor::checkPayeeInSplit(MyMoneySplit& s, const QString& payeeId)
+{
+ if(s.accountId().isEmpty())
+ return;
+
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(s.accountId());
+ if(acc.isIncomeExpense()) {
+ s.setPayeeId(payeeId);
+ } else {
+ if(s.payeeId().isEmpty())
+ s.setPayeeId(payeeId);
+ }
+}
+
+MyMoneyMoney StdTransactionEditor::amountFromWidget(bool* update) const
+{
+ bool updateValue = false;
+ MyMoneyMoney value;
+
+ KMyMoneyCashFlowCombo* cashflow = dynamic_cast<KMyMoneyCashFlowCombo*>(haveWidget("cashflow"));
+ if(cashflow) {
+ // form based input
+ kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(m_editWidgets["amount"]);
+ // if both fields do not contain changes -> no need to update
+ if(cashflow->direction() != KMyMoneyRegister::Unknown
+ && !amount->lineedit()->text().isEmpty())
+ updateValue = true;
+ value = amount->value();
+ if(cashflow->direction() == KMyMoneyRegister::Payment)
+ value = -value;
+
+ } else if(haveWidget("deposit")) {
+ // register based input
+ kMyMoneyEdit* deposit = dynamic_cast<kMyMoneyEdit*>(m_editWidgets["deposit"]);
+ kMyMoneyEdit* payment = dynamic_cast<kMyMoneyEdit*>(m_editWidgets["payment"]);
+ // if both fields do not contain text -> no need to update
+ if(!(deposit->lineedit()->text().isEmpty() && payment->lineedit()->text().isEmpty()))
+ updateValue = true;
+
+ if(deposit->value().isPositive())
+ value = deposit->value();
+ else
+ value = -(payment->value());
+ }
+
+ if(update)
+ *update = updateValue;
+
+ // determine the max fraction for this account and
+ // adjust the value accordingly
+ return value.convert(m_account.fraction());
+}
+
+bool StdTransactionEditor::createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog)
+{
+ // extract price info from original transaction
+ m_priceInfo.clear();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ if(!torig.id().isEmpty()) {
+ for(it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) {
+ if((*it_s).id() != sorig.id()) {
+ MyMoneyAccount cat = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(cat.currencyId() != m_account.currencyId()) {
+ if(!(*it_s).shares().isZero() && !(*it_s).value().isZero()) {
+ m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce();
+ }
+ }
+ }
+ }
+ }
+
+ t = torig;
+
+ t.removeSplits();
+ t.setCommodity(m_account.currencyId());
+
+ kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"]);
+ if(postDate->date().isValid()) {
+ t.setPostDate(postDate->date());
+ }
+
+ // we start with the previous values, make sure we can add them later on
+ MyMoneySplit s0 = sorig;
+ s0.clearId();
+
+ // make sure we reference this account here
+ s0.setAccountId(m_account.id());
+
+ // memo and number field are special: if we have multiple transactions selected
+ // and the edit field is empty, we treat it as "not modified".
+ // FIXME a better approach would be to have a 'dirty' flag with the widgets
+ // which identifies if the originally loaded value has been modified
+ // by the user
+ KTextEdit* memo = dynamic_cast<KTextEdit*>(m_editWidgets["memo"]);
+ if(memo) {
+ if(!isMultiSelection() || (isMultiSelection() && !memo->text().isEmpty() ) )
+ s0.setMemo(memo->text());
+ }
+
+ kMyMoneyLineEdit* number = dynamic_cast<kMyMoneyLineEdit*>(haveWidget("number"));
+ if(number) {
+ if(!isMultiSelection() || (isMultiSelection() && !number->text().isEmpty() ) )
+ s0.setNumber(number->text());
+ }
+
+ KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(m_editWidgets["payee"]);
+ QString payeeId;
+ if(!isMultiSelection() || (isMultiSelection() && !payee->currentText().isEmpty())) {
+ payeeId = payee->selectedItem();
+ s0.setPayeeId(payeeId);
+ }
+
+ bool updateValue;
+ MyMoneyMoney value = amountFromWidget(&updateValue);
+
+ if(updateValue) {
+ // for this account, the shares and value is the same
+ s0.setValue(value);
+ s0.setShares(value);
+ } else {
+ value = s0.value();
+ }
+
+ // if we mark the split reconciled here, we'll use today's date if no reconciliation date is given
+ KMyMoneyReconcileCombo* status = dynamic_cast<KMyMoneyReconcileCombo*>(m_editWidgets["status"]);
+ if(status->state() != MyMoneySplit::Unknown)
+ s0.setReconcileFlag(status->state());
+
+ if(s0.reconcileFlag() == MyMoneySplit::Reconciled && !s0.reconcileDate().isValid())
+ s0.setReconcileDate(QDate::currentDate());
+
+ checkPayeeInSplit(s0, payeeId);
+
+ // add the split to the transaction
+ t.addSplit(s0);
+
+ // if we have no other split we create it
+ // if we have none or only one other split, we reconstruct it here
+ // if we have more than one other split, we take them as they are
+ // make sure to perform all those changes on a local copy
+ QValueList<MyMoneySplit> splits = m_splits;
+
+ MyMoneySplit s1;
+ if(splits.count() == 0) {
+ s1.setMemo(s0.memo());
+ splits.append(s1);
+
+ // make sure we will fill the value and share fields later on
+ updateValue = true;
+ }
+
+ // FIXME in multiSelection we currently only support transactions with one
+ // or two splits. So we check the original transaction and extract the other
+ // split or create it
+ if(isMultiSelection()) {
+ if(torig.splitCount() == 2) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) {
+ if((*it_s).id() == sorig.id())
+ continue;
+ s1 = *it_s;
+ s1.clearId();
+ break;
+ }
+ }
+ } else {
+ if(splits.count() == 1) {
+ s1 = splits[0];
+ s1.clearId();
+ }
+ }
+
+ if(isMultiSelection() || splits.count() == 1) {
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ if(!isMultiSelection() || (isMultiSelection() && !category->currentText().isEmpty())) {
+ s1.setAccountId(category->selectedItem());
+ }
+
+ // if the first split has a memo but the second split is empty,
+ // we just copy the memo text over
+ if(memo) {
+ if(!isMultiSelection() || (isMultiSelection() && !memo->text().isEmpty())) {
+ // if the memo is filled, we check if the
+ // account referenced by s1 is a regular account or a category.
+ // in case of a regular account, we just leave the memo as is
+ // in case of a category we simply copy the new value over the old.
+ // in case we don't even have an account id, we just skip because
+ // the split will be removed later on anyway.
+ if(!s1.memo().isEmpty()) {
+ if(!s1.accountId().isEmpty()) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(s1.accountId());
+ if(acc.isIncomeExpense()) {
+ s1.setMemo(s0.memo());
+ }
+ }
+ } else {
+ s1.setMemo(s0.memo());
+ }
+ }
+ }
+
+ if(updateValue && !s1.accountId().isEmpty()) {
+ s1.setValue(-value);
+ MyMoneyMoney shares;
+ if(!skipPriceDialog) {
+ if(!KCurrencyCalculator::setupSplitPrice(shares, t, s1, m_priceInfo, m_regForm))
+ return false;
+ } else {
+ MyMoneyAccount cat = MyMoneyFile::instance()->account(s1.accountId());
+ if(m_priceInfo.find(cat.currencyId()) != m_priceInfo.end()) {
+ shares = (s1.value() * m_priceInfo[cat.currencyId()]).reduce().convert(cat.fraction());
+ }
+ else
+ shares = s1.value();
+ }
+ s1.setShares(shares);
+ }
+
+ checkPayeeInSplit(s1, payeeId);
+
+ if(!s1.accountId().isEmpty())
+ t.addSplit(s1);
+
+ } else {
+ QValueList<MyMoneySplit>::iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ s1 = *it_s;
+ s1.clearId();
+ checkPayeeInSplit(s1, payeeId);
+ t.addSplit(s1);
+ }
+ }
+ return true;
+}
+
+void StdTransactionEditor::setupFinalWidgets(void)
+{
+ addFinalWidget(haveWidget("deposit"));
+ addFinalWidget(haveWidget("payment"));
+ addFinalWidget(haveWidget("amount"));
+ addFinalWidget(haveWidget("status"));
+}
+
+void StdTransactionEditor::slotUpdateAccount(const QString& id)
+{
+ TransactionEditor::slotUpdateAccount(id);
+ KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets["category"]);
+ if(category && category->splitButton()) {
+ category->splitButton()->setDisabled(id.isEmpty());
+ }
+}
+
+#include "transactioneditor.moc"
+
diff --git a/kmymoney2/dialogs/transactioneditor.h b/kmymoney2/dialogs/transactioneditor.h
new file mode 100644
index 0000000..bf47598
--- /dev/null
+++ b/kmymoney2/dialogs/transactioneditor.h
@@ -0,0 +1,416 @@
+/***************************************************************************
+ transactioneditor.h
+ ----------
+ begin : Wed Jun 07 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TRANSACTIONEDITOR_H
+#define TRANSACTIONEDITOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qwidgetlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/transactioneditorcontainer.h>
+#include <kmymoney/register.h>
+
+class KCurrencyExchange;
+class KMyMoneyCategory;
+
+class TransactionEditor : public QObject
+{
+ Q_OBJECT
+public:
+ TransactionEditor() {}
+ TransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate);
+ virtual ~TransactionEditor();
+
+ /**
+ * This method is used as a helper because virtual methods cannot be
+ * called within a constructor. Thus setup() should be called immediately
+ * after a TransactionEditor() object or one of its derivatives is
+ * constructed. The parameter @a account identifies the account that
+ * is currently opened in the calling ledger view.
+ *
+ * This account will not be included in category sets. The default is
+ * no account so all will be shown. I have no idea anymore, what I
+ * tried to say with the first sentence above. :( Maybe this is crap.
+ *
+ * @param tabOrderWidgets QWidgetList which will be filled with the pointers
+ * to the editWidgets in their tab order
+ * @param account account that is currently shown in the calling ledger view
+ * @param action default action (defaults to ActionNone).
+ */
+ void setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account = MyMoneyAccount(), KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone);
+
+ /**
+ * Enter the transactions into the ledger. In case of a newly created
+ * transaction @a newId contains the assigned id. In case @a askForSchedule
+ * is true (the default), the user will be asked if he wants to enter new
+ * transactions with a post date in the future into the ledger or rather
+ * create a schedule for them. In case @a suppressBalanceWarnings is @p false
+ * (the default) a warning will be displayed when the balance crosses the minimum
+ * or maximum balance settings for the account.
+ */
+ virtual bool enterTransactions(QString& newId, bool askForSchedule = true, bool suppressBalanceWarnings = false);
+
+ /**
+ * This method creates a transaction based on the contents of the current widgets,
+ * the splits in m_split in single selection mode or an existing transaction/split
+ * and the contents of the widgets in multi selection mode.
+ *
+ * The split referencing the current account is returned as the first split in the
+ * transaction's split list.
+ *
+ * @param t reference to created transaction
+ * @param torig the original transaction
+ * @param sorig the original split
+ * @param skipPriceDialog if @p true the user will not be requested for price information
+ * (defaults to @p false)
+ *
+ * @return @p false if aborted by user, @p true otherwise
+ *
+ * @note Usually not used directly. If unsure, use enterTransactions() instead.
+ */
+ virtual bool createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog = false) = 0;
+
+ /**
+ * This method returns information about the completeness of the data
+ * entered. This can be used to control the availability of the
+ * 'Enter transaction' action.
+ *
+ * @retval true if entering the transaction into the engine
+ * @retval false if not enough information is present to enter the
+ * transaction into the engine
+ *
+ * @param reason will be filled with a string about the reason why the
+ * completeness is not reached. Empty if the return value
+ * is @c true.
+ *
+ * @sa transactionDataSufficient()
+ */
+ virtual bool isComplete(QString& reason) const = 0;
+
+ /**
+ * This method returns information if the editor is started with multiple transactions
+ * being selected or not.
+ *
+ * @retval false only a single transaction was selected when the editor was started
+ * @retval true multiple transactions were selected when the editor was started
+ */
+ virtual bool isMultiSelection(void) const { return m_transactions.count() > 1; }
+
+ virtual bool fixTransactionCommodity(const MyMoneyAccount& account);
+
+ virtual bool canAssignNumber(void) const;
+ virtual void assignNextNumber(void);
+
+ /**
+ * Returns a pointer to the widget that should receive
+ * the focus after the editor has been started.
+ */
+ virtual QWidget* firstWidget(void) const = 0;
+
+ /**
+ * Returns a pointer to a widget by name
+ */
+ QWidget* haveWidget(const QString& name) const;
+
+ void setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s);
+
+ bool eventFilter(QObject* o, QEvent* e);
+
+ const MyMoneyAccount& account(void) const { return m_account; }
+
+ void clearFinalWidgets(void);
+
+ void addFinalWidget(const QWidget*);
+
+public slots:
+ void slotReloadEditWidgets(void);
+
+ /**
+ * The default implementation returns QDialog::Rejected
+ */
+ virtual int slotEditSplits(void);
+
+ /**
+ * Modify the account which the transaction should be based on. The
+ * initial value for the account is passed during setup().
+ *
+ * @param id of the account to be used
+ */
+ void slotUpdateAccount(const QString& id);
+
+protected:
+ virtual void createEditWidgets(void) = 0;
+ virtual void setupFinalWidgets(void) = 0;
+ virtual void loadEditWidgets(KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone) = 0;
+ void setupCategoryWidget(KMyMoneyCategory* category, const QValueList<MyMoneySplit>& splits, QString& categoryId, const char* splitEditSlot, bool allowObjectCreation = true);
+
+ /**
+ * This method sets the precision of the value widgets to reflect
+ * the account in m_account. If m_account has no id, the precision
+ * defaults to 2.
+ */
+ void setupPrecision(void);
+
+protected slots:
+ virtual void slotUpdateButtonState(void);
+ virtual void slotUpdateAccount(void);
+ virtual void slotNumberChanged(const QString&);
+
+signals:
+ /**
+ * This signal is sent out by the destructor to inform other entities
+ * that editing has been finished. The parameter @a t contains the list
+ * of transactions that were processed.
+ */
+ void finishEdit(const KMyMoneyRegister::SelectedTransactions& t);
+
+ /**
+ * This signal is sent out whenever enough data is present to enter the
+ * transaction into the ledger. This signal can be used to control the
+ * KAction which implements entering the transaction.
+ *
+ * @sa isComplete()
+ *
+ * @param state @a true if enough data is present, @a false otherwise.
+ */
+ void transactionDataSufficient(bool state);
+
+ /**
+ * This signal is sent out, when a new payee needs to be created
+ * @sa KMyMoneyCombo::createItem()
+ *
+ * @param txt The name of the payee to be created
+ * @param id A connected slot should store the id of the created object in this variable
+ */
+ void createPayee(const QString& txt, QString& id);
+
+ /**
+ * This signal is sent out, when a new category needs to be created
+ * Depending on the setting of either a payment or deposit, the parent
+ * account will be preset to Expense or Income.
+ *
+ * @param account reference to account info. Will be filled by called slot
+ * @param parent reference to parent account
+ */
+ void createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent);
+
+ /**
+ * This signal is sent out, when a new security (e.g. stock )needs to be created
+ * @a Parent should be the investment account under which the security account
+ * will be created.
+ *
+ * @param account reference to account info. Will be filled by called slot
+ * @param parent reference to parent account
+ */
+ void createSecurity(MyMoneyAccount& account, const MyMoneyAccount& parent);
+
+ /**
+ * Signal is emitted, if any of the widgets enters (@a state equals @a true)
+ * or leaves (@a state equals @a false) object creation mode.
+ *
+ * @param state Enter (@a true) or leave (@a false) object creation
+ */
+ void objectCreation(bool state);
+
+ void statusMsg(const QString& txt);
+
+ void statusProgress(int cnt, int base);
+
+ /**
+ * This signal is sent out for each newly added transaction
+ *
+ * @param date the post date of the newly created transaction
+ */
+ void lastPostDateUsed(const QDate& date);
+
+ /**
+ * This signal is sent out, if the user decides to schedule the transaction @a t
+ * rather then adding it to the ledger right away.
+ */
+ void scheduleTransaction(const MyMoneyTransaction& t, MyMoneySchedule::occurenceE occurence);
+
+ /**
+ * This signal is sent out, if the user double clicks the number field
+ */
+ void assignNumber(void);
+
+ /**
+ * This signal is sent out, if the user has pressed the ESC key.
+ */
+ void escapePressed(void);
+
+ /**
+ * This signal is sent out, if the user has pressed the Return or Enter
+ * key and asks to end editing the transaction
+ */
+ void returnPressed(void);
+
+ /**
+ * This signal is sent out, if any of the balance warning levels
+ * for @p account has been reached. @p msg contains the message text.
+ * @p parent points to the parent widget to be used for the warning message box.
+ */
+ void balanceWarning(QWidget* parent, const MyMoneyAccount& account, const QString& msg);
+
+protected:
+ QValueList<MyMoneySplit> m_splits;
+ KMyMoneyRegister::SelectedTransactions m_transactions;
+ QValueList<const QWidget*> m_finalEditWidgets;
+ TransactionEditorContainer* m_regForm;
+ KMyMoneyRegister::Transaction* m_item;
+ KMyMoneyRegister::QWidgetContainer m_editWidgets;
+ MyMoneyAccount m_account;
+ MyMoneyTransaction m_transaction;
+ MyMoneySplit m_split;
+ QDate m_lastPostDate;
+ QMap<QString, MyMoneyMoney> m_priceInfo;
+ KMyMoneyRegister::Action m_initialAction;
+ bool m_openEditSplits;
+};
+
+
+class StdTransactionEditor : public TransactionEditor
+{
+ Q_OBJECT
+public:
+ StdTransactionEditor();
+ StdTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate);
+ ~StdTransactionEditor();
+
+ bool isComplete(QString& reason) const;
+ QWidget* firstWidget(void) const;
+
+ bool eventFilter(QObject* o, QEvent* e);
+
+ /**
+ * This method creates a transaction based on the contents of the current widgets,
+ * the splits in m_split in single selection mode or an existing transaction/split
+ * and the contents of the widgets in multi selection mode.
+ *
+ * The split referencing the current account is returned as the first split in the
+ * transaction's split list.
+ *
+ * @param t reference to created transaction
+ * @param torig the original transaction
+ * @param sorig the original split
+ * @param skipPriceDialog if @p true the user will not be requested for price information
+ * (defaults to @p false)
+ *
+ * @return @p false if aborted by user, @p true otherwise
+ *
+ * @note Usually not used directly. If unsure, use enterTransactions() instead.
+ */
+ bool createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog = false);
+
+public slots:
+ int slotEditSplits(void);
+ void slotUpdateAmount(const QString&);
+
+protected slots:
+ void slotReloadEditWidgets(void);
+ void slotUpdatePayment(const QString&);
+ void slotUpdateDeposit(const QString&);
+ void slotUpdateCategory(const QString&);
+ void slotUpdatePayee(const QString&);
+ void slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection);
+ void slotCreateCategory(const QString&, QString&);
+ void slotUpdateAction(int action);
+ void slotUpdateAccount(const QString& id);
+
+protected:
+ /**
+ * This method creates all necessary widgets for this transaction editor.
+ * All signals will be connected to the relevant slots.
+ */
+ void createEditWidgets(void);
+
+ /**
+ * This method (re-)loads the widgets with the transaction information
+ * contained in @a m_transaction and @a m_split.
+ *
+ * @param action preset the edit wigdets for @a action if no transaction
+ * is present
+ */
+ void loadEditWidgets(KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone);
+
+ void setupCategoryWidget(QString&);
+ void updateAmount(const MyMoneyMoney& value);
+ bool isTransfer(const QString& accId1, const QString& accId2) const;
+
+ void checkPayeeInSplit(MyMoneySplit& s, const QString& payeeId);
+
+ /**
+ * This method fills the editor widgets with the last transaction
+ * that can be found for payee @a payeeId in the account @a m_account.
+ */
+ void autoFill(const QString& payeeId);
+
+ /**
+ * Extracts the amount of the transaction from the widgets depending
+ * if form or register based input method is used.
+ * Returns if an amount has been found in @a update.
+ *
+ * @param update pointer to update information flag
+ * @return amount of transaction (deposit positive, payment negative)
+ */
+ MyMoneyMoney amountFromWidget(bool* update = 0) const;
+
+ /**
+ * Create or update a VAT split
+ */
+ void updateVAT(bool amountChanged = true);
+
+ MyMoneyMoney removeVatSplit(void);
+
+ /**
+ * This method adds a VAT split to transaction @a tr if necessary.
+ *
+ * @param tr transaction that the split should be added to
+ * @param amount Amount to be used for the calculation. Depending upon the
+ * setting of the resp. category, this value is treated as
+ * either gross or net value.
+ * @retval false VAT split has not been added
+ * @retval true VAT split has been added
+ */
+ bool addVatSplit(MyMoneyTransaction& tr, const MyMoneyMoney& amount);
+
+ void setupFinalWidgets(void);
+
+ /**
+ * This method returns the sum of all splits of transaction @a t that
+ * reference account m_account.
+ */
+ MyMoneyMoney shares(const MyMoneyTransaction& t) const;
+
+private:
+ MyMoneyMoney m_shares;
+ bool m_inUpdateVat;
+};
+
+
+#endif
diff --git a/kmymoney2/dialogs/transactionmatcher.cpp b/kmymoney2/dialogs/transactionmatcher.cpp
new file mode 100644
index 0000000..5b8d4b5
--- /dev/null
+++ b/kmymoney2/dialogs/transactionmatcher.cpp
@@ -0,0 +1,361 @@
+/***************************************************************************
+ transactionmatcher.cpp
+ ----------
+ begin : Tue Jul 08 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "transactionmatcher.h"
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/kmymoneyutils.h>
+
+TransactionMatcher::TransactionMatcher(const MyMoneyAccount& acc) :
+ m_account(acc),
+ m_days(3)
+{
+}
+
+void TransactionMatcher::match(MyMoneyTransaction tm, MyMoneySplit sm, MyMoneyTransaction ti, MyMoneySplit si, bool allowImportedTransactions)
+{
+ const MyMoneySecurity& sec = MyMoneyFile::instance()->security(m_account.currencyId());
+
+ // Now match the transactions.
+ //
+ // 'Matching' the transactions entails DELETING the end transaction,
+ // and MODIFYING the start transaction as needed.
+ //
+ // There are a variety of ways that a transaction can conflict.
+ // Post date, splits, amount are the ones that seem to matter.
+ // TODO: Handle these conflicts intelligently, at least warning
+ // the user, or better yet letting the user choose which to use.
+ //
+ // For now, we will just use the transaction details from the start
+ // transaction. The only thing we'll take from the end transaction
+ // are the bank ID's.
+ //
+ // What we have to do here is iterate over the splits in the end
+ // transaction, and find the corresponding split in the start
+ // transaction. If there is a bankID in the end split but not the
+ // start split, add it to the start split. If there is a bankID
+ // in BOTH, then this transaction cannot be merged (both transactions
+ // were imported!!) If the corresponding start split cannot be
+ // found and the end split has a bankID, we should probably just fail.
+ // Although we could ADD it to the transaction.
+
+ // ipwizard: Don't know if iterating over the transactions is a good idea.
+ // In case of a split transaction recorded with KMyMoney and the transaction
+ // data being imported consisting only of a single category assignment, this
+ // does not make much sense. The same applies for investment transactions
+ // stored in KMyMoney against imported transactions. I think a better solution
+ // is to just base the match on the splits referencing the same (currently
+ // selected) account.
+
+ // verify, that tm is a manually (non-matched) transaction and ti an imported one
+ if(sm.isMatched() || (!allowImportedTransactions && tm.isImported()))
+ throw new MYMONEYEXCEPTION(i18n("First transaction does not match requirement for matching"));
+ if(!ti.isImported())
+ throw new MYMONEYEXCEPTION(i18n("Second transaction does not match requirement for matching"));
+
+ // verify that the amounts are the same, otherwise we should not be matching!
+ if(sm.shares() != si.shares()) {
+ throw new MYMONEYEXCEPTION(i18n("Splits for %1 have conflicting values (%2,%3)").arg(m_account.name()).arg(sm.shares().formatMoney(m_account, sec), si.shares().formatMoney(m_account, sec)));
+ }
+
+ // ipwizard: I took over the code to keep the bank id found in the endMatchTransaction
+ // This might not work for QIF imports as they don't setup this information. It sure
+ // makes sense for OFX and HBCI.
+ const QString& bankID = si.bankID();
+ if (!bankID.isEmpty()) {
+ try {
+ if (sm.bankID().isEmpty() ) {
+ sm.setBankID( bankID );
+ tm.modifySplit(sm);
+ } else if(sm.bankID() != bankID) {
+ throw new MYMONEYEXCEPTION(i18n("Both of these transactions have been imported into %1. Therefore they cannot be matched. Matching works with one imported transaction and one non-imported transaction.").arg(m_account.name()));
+ }
+ } catch(MyMoneyException *e) {
+ QString estr = e->what();
+ delete e;
+ throw new MYMONEYEXCEPTION(i18n("Unable to match all splits (%1)").arg(estr));
+ }
+ }
+
+#if 0 // Ace's original code
+ // TODO (Ace) Add in another error to catch the case where a user
+ // tries to match two hand-entered transactions.
+ QValueList<MyMoneySplit> endSplits = endMatchTransaction.splits();
+ QValueList<MyMoneySplit>::const_iterator it_split = endSplits.begin();
+ while (it_split != endSplits.end())
+ {
+ // find the corresponding split in the start transaction
+ MyMoneySplit startSplit;
+ QString accountid = (*it_split).accountId();
+ try
+ {
+ startSplit = startMatchTransaction.splitByAccount( accountid );
+ }
+ // only exception is thrown if we cannot find a split like this
+ catch(MyMoneyException *e)
+ {
+ delete e;
+ startSplit = (*it_split);
+ startSplit.clearId();
+ startMatchTransaction.addSplit(startSplit);
+ }
+
+ // verify that the amounts are the same, otherwise we should not be
+ // matching!
+ if ( (*it_split).value() != startSplit.value() )
+ {
+ QString accountname = MyMoneyFile::instance()->account(accountid).name();
+ throw new MYMONEYEXCEPTION(i18n("Splits for %1 have conflicting values (%2,%3)").arg(accountname).arg((*it_split).value().formatMoney(),startSplit.value().formatMoney()));
+ }
+
+ QString bankID = (*it_split).bankID();
+ if ( ! bankID.isEmpty() )
+ {
+ try
+ {
+ if ( startSplit.bankID().isEmpty() )
+ {
+ startSplit.setBankID( bankID );
+ startMatchTransaction.modifySplit(startSplit);
+ }
+ else
+ {
+ QString accountname = MyMoneyFile::instance()->account(accountid).name();
+ throw new MYMONEYEXCEPTION(i18n("Both of these transactions have been imported into %1. Therefore they cannot be matched. Matching works with one imported transaction and one non-imported transaction.").arg(accountname));
+ }
+ }
+ catch(MyMoneyException *e)
+ {
+ QString estr = e->what();
+ delete e;
+ throw new MYMONEYEXCEPTION(i18n("Unable to match all splits (%1)").arg(estr));
+ }
+ }
+ ++it_split;
+ }
+#endif
+
+ // mark the split as cleared if it does not have a reconciliation information yet
+ if(sm.reconcileFlag() == MyMoneySplit::NotReconciled) {
+ sm.setReconcileFlag(MyMoneySplit::Cleared);
+ }
+
+ // if we don't have a payee assigned to the manually entered transaction
+ // we use the one we found in the imported transaction
+ if(sm.payeeId().isEmpty() && !si.payeeId().isEmpty()) {
+ sm.setValue("kmm-orig-payee", sm.payeeId());
+ sm.setPayeeId(si.payeeId());
+ }
+
+ // We use the imported postdate and keep the previous one for unmatch
+ if(tm.postDate() != ti.postDate()) {
+ sm.setValue("kmm-orig-postdate", tm.postDate().toString(Qt::ISODate));
+ tm.setPostDate(ti.postDate());
+ }
+
+ // combine the two memos into one
+ QString memo = sm.memo();
+ if(!si.memo().isEmpty() && si.memo() != memo) {
+ sm.setValue("kmm-orig-memo", memo);
+ if(!memo.isEmpty())
+ memo += "\n";
+ memo += si.memo();
+ }
+ sm.setMemo(memo);
+
+ // remember the split we matched
+ sm.setValue("kmm-match-split", si.id());
+
+ sm.addMatch(ti);
+ tm.modifySplit(sm);
+
+ MyMoneyFile::instance()->modifyTransaction(tm);
+ // Delete the end transaction if it was stored in the engine
+ if(!ti.id().isEmpty())
+ MyMoneyFile::instance()->removeTransaction(ti);
+}
+
+void TransactionMatcher::unmatch(const MyMoneyTransaction& _t, const MyMoneySplit& _s)
+{
+ if(_s.isMatched()) {
+ MyMoneyTransaction tm(_t);
+ MyMoneySplit sm(_s);
+ MyMoneyTransaction ti(sm.matchedTransaction());
+ MyMoneySplit si;
+ // if we don't have a split, then we don't have a memo
+ try {
+ si = ti.splitById(sm.value("kmm-match-split"));
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+ sm.removeMatch();
+
+ // restore the postdate if modified
+ if(!sm.value("kmm-orig-postdate").isEmpty()) {
+ tm.setPostDate(QDate::fromString(sm.value("kmm-orig-postdate"), Qt::ISODate));
+ }
+
+ // restore payee if modified
+ if(!sm.value("kmm-orig-payee").isEmpty()) {
+ sm.setPayeeId(sm.value("kmm-orig-payee"));
+ }
+
+ // restore memo if modified
+ if(!sm.value("kmm-orig-memo").isEmpty()) {
+ sm.setMemo(sm.value("kmm-orig-memo"));
+ }
+
+ sm.deletePair("kmm-orig-postdate");
+ sm.deletePair("kmm-orig-payee");
+ sm.deletePair("kmm-orig-memo");
+ sm.deletePair("kmm-match-split");
+ tm.modifySplit(sm);
+
+ MyMoneyFile::instance()->modifyTransaction(tm);
+ MyMoneyFile::instance()->addTransaction(ti);
+ }
+}
+
+void TransactionMatcher::accept(const MyMoneyTransaction& _t, const MyMoneySplit& _s)
+{
+ if(_s.isMatched()) {
+ MyMoneyTransaction tm(_t);
+ MyMoneySplit sm(_s);
+ sm.removeMatch();
+ sm.deletePair("kmm-orig-postdate");
+ sm.deletePair("kmm-orig-payee");
+ sm.deletePair("kmm-orig-memo");
+ sm.deletePair("kmm-match-split");
+ tm.modifySplit(sm);
+
+ MyMoneyFile::instance()->modifyTransaction(tm);
+ }
+}
+
+void TransactionMatcher::checkTransaction(const MyMoneyTransaction& tm, const MyMoneyTransaction& ti, const MyMoneySplit& si, QPair<MyMoneyTransaction, MyMoneySplit>& lastMatch, TransactionMatcher::autoMatchResultE& result, int variation) const
+{
+ Q_UNUSED(ti);
+
+
+ const QValueList<MyMoneySplit>& splits = tm.splits();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ MyMoneyMoney upper((*it_s).shares());
+ MyMoneyMoney lower(upper);
+ if((variation > 0) && (variation < 100)) {
+ lower = lower - (lower.abs() * MyMoneyMoney(variation, 100));
+ upper = upper + (upper.abs() * MyMoneyMoney(variation, 100));
+ }
+ // we only check for duplicates / matches if the sign
+ // of the amount for this split is identical
+ if((si.shares() >= lower) && (si.shares() <= upper)) {
+ // check for duplicate (we can only do that, if we have a bankID)
+ if(!si.bankID().isEmpty()) {
+ if((*it_s).bankID() == si.bankID()) {
+ lastMatch = QPair<MyMoneyTransaction, MyMoneySplit>(tm, *it_s);
+ result = matchedDuplicate;
+ break;
+ }
+ // in case the stored split already has a bankid
+ // assigned, it must be a different one and therefore
+ // will certainly not match
+ if(!(*it_s).bankID().isEmpty())
+ continue;
+ }
+ // check if this is the one that matches
+ if((*it_s).accountId() == si.accountId()
+ && (si.shares() >= lower) && (si.shares() <= upper)
+ && !(*it_s).isMatched()) {
+ if(tm.postDate() == ti.postDate()) {
+ lastMatch = QPair<MyMoneyTransaction, MyMoneySplit>(tm, *it_s);
+ result = matchedExact;
+ } else if(result != matchedExact) {
+ lastMatch = QPair<MyMoneyTransaction, MyMoneySplit>(tm, *it_s);
+ result = matched;
+ }
+ }
+ }
+ }
+}
+
+MyMoneyObject const * TransactionMatcher::findMatch(const MyMoneyTransaction& ti, const MyMoneySplit& si, MyMoneySplit& sm, autoMatchResultE& result)
+{
+ result = notMatched;
+ sm = MyMoneySplit();
+
+ MyMoneyTransactionFilter filter(si.accountId());
+ filter.setReportAllSplits(false);
+ filter.setDateFilter(ti.postDate().addDays(-m_days), ti.postDate().addDays(m_days));
+ filter.setAmountFilter(si.shares(), si.shares());
+
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> > list;
+ MyMoneyFile::instance()->transactionList(list, filter);
+
+ // parse list
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::iterator it_l;
+ QPair<MyMoneyTransaction, MyMoneySplit> lastMatch;
+
+ for(it_l = list.begin(); (result != matchedDuplicate) && (it_l != list.end()); ++it_l) {
+ // just skip myself
+ if((*it_l).first.id() == ti.id()) {
+ continue;
+ }
+
+ checkTransaction((*it_l).first, ti, si, lastMatch, result);
+ }
+
+ MyMoneyObject* rc = 0;
+ if(result != notMatched) {
+ sm = lastMatch.second;
+ rc = new MyMoneyTransaction(lastMatch.first);
+
+ } else {
+ // if we did not find anything, we need to scan for scheduled transactions
+ QValueList<MyMoneySchedule> list;
+ QValueList<MyMoneySchedule>::iterator it_sch;
+ // find all schedules that have a reference to the current account
+ list = MyMoneyFile::instance()->scheduleList(m_account.id());
+ for(it_sch = list.begin(); (result != matched && result != matchedExact) && (it_sch != list.end()); ++it_sch) {
+ // get the next due date adjusted by the weekend switch
+ QDate nextDueDate = (*it_sch).nextDueDate();
+ if((*it_sch).isOverdue() ||
+ (nextDueDate >= ti.postDate().addDays(-m_days)
+ && nextDueDate <= ti.postDate().addDays(m_days))) {
+ MyMoneyTransaction st = KMyMoneyUtils::scheduledTransaction(*it_sch);
+ checkTransaction(st, ti, si, lastMatch, result, (*it_sch).variation());
+ if(result == matched || result == matchedExact) {
+ sm = lastMatch.second;
+ rc = new MyMoneySchedule(*it_sch);
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
diff --git a/kmymoney2/dialogs/transactionmatcher.h b/kmymoney2/dialogs/transactionmatcher.h
new file mode 100644
index 0000000..e5e036c
--- /dev/null
+++ b/kmymoney2/dialogs/transactionmatcher.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ transactionmatcher.h
+ ----------
+ begin : Tue Jul 08 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TRANSACTIONMATCHER_H
+#define TRANSACTIONMATCHER_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneyaccount.h>
+class MyMoneySchedule;
+
+class TransactionMatcher
+{
+public:
+ typedef enum {
+ notMatched = 0, ///< no matching transaction found
+ matched, ///< matching transaction found
+ matchedExact, ///< matching transaction found with exact same date
+ matchedDuplicate ///< duplicate matching transaction found
+ } autoMatchResultE;
+
+ TransactionMatcher(const MyMoneyAccount& acc);
+
+ /**
+ * This method matches the manual entered transaction @p tm with the imported
+ * transaction @p ti based on the splits @p sm and @p si. If the match can be applied,
+ * MyMoneyTransaction::addMatch() is used to include @p ti inside @p tm and the
+ * engine data (MyMoneyFile) is updated. A possible bankid found in the imported
+ * split is carried over into the manual transaction.
+ *
+ * The following things will be done in case of a match:
+ *
+ * - if the postdate differs between the two transactions
+ * - the postdate of the manual entered transaction is stored in kmm-orig-postdate
+ * - the postdate of the imported transaction is assigned to the resulting transaction
+ * - if the payee differs between the two splits
+ * - the payee of the manual split is stored in kmm-orig-payee
+ * - the payee of the imported split is assigned to the resulting split
+ * - if the reconciliation state is not-reconciled
+ * - the reconciliation state is set to cleared
+ * - the bankid of the imported transaction is assigned to the resulting transaction
+ * - the resulting transaction will be updated and the imported transaction removed
+ * from the engine
+ *
+ * The application of the match depends on the following items:
+ *
+ * - both share values of @p sm and @p si must be identical
+ * - @p tm must be a non-imported (see below), non-matched transaction
+ * - @p ti must be an imported transaction
+ *
+ * If @p allowImportedTransactions is true, @p tm may be an imported transaction. The
+ * default of @p allowImportedTransactions is @p false.
+ *
+ * In case of errors, an exception is thrown.
+ */
+ void match(MyMoneyTransaction tm, MyMoneySplit sm, MyMoneyTransaction ti, MyMoneySplit si, bool allowImportedTransactions = false);
+
+ /**
+ * This method is used to unmatch a previously matched transaction (see match() and findMatch() )
+ * and restore the original and imported transaction in the engine.
+ *
+ * The following things will be done in case @p t is a matched transaction:
+ *
+ * - the enclosed imported transaction is extracted and restored
+ * - if the kvp contains a kmm-orig-payee record
+ * - the payee is updated to this value if it still exists, otherwise the payee is left empty
+ * - if the kvp contains a kmm-orig-postdate record
+ * - the postdate of the transaction is changed to the value stored in this record
+ * - a matching bankid is removed from the transaction
+ * - the resulting transaction will be updated and the imported transaction inserted
+ * into the engine
+ *
+ * In case of errors, an exception is thrown.
+ */
+ void unmatch(const MyMoneyTransaction& t, const MyMoneySplit& s);
+
+ /**
+ * This method is used to accept a previously matched transaction (see match() and findMatch())
+ *
+ * The following things will be done in case @p _t is a matched transaction
+ *
+ * - the enclosed imported transaction is removed
+ * - the kvps kmm-orig-payee and kmm-orig-postdate are removed
+ * - the resulting transaction will be updated
+ *
+ * In case of errors, an exception is thrown
+ */
+ void accept(const MyMoneyTransaction& t, const MyMoneySplit& s);
+
+ /**
+ * This method is used to automatically find a matching transaction in the ledger or the schedules.
+ * It should also detect duplicate imports according to the splits bankid.
+ *
+ * To be designed
+ *
+ * @param ti the imported transaction we want to match
+ * @param si the split of that transaction referencing the account we import into
+ * @param sm the split of the object returned that matches the split @a si. In case
+ * the returned pointer is not 0 this object contains the split. In other
+ * cases it contains an empty MyMoneySplit.
+ * @param result reference to the result details
+ *
+ * @returns pointer to MyMoneyObject (either a MyMoneyTransaction or a MyMoneySchedule). The
+ * caller of this method becomes the owner of the object pointed to and is responsible
+ * to delete the object
+ */
+ MyMoneyObject const * findMatch(const MyMoneyTransaction& ti, const MyMoneySplit& si, MyMoneySplit& sm, autoMatchResultE& result);
+
+ /**
+ * Sets the number of @a days to look for matching transactions. The default after object creation is 3 days.
+ */
+ void setMatchWindow(int days) { m_days = days; }
+
+private:
+ void checkTransaction(const MyMoneyTransaction& tm, const MyMoneyTransaction& ti, const MyMoneySplit& si, QPair<MyMoneyTransaction, MyMoneySplit>& lastMatch, autoMatchResultE& result, int variation = 0) const;
+
+private:
+ MyMoneyAccount m_account;
+ int m_days;
+};
+
+
+#endif
diff --git a/kmymoney2/export.h b/kmymoney2/export.h
new file mode 100644
index 0000000..1e8c3aa
--- /dev/null
+++ b/kmymoney2/export.h
@@ -0,0 +1,37 @@
+/*
+ This file is part of kmymoney2 project
+ Copyright (c) 2005 Laurent Montel <montel@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _KMYMONEY_EXPORT_H
+#define _KMYMONEY_EXPORT_H
+
+#include <kdeversion.h>
+
+#if KDE_IS_VERSION(3,2,90)
+ #ifdef __KDE_HAVE_GCC_VISIBILITY
+ #include <kdemacros.h>
+ #define KMYMONEY_EXPORT KDE_EXPORT
+ #else
+ #define KMYMONEY_EXPORT
+ #endif
+#else
+ #define KMYMONEY_EXPORT
+#endif
+#endif /* _KMYMONEY_EXPORT_H */
+
diff --git a/kmymoney2/hi128-app-kmymoney2.png b/kmymoney2/hi128-app-kmymoney2.png
new file mode 100644
index 0000000..8831c89
--- /dev/null
+++ b/kmymoney2/hi128-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/hi16-app-kmymoney2.png b/kmymoney2/hi16-app-kmymoney2.png
new file mode 100644
index 0000000..602dfe2
--- /dev/null
+++ b/kmymoney2/hi16-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/hi32-app-kmymoney2.png b/kmymoney2/hi32-app-kmymoney2.png
new file mode 100644
index 0000000..2c094bd
--- /dev/null
+++ b/kmymoney2/hi32-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/hi48-app-kmymoney2.png b/kmymoney2/hi48-app-kmymoney2.png
new file mode 100644
index 0000000..5d3dd78
--- /dev/null
+++ b/kmymoney2/hi48-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/hi64-app-kmymoney2.png b/kmymoney2/hi64-app-kmymoney2.png
new file mode 100644
index 0000000..c92938c
--- /dev/null
+++ b/kmymoney2/hi64-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/html/Makefile.am b/kmymoney2/html/Makefile.am
new file mode 100644
index 0000000..0d37ad0
--- /dev/null
+++ b/kmymoney2/html/Makefile.am
@@ -0,0 +1,23 @@
+KDE_OPTIONS = noautodist
+
+SUBDIRS = images
+
+HOMEPAGES = home_pt_BR.html home_de.html home_es.html home_fr.html home_gl.html home.html home_it.html home_nl.html home_ro.html home_ru.html home_tr.html home_pt.html
+
+WHATSNEWPAGES = whats_new_pt_BR.html whats_new_de.html whats_new_es.html whats_new_fr.html whats_new_gl.html whats_new.html whats_new_it.html whats_new_nl.html whats_new_ro.html whats_new_ru.html whats_new_tr.html
+
+EXTRA_DIST = $(HOMEPAGES) $(WHATSNEWPAGES) kmymoney2.css welcome.css
+
+LOCAL_DIR = kmymoney2/html
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(EXTRA_DIST); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+uninstall-local:
+ for file in $(EXTRA_DIST); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
diff --git a/kmymoney2/html/home.html b/kmymoney2/html/home.html
new file mode 100644
index 0000000..cf7e00e
--- /dev/null
+++ b/kmymoney2/html/home.html
@@ -0,0 +1,59 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Welcome to KMyMoney</h3>
+<h4 id="subtitle">The free, easy to use, personal finance manager for KDE</h4>
+<!--p id="tagline">Personal Finance Software</p-->
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Go to My Financial Summary</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div><!--topright-->
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+<h4>Start with one of the following activities...</h4>
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Get started and setup my accounts</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Open an existing KMyMoney data file</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Learn how to use KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visit the KMyMoney website</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Get help from the KMyMoney community</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">See what's new in this version</a></li>
+ </ul>
+ </div><!--welcomeMenu-->
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div><!--rightborder-->
+<div id="bottomleft">
+<div id="bottomright"></div><!--bottomright-->
+</div><!--bottomleft-->
+</div><!--topleft-->
+</body>
+</html>
diff --git a/kmymoney2/html/home_de.html b/kmymoney2/html/home_de.html
new file mode 100644
index 0000000..a3bf0c6
--- /dev/null
+++ b/kmymoney2/html/home_de.html
@@ -0,0 +1,58 @@
+<!--
+******************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+Thomas Baumgart ipwizard<at>users.sourceforge.net
+******************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=utf-8">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Willkommen bei KMyMoney</h3>
+<h4 id="subtitle">Ihrem persönlichen Finanzassistenten</h4>
+<!--p id="tagline">Personal Finance Software</p-->
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Zur Finanzübersicht</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <h4>Beginne mit einer der folgenden Aktivitäten...</h4>
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Erzeuge eine neue KMyMoney Datei</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Öffne eine bestehende KMyMoney Datei</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Lerne mit KMyMoney umzugehen</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Besuche die KMyMoney website</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Erhalte Hilfe von der KMyMoney Community</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Übersicht der neuen Funktionen dieser Version</a></li>
+ </ul>
+ </div><!--welcomeMenu-->
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div><!--rightborder-->
+<div id="bottomleft">
+<div id="bottomright"></div><!--bottomright-->
+</div><!--bottomleft-->
+</div><!--topleft-->
+</body>
+</html>
diff --git a/kmymoney2/html/home_es.html b/kmymoney2/html/home_es.html
new file mode 100644
index 0000000..78831fa
--- /dev/null
+++ b/kmymoney2/html/home_es.html
@@ -0,0 +1,58 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title" style="font-size: 20px;">Bienvenido a KMyMoney</h3>
+<h4 id="subtitle">Software de Gesti&oacute;n de Finanzas Personales</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Ir a Mi Resumen Financiero</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Crear un nuevo archivo de datos de KMyMoney</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Utilizar un archivos existente de datos de KMyMoney</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Aprender a usar KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visitar el sitio web de KMyMoney</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Obtener ayuda de la comunidad de KMyMoney</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Ver lo nuevo en esta versi&oacute;n</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_fr.html b/kmymoney2/html/home_fr.html
new file mode 100644
index 0000000..6f46322
--- /dev/null
+++ b/kmymoney2/html/home_fr.html
@@ -0,0 +1,61 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title" style="font-size: 20px;">Bienvenue dans KMyMoney</h3>
+<h4 id="subtitle">Logiciel de comptabilit� personnelle</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Acc�der � mon r�sum� financier</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <td style="height: 150px; width: 380px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Cr�er un nouveau fichier KMyMoney</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Utiliser un fichier KMyMoney existant</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Apprendre � utiliser KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visiter le site web de KMyMoney</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Obtenir de l'aide de la communaut� KMyMoney</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Voir les nouveaut�s de cette version</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
+
+
+
+
diff --git a/kmymoney2/html/home_gl.html b/kmymoney2/html/home_gl.html
new file mode 100644
index 0000000..09210fc
--- /dev/null
+++ b/kmymoney2/html/home_gl.html
@@ -0,0 +1,57 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Documento sen título</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title" style="font-size: 20px;">Benvido a KMyMoney</h3>
+<h4 id="subtitle">O xestor das s&uacute;as finanzas</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Ir ao resumo financeiro</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Criar un ficheiro novo</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Abrir un ficheiro de KMyMoney</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Aprender a utilizar KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visitar a web do proxecto</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Get help from the KMyMoney community</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Ver as novidades desta versi&oacute;n</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_it.html b/kmymoney2/html/home_it.html
new file mode 100644
index 0000000..ab9d4ea
--- /dev/null
+++ b/kmymoney2/html/home_it.html
@@ -0,0 +1,59 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Documento senza titolo</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Benvenuti in KMyMoney</h3>
+<h4 id="subtitle">Il gestore delle finanze personali per KDE libero e facile da utilizzare</h4>
+<!--p id="tagline">Personal Finance Software</p-->
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Vai al Riepilogo finanziario</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div><!--topright-->
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+<h4>Inizia con una delle seguenti attivit...</h4>
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Inizia e configura i miei conti</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Apri un file dati esistente di KMyMoney</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Impara a utilizzare KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visita il sito web di KMyMoney</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Ottieni aiuto dalla comunit di KMyMoney</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Leggi le novit di questa versione</a></li>
+ </ul>
+ </div><!--welcomeMenu-->
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div><!--rightborder-->
+<div id="bottomleft">
+<div id="bottomright"></div><!--bottomright-->
+</div><!--bottomleft-->
+</div><!--topleft-->
+</body>
+</html>
diff --git a/kmymoney2/html/home_nl.html b/kmymoney2/html/home_nl.html
new file mode 100644
index 0000000..531fd24
--- /dev/null
+++ b/kmymoney2/html/home_nl.html
@@ -0,0 +1,58 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Welkom bij KMyMoney</h3>
+<h4 id="subtitle">Persoonlijke Financi&euml;le Software</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Ga naar mijn Financi&euml;le Samenvatting</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Cre&euml;er een nieuw KMyMoney bestand</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Open een bestaand KMyMoney bestand</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Leer hoe je KMyMoney gebruikt</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Bezoek de KMyMoney website</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Vraag hulp aan de KMyMoney community</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Nieuw in deze versie</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_pt.html b/kmymoney2/html/home_pt.html
new file mode 100644
index 0000000..948290e
--- /dev/null
+++ b/kmymoney2/html/home_pt.html
@@ -0,0 +1,57 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Bemvindo ao KMyMoney</h3>
+<h4 id="subtitle">Gestor de Finanas Pessoais</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Aceder ao meu resumo financeiro</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Criar um novo ficheiro de dados KMyMoney</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Abrir um ficheiro de dados KMyMoney</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Aprender a utilizar o KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visitar o site internet do KMyMoney</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Ver as novidades de esta verso</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_pt_BR.html b/kmymoney2/html/home_pt_BR.html
new file mode 100644
index 0000000..ab2a30a
--- /dev/null
+++ b/kmymoney2/html/home_pt_BR.html
@@ -0,0 +1,58 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Pgina Inicial</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Bem Vindo ao KMyMoney</h3>
+<h4 id="subtitle">Software de Finanas Pessoais</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Ir para o Meu Resumo Financeiro</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Criar um novo arquivo de dados do KMyMoney</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Abrir um arquivo de dados existente do KMyMoney</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Aprender como usar o KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Visitar a pgina Web do KMyMoney</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Obter ajuda da comunidade do KMyMoney</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Ver as novidades desta verso</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_ro.html b/kmymoney2/html/home_ro.html
new file mode 100644
index 0000000..948748f
--- /dev/null
+++ b/kmymoney2/html/home_ro.html
@@ -0,0 +1,58 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Bine aţi venit în KMyMoney</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=utf-8">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Bine aţi venit în KMyMoney</h3>
+<h4 id="subtitle">Aplicaţie pentru gestionarea finanţelor personale</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Du-te la sumarul meu finaciar</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <!-- <td style="height: 150px; width: 380px;"> -->
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Creaţi un fişier de date KMyMoney nou</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Folosiţi un fişier de date KMyMoney existent</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Învăţaţi cum se foloseşte KMyMoney</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Vizitaţi siteul KMyMoney</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Cereţi ajutorul comunutăţii KMyMoney</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Vizualizaţi noutăţile din această versiune</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_ru.html b/kmymoney2/html/home_ru.html
new file mode 100644
index 0000000..9046c70
--- /dev/null
+++ b/kmymoney2/html/home_ru.html
@@ -0,0 +1,56 @@
+<!--
+***************************************************************************************
+16.03.2007 KMyMoney Welcome Page on Russian
+Andrey Cherepanov sibskull<at>mail.ru
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Страница приветствия</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=utf-8">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">Добро пожаловать в KMyMoney</h3>
+<h4 id="subtitle">Программа учёта финансов</h4>
+
+<div id="returnLink"><img src="images/backarrow.png" style="vertical-align: middle; "> <a href="/home">Сводное финансовое состояние</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <td style="height: 150px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Создать новый файл и настроить счета</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Открыть существующий файл</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">Руководство пользователя</a> (на английском языке)</li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">Веб-сайт KMyMoney</a> (на английском языке)</li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Форум сообщества пользователей KMyMoney</a> (на английском языке)</li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew">Изменения в этой версии</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/home_tr.html b/kmymoney2/html/home_tr.html
new file mode 100644
index 0000000..275226d
--- /dev/null
+++ b/kmymoney2/html/home_tr.html
@@ -0,0 +1,57 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Untitled Document</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-9">
+ <link href="welcome.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+<h3 id="title">KMyMoney Uygulamasna Hogeldiniz</h3>
+<h4 id="subtitle">Kiisel Finans Uygulamas</h4>
+
+<div id="returnLink"><a href="/home"><img src="images/backarrow.png">Finansal zetim Sayfasna Git</a></div>
+<div id="topleft">
+<div id="topright"><img src="images/spacer.png"></div>
+<div id="rightborder">
+<table style="width: 100%;">
+ <tbody>
+ <tr>
+ <td></td>
+ <td style="height: 150px; width: 380px;">
+ <div id="welcomeMenu">
+ <ul>
+ <li><img src="images/filenew.png"><a href="/action?id=file_new">Yeni KMyMoney veri dosyas olutur</a></li>
+ <li><img src="images/kmymoneydata.png"><a href="/action?id=file_open">Bir KMyMoney veri dosyas kullan</a></li>
+ <li><img src="images/manual.png"><a href="/action?id=help_contents">KMyMoney kullanm klavuzu</a></li>
+ <li><img src="images/konqueror.png"><a href="http://kmymoney2.sf.net">KMyMoney websitesine git</a></li>
+ <li><img src="images/about_kde.png"><a href="http://forum.kde.org/viewforum.php?f=69">Get help from the KMyMoney community</a></li>
+ <li><img src="images/messagebox_info.png"><a href="/welcome?mode=whatsnew"> Bu srmdeki yenilikler sayfasna git</a></li>
+ </ul>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<div id="bottomleft">
+<div id="bottomright"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/kmymoney2/html/images/Makefile.am b/kmymoney2/html/images/Makefile.am
new file mode 100644
index 0000000..94e4531
--- /dev/null
+++ b/kmymoney2/html/images/Makefile.am
@@ -0,0 +1,20 @@
+####### kdevelop will overwrite this part!!! (begin)##########
+
+KDE_OPTIONS = noautodist
+
+EXTRA_DIST = backarrow.png background.png bc.png bl.png bottomleft.png bottomright.png br.png center.png filenew.png kmymoneydata.png konqueror.png lc.png manual.png messagebox_info.png original-trans_logo.png rc.png rightborder.png spacer.png tc.png title-center.png title-left.png title-right.png tl.png topleft.png topright.png trans_logo.png tr.png spacer.gif shadow.png currencyflourish.png top-shadow.png arrow.png bg-texture.png about_kde.png
+
+LOCAL_DIR = kmymoney2/html/images
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/kmymoney2/html/images
+ for file in $(EXTRA_DIST); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+uninstall-local:
+ for file in $(EXTRA_DIST); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
+####### kdevelop will overwrite this part!!! (end)############
diff --git a/kmymoney2/html/images/about_kde.png b/kmymoney2/html/images/about_kde.png
new file mode 100644
index 0000000..a0f2439
--- /dev/null
+++ b/kmymoney2/html/images/about_kde.png
Binary files differ
diff --git a/kmymoney2/html/images/arrow.png b/kmymoney2/html/images/arrow.png
new file mode 100644
index 0000000..aaa00d5
--- /dev/null
+++ b/kmymoney2/html/images/arrow.png
Binary files differ
diff --git a/kmymoney2/html/images/backarrow.png b/kmymoney2/html/images/backarrow.png
new file mode 100644
index 0000000..80c9703
--- /dev/null
+++ b/kmymoney2/html/images/backarrow.png
Binary files differ
diff --git a/kmymoney2/html/images/background.png b/kmymoney2/html/images/background.png
new file mode 100644
index 0000000..fec81ec
--- /dev/null
+++ b/kmymoney2/html/images/background.png
Binary files differ
diff --git a/kmymoney2/html/images/bc.png b/kmymoney2/html/images/bc.png
new file mode 100644
index 0000000..d2f1a11
--- /dev/null
+++ b/kmymoney2/html/images/bc.png
Binary files differ
diff --git a/kmymoney2/html/images/bg-texture.png b/kmymoney2/html/images/bg-texture.png
new file mode 100644
index 0000000..e71ad16
--- /dev/null
+++ b/kmymoney2/html/images/bg-texture.png
Binary files differ
diff --git a/kmymoney2/html/images/bl.png b/kmymoney2/html/images/bl.png
new file mode 100644
index 0000000..a84c1d6
--- /dev/null
+++ b/kmymoney2/html/images/bl.png
Binary files differ
diff --git a/kmymoney2/html/images/bottomleft.png b/kmymoney2/html/images/bottomleft.png
new file mode 100644
index 0000000..57c6c57
--- /dev/null
+++ b/kmymoney2/html/images/bottomleft.png
Binary files differ
diff --git a/kmymoney2/html/images/bottomright.png b/kmymoney2/html/images/bottomright.png
new file mode 100644
index 0000000..e35125b
--- /dev/null
+++ b/kmymoney2/html/images/bottomright.png
Binary files differ
diff --git a/kmymoney2/html/images/br.png b/kmymoney2/html/images/br.png
new file mode 100644
index 0000000..c1e7f51
--- /dev/null
+++ b/kmymoney2/html/images/br.png
Binary files differ
diff --git a/kmymoney2/html/images/center.png b/kmymoney2/html/images/center.png
new file mode 100644
index 0000000..fcf4a9a
--- /dev/null
+++ b/kmymoney2/html/images/center.png
Binary files differ
diff --git a/kmymoney2/html/images/currencyflourish.png b/kmymoney2/html/images/currencyflourish.png
new file mode 100644
index 0000000..2a7e924
--- /dev/null
+++ b/kmymoney2/html/images/currencyflourish.png
Binary files differ
diff --git a/kmymoney2/html/images/filenew.png b/kmymoney2/html/images/filenew.png
new file mode 100644
index 0000000..1da021f
--- /dev/null
+++ b/kmymoney2/html/images/filenew.png
Binary files differ
diff --git a/kmymoney2/html/images/kmymoneydata.png b/kmymoney2/html/images/kmymoneydata.png
new file mode 100644
index 0000000..bb3f937
--- /dev/null
+++ b/kmymoney2/html/images/kmymoneydata.png
Binary files differ
diff --git a/kmymoney2/html/images/konqueror.png b/kmymoney2/html/images/konqueror.png
new file mode 100644
index 0000000..fe7af79
--- /dev/null
+++ b/kmymoney2/html/images/konqueror.png
Binary files differ
diff --git a/kmymoney2/html/images/lc.png b/kmymoney2/html/images/lc.png
new file mode 100644
index 0000000..58a904c
--- /dev/null
+++ b/kmymoney2/html/images/lc.png
Binary files differ
diff --git a/kmymoney2/html/images/manual.png b/kmymoney2/html/images/manual.png
new file mode 100644
index 0000000..04b3070
--- /dev/null
+++ b/kmymoney2/html/images/manual.png
Binary files differ
diff --git a/kmymoney2/html/images/messagebox_info.png b/kmymoney2/html/images/messagebox_info.png
new file mode 100644
index 0000000..6e21f06
--- /dev/null
+++ b/kmymoney2/html/images/messagebox_info.png
Binary files differ
diff --git a/kmymoney2/html/images/original-trans_logo.png b/kmymoney2/html/images/original-trans_logo.png
new file mode 100644
index 0000000..25ea91f
--- /dev/null
+++ b/kmymoney2/html/images/original-trans_logo.png
Binary files differ
diff --git a/kmymoney2/html/images/rc.png b/kmymoney2/html/images/rc.png
new file mode 100644
index 0000000..198aff0
--- /dev/null
+++ b/kmymoney2/html/images/rc.png
Binary files differ
diff --git a/kmymoney2/html/images/rightborder.png b/kmymoney2/html/images/rightborder.png
new file mode 100644
index 0000000..fd29307
--- /dev/null
+++ b/kmymoney2/html/images/rightborder.png
Binary files differ
diff --git a/kmymoney2/html/images/shadow.png b/kmymoney2/html/images/shadow.png
new file mode 100644
index 0000000..5e6ff3d
--- /dev/null
+++ b/kmymoney2/html/images/shadow.png
Binary files differ
diff --git a/kmymoney2/html/images/spacer.gif b/kmymoney2/html/images/spacer.gif
new file mode 100644
index 0000000..fc25609
--- /dev/null
+++ b/kmymoney2/html/images/spacer.gif
Binary files differ
diff --git a/kmymoney2/html/images/spacer.png b/kmymoney2/html/images/spacer.png
new file mode 100644
index 0000000..8bcb60d
--- /dev/null
+++ b/kmymoney2/html/images/spacer.png
Binary files differ
diff --git a/kmymoney2/html/images/tc.png b/kmymoney2/html/images/tc.png
new file mode 100644
index 0000000..a93334c
--- /dev/null
+++ b/kmymoney2/html/images/tc.png
Binary files differ
diff --git a/kmymoney2/html/images/title-center.png b/kmymoney2/html/images/title-center.png
new file mode 100644
index 0000000..3b3cec9
--- /dev/null
+++ b/kmymoney2/html/images/title-center.png
Binary files differ
diff --git a/kmymoney2/html/images/title-left.png b/kmymoney2/html/images/title-left.png
new file mode 100644
index 0000000..8c20d8a
--- /dev/null
+++ b/kmymoney2/html/images/title-left.png
Binary files differ
diff --git a/kmymoney2/html/images/title-right.png b/kmymoney2/html/images/title-right.png
new file mode 100644
index 0000000..3938c54
--- /dev/null
+++ b/kmymoney2/html/images/title-right.png
Binary files differ
diff --git a/kmymoney2/html/images/tl.png b/kmymoney2/html/images/tl.png
new file mode 100644
index 0000000..3e0156c
--- /dev/null
+++ b/kmymoney2/html/images/tl.png
Binary files differ
diff --git a/kmymoney2/html/images/top-shadow.png b/kmymoney2/html/images/top-shadow.png
new file mode 100644
index 0000000..b59c952
--- /dev/null
+++ b/kmymoney2/html/images/top-shadow.png
Binary files differ
diff --git a/kmymoney2/html/images/topleft.png b/kmymoney2/html/images/topleft.png
new file mode 100644
index 0000000..a15cf15
--- /dev/null
+++ b/kmymoney2/html/images/topleft.png
Binary files differ
diff --git a/kmymoney2/html/images/topright.png b/kmymoney2/html/images/topright.png
new file mode 100644
index 0000000..9ad46c9
--- /dev/null
+++ b/kmymoney2/html/images/topright.png
Binary files differ
diff --git a/kmymoney2/html/images/tr.png b/kmymoney2/html/images/tr.png
new file mode 100644
index 0000000..fa73979
--- /dev/null
+++ b/kmymoney2/html/images/tr.png
Binary files differ
diff --git a/kmymoney2/html/images/trans_logo.png b/kmymoney2/html/images/trans_logo.png
new file mode 100644
index 0000000..0d73e2c
--- /dev/null
+++ b/kmymoney2/html/images/trans_logo.png
Binary files differ
diff --git a/kmymoney2/html/kmymoney2.css b/kmymoney2/html/kmymoney2.css
new file mode 100644
index 0000000..a18dfde
--- /dev/null
+++ b/kmymoney2/html/kmymoney2.css
@@ -0,0 +1,370 @@
+
+@media screen {
+
+ A.el { text-decoration: none; }
+ A.elRef { font-weight: bold }
+ A.code { text-decoration: none; font-weight: normal; color: #4C59A6 }
+ A.codeRef { font-weight: normal; color: #4C59A6 }
+ A:hover { text-decoration: none; font-weight: normal; color: #4C59A6 }
+
+ body {
+ background-color: Window;
+ color:WindowText;
+ font-family: verdana, arial, sans-serif;
+ }
+
+ .setcolor { /*sets color of some spacing elements (such as the column between assets and liabilities) to the desired color*/
+ background-color:Window;
+}
+
+body#summaryview { /* set body attributes that affect only the summary view (and not reports) */
+ background: url(./images/bg-texture.png) repeat fixed;
+}
+
+
+#vieweffect { /* creates a dropshadow at the top of the view creating a resessed effect */
+ background: url(./images/top-shadow.png) repeat-x top;
+ margin:0px -10px 0px -10px;
+ position:fixed;
+ top:-5px;
+ width:100%;
+ height:20px;
+ z-index:50;
+}
+
+ #summarytitle { /* "your financial summary" title on summary page */
+ display:block;
+ margin-bottom:6px;
+ text-align: right;
+ color:WindowText;
+ Font-size:20px;
+ padding:10px 15px 15px 0;
+ }
+
+ .shadow {/*wraps .displayblock -can be used for special decorative effects like a drop shadow */
+ background: url(./images/shadow.png) no-repeat bottom right;
+ margin:0px 5px 30px 15px;
+ }
+
+ .displayblock {/*ties together a summary header and a table into a single content block*/
+ display:block;
+ position:relative;
+ top:-6px;
+ left:-6px;
+ background-color: Window;
+ border-right: 1px solid gray;
+ border-bottom: 1px solid gray;
+ border-left: 1px solid lightgrey;
+/*border:1px solid WindowText;*/
+ padding: 0px;
+ }
+
+ .summaryheader { /*section labels over each table in the financial summary*/
+ background: HighLight url(./images/currencyflourish.png) no-repeat bottom right;
+ color:HighLightText;
+ Font-size:1.2em;
+ font-weight:bold;
+ padding:5px 10px;
+ }
+
+ .summarytable { /*the tables in the financial summary */
+ padding:5px;
+ }
+
+ .summarytable td { /*style <td> in the tables in the financial summary */
+ padding:5px 10px;
+ border-left: medium solid Window;
+ border-right: medium solid window;
+ color:WindowText;
+ }
+
+ .itemtitle { /*<tr> -additional label for table headers. example "Assets" and "Liabilities"*/
+ color:HighLight;
+ Font-weight:bold;
+ }
+
+ .itemtitle td { /*<td> table data cells related to .itemtitle*/
+ padding:0px 10px 0px 10px;
+ border-left: 0px;
+ border-right: 0px;
+ font-size:1.2em;
+ }
+
+ .item { /*<tr> -item labels (table headers) for sections in the financial summary */
+ font-weight:bold;
+ color:WindowText;
+ }
+
+ .item td { /*<td> table data cells related to .item*/
+ border-left: 0px;
+ border-right: 0px;
+ border-bottom:3px solid WindowText;
+ }
+
+ .warningtitle { /*<tr> -set warning background color -overdue payments -items of this class also belong to the class called "itemtitle"*/
+ color:red;/*set programatically, not by css*/
+ background-color: infobackground;
+ }
+
+ .warning { /*<tr> -set warning background color -items of this class also belong to the class called "item"*/
+ background-color: infobackground;
+ }
+
+ th.left, td.left {/*rule to align table header and table data cells*/
+ text-align: left;
+ }
+
+ th.right, td.right {/*rule to align table header and table data cells*/
+ text-align: right;
+ }
+
+ th.center, td.center {/*rule to align table header and table data cells*/
+ text-align: center;
+ }
+
+ .gap { /* used for spacing in financial summary and reports if needed -match to background color of body if you don't want it to show.*/
+
+ }
+
+/***********************************************************/
+/* These affect only the reports found in the reports view */
+
+ h2.report { /* header -title on report pages */
+ font-size: 18px;
+ font-family: verdana, arial, sans-serif;
+ margin-right: 10px;
+ margin-left: 10px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ text-align: center;
+ color:WindowText;
+ }
+
+ .itemheader { /*column labels in reports */
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-weight: bold;
+ background-color: Window;
+ color: WindowText;
+ padding-top: 5px;
+ padding-left: 20px;
+ padding-bottom: 5px;
+ }
+
+ div.subtitle { /*subtitle of each report page*/
+ text-align: center;
+ color:WindowText;
+ }
+
+ table.report {/*center the report*/
+ margin-left:auto;
+ margin-right:auto;
+ }
+
+ table.report th {/*styles table header cells*/
+ padding: 0.5em 0.5em;
+ }
+
+ table.report td {/*styles table cells- but not background color*/
+ font-size: 9pt;
+ padding: 0 0.5em;
+ text-align: right;
+ }
+
+ table.report td.leftborder {/*does not appear to be in use*/
+ border-left: 1px solid;
+ }
+
+ table.report td.left {/*far left column*/
+ text-align: left;
+ }
+
+ table.report td.left0 {/*does not appear to be in use*/
+ text-align: left;
+ }
+
+ table.report td.left1 {/*does not appear to be in use*/
+ text-align: left;
+ text-indent: 1.0em;
+ }
+
+ table.report td.left2 {/*does not appear to be in use*/
+ text-align: left;
+ text-indent: 2.0em;
+ }
+
+ table.report tr#subtotal td {/*line separating row groups*/
+ border-bottom: 1px solid black;
+ font-weight: normal;
+ }
+
+table.report tr#solo td {/*line separating rows that are not groups*/
+ border-bottom: 1px solid black;
+ font-weight: normal;
+ }
+
+table.report tr#topparent td.left {/*parent label for each row group containing children*/
+ font-weight: bold;
+ }
+
+ table.report tr#solo td.left {/*label for each row group _not_ containing children*/
+ font-weight: bold;
+ }
+
+ table.report tr.sectionheader td { /* label (title) of each section -subtotals -for example 'Income' and 'Expenses' */
+ font-weight: bold;
+ padding: 0.5em 0.5em 0 0.5em;
+ color:WindowText;
+ }
+
+ table.report tr.sectionfooter td { /* totals for each section -subtotals */
+ border-top: 1px solid black;
+ padding: 0 0.5em 0.5em 0.5em;
+ color:WindowText;
+ }
+
+ table.report tr.reportfooter td { /* "Grand Total" totals" */
+ border-bottom: 1px solid black;
+ border-top: 1px solid black;
+ padding: 0 0.5em 0 0.5em;
+ color:WindowText;
+ }
+
+ table.report tr.reportfooter td.left { /* "Grand Total" label in the left column */
+ font-weight: bold;
+ color:WindowText;
+ }
+
+ table.report tr.spacer td {/*used to make a table row act as a spacer when needed*/
+ font-size: 4pt;
+ padding: 1em 0;
+ }
+}
+
+@media print {
+
+ body { background: white; margin: 0; padding: 0 }
+ body { font-family: helvetica, arial; font-size: 10pt }
+ td,th { font-family: helvetica, arial; font-size: 9pt }
+
+ thead { display: table-header-group }
+ tbody { display: table-row-group }
+ tfoot { display: table-footer-group }
+ tr { page-break-inside: avoid }
+
+ div.gap { display: none }
+ .spacer { display: none }
+
+ h2.report,
+ div.subtitle { margin: 6pt; padding: 0; text-align: center }
+ div.subtitle { margin-bottom: 18pt }
+
+ table { border-collapse: separate; border-spacing: 1px; }
+ table { margin-left: auto; margin-right: auto }
+ td { vertical-align: baseline }
+
+ table.report {/*center the report*/
+ margin-left:auto;
+ margin-right:auto;
+ }
+
+ table.report th {/*styles table header cells*/
+ padding: 0.5em 0.5em;
+ }
+
+ table.report td {/*styles table cells- but not background color*/
+ text-align: right;
+ }
+ table.report td.left {/*far left column*/
+ text-align: left;
+ }
+
+ table.report td.left0 {/*does not appear to be in use*/
+ text-align: left;
+ }
+
+ table.report td.left1 {/*does not appear to be in use*/
+ text-align: left;
+ text-indent: 1.0em;
+ }
+
+ table.report td.left2 {/*does not appear to be in use*/
+ text-align: left;
+ text-indent: 2.0em;
+ }
+
+ table.report tr#subtotal td {/*line separating row groups*/
+ border-bottom: 1px solid black;
+ font-weight: normal;
+ }
+
+table.report tr#solo td {/*line separating rows that are not groups*/
+ border-bottom: 1px solid black;
+ font-weight: normal;
+ }
+
+table.report tr#topparent td.left {/*parent label for each row group containing children*/
+ font-weight: bold;
+ }
+
+ table.report tr#solo td.left {/*label for each row group _not_ containing children*/
+ font-weight: bold;
+ }
+
+ th { border-bottom: 1pt solid black }
+/* th { background: #cccccc } */
+ tr.item0 td { background: #f2f2ff }
+ tr.item1 td { background: #f2fff2 }
+ tr.row-even td { background: #f2f2ff }
+ tr.row-odd td { background: #f2fff2 }
+
+ tr.item0 td,
+ tr.item1 td,
+ tr.itemA td,
+ tr.itemZ td { font-style: italic }
+
+ td.left0,
+ td.left1,
+ td.left2,
+ td.left { text-align: left }
+ td.center { text-align: center }
+ td.right { text-align: right }
+ td, th { padding: 2pt 4pt }
+
+ tr.sectionheader td.left,
+ tr.sectionfooter td.left,
+ tr.sectionheader td.left0,
+ tr.sectionfooter td.left0 {
+ padding-top: 12pt; font-size: 1.1em; font-weight: bold
+ }
+
+ tr.sectionheader td.left1,
+ tr.sectionfooter td.left1,
+ tr.sectionheader td.left2,
+ tr.sectionfooter td.left2 {
+ padding-top: 6pt; font-size: 0.9em; font-weight: bold
+ }
+
+ tr.reportfooter td.left {
+ padding-top: 12pt; font-size: 1.1em; font-weight: bold
+ }
+
+ #subtotal { font-style: italic }
+/* #topparent td, #solo td { border-top: 1px solid gray } */
+}
+
+tr.item0 td,tr.item1 td,tr.itemA td,tr.itemZ td {
+ font-style: italic;
+ }
+
+tr.itemA td {
+ border-bottom: 1px dotted gray;
+ }
+
+tr.itemZ td {
+ border-top: 1px dotted gray;
+ }
+
+.item0 .value,.item1 .value {
+ padding-right: 2em;
+ }
+
diff --git a/kmymoney2/html/welcome.css b/kmymoney2/html/welcome.css
new file mode 100644
index 0000000..aa0c7c4
--- /dev/null
+++ b/kmymoney2/html/welcome.css
@@ -0,0 +1,171 @@
+/*******************************************************************
+3/23/2005 KMyMoney Welcome Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+********************************************************************/
+
+
+body {
+ background-color: highlight;
+ margin-top:100px;
+ }
+
+
+#background_image {
+ z-index: -10;
+ position:absolute;
+ left:0px;
+ top:0px;
+ width:100%;
+ }
+
+
+#KMyMoneyLogo {
+ position:absolute;
+ top:12px;
+ left:25px;
+ z-index: 10;
+ }
+
+/*line of text under logo("Personal Finance Software")*/
+
+#tagline {
+ position:absolute;
+ top:55px;
+ left:25px;
+ font-family:bitstream vera sans, verdana, sans;
+ font-size:8px;
+ color: highlighttext;
+ }
+
+/*("Welcome to KMyMoney","What's New in...")*/
+
+#title {
+ font-family:bitstream vera sans, verdana, sans;
+ line-height:1em;
+ font-size: 20px;
+ position:absolute;
+ top:-3px;
+ right:25px;
+ color:highlighttext;
+ }
+
+#subtitle {
+ font-family:bitstream vera sans, verdana, sans;
+ line-height:1em;
+ font-size: 10px;
+ position:absolute;
+ top:30px;
+ right:25px;
+ color:highlighttext;
+ }
+
+
+/*link under title, "Goto My Financial Summary"etc.*/
+
+#summaryLink, #returnLink {
+ position:absolute;
+ top:75px;
+ left:6%;
+ color:highlighttext;
+ }
+
+
+#returnLink img {
+ vertical-align:middle;
+ position:relative;
+ margin-right: 5px;
+ top:-3px;
+ }
+
+
+#summaryLink a, #returnLink a {
+ color:highlighttext;
+ text-decoration:none;
+ }
+
+
+#summaryLink a:hover, #returnLink a:hover {
+ color:highlighttext;
+ text-decoration:underline;
+ }
+
+
+
+/*start content box frame*/
+
+#topleft {
+ background:
+url(./images/topleft.png) no-repeat left top;
+ width:87%;
+ margin-left:5%;
+ margin-right:5%;
+
+ }
+#topright {
+ background:url(./images/topright.png)
+ top right no-repeat;
+ position: relative;
+ right:-22px;
+ padding-top: 20px;
+ }
+
+#rightborder {
+ background: url(./images/rightborder.png)
+ top right repeat-y;
+ position: relative;
+ right:-22px;
+ padding-right: 22px;
+ margin-bottom: -91px;/*appears to adjust margin below content*/
+ }
+
+#bottomleft {
+ background:
+ url(./images/bottomleft.png)
+ bottom left no-repeat;
+ position: relative;
+ top: 91px;
+padding-top: 0px;
+
+ }
+
+#bottomright {
+ background: url(./images/bottomright.png)
+ bottom right no-repeat;
+ position: relative;
+ right:-22px;
+ padding-top: 91px;
+ }
+
+/* end content box frame */
+
+
+/* list of links on welcome page */
+
+#welcomeMenu ul {
+ list-style-type:none;
+ /*removes default bullets*/
+ }
+
+
+#welcomeMenu li {
+ margin-bottom: 10px;
+ /*adds space between lines*/ color: black;
+ }
+
+
+#welcomeMenu span:hover {
+ text-decoration:underline;
+ /*sets hover attributes*/
+ }
+
+/* replacement bullets */
+
+#welcomeMenu img {
+ vertical-align:middle;
+ position:relative;
+ margin-right: 5px;
+ top: -2px;
+ }
+
+ \ No newline at end of file
diff --git a/kmymoney2/html/whats_new.html b/kmymoney2/html/whats_new.html
new file mode 100644
index 0000000..4aa393c
--- /dev/null
+++ b/kmymoney2/html/whats_new.html
@@ -0,0 +1,97 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title">What's new in KMyMoney 1.0</h3>
+ <!--p id="tagline">Personal Finance Software</p-->
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Return to the Welcome page</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+
+
+<p>The KMyMoney development team is pleased to announce a major step forward for what has been described as "the BEST personal finance manager for FREE users". With over 3 years of development, this new stable release has a lot of new features and a refreshed user interface.</p>
+
+<h4>What's new since version 0.9.3:</h4>
+<ul>
+<li>A new look and feel, and a new set of icons</li>
+<li>Added investment price reports, investment moving average price</li>
+<li>Added GUI option for expert mode</li>
+<li>Improved scheduled occurrences support</li>
+<li>Improved support for CMake</li>
+<li>Improved text filter for transactions</li>
+<li>Improved charts look and feel</li>
+<li>Improved DB support and performance</li>
+<li>Improved QIF and OFX support</li>
+<li>Updated documentation</li>
+<li>Updated translations</li>
+<li>A lot of bug fixing and polishing rough edges to make this an outstanding release</li>
+</ul>
+
+<h4>What's new since version 0.8.9:</h4>
+<ul>
+<li>Home Page. Improved reports are available on the home page to give a quick glance on your financial situation</li>
+<li>Appearance. A refreshed home page and a new set of icons have been exclusively designed to celebrate the 1.0 release</li>
+<li>Budgets. A new budget feature allows you to specify your future expectations of income and expenditure, and then to compare your actual performance against these. You can use your historical data to have KMyMoney create a basic budget for you. Budget reports can be displayed as charts if desired. Monthly budget overruns can be displayed on your home page, but can be removed if you find it too depressing</li>
+<li>Forecasts. A forecast can be produced of the future balances of your critical accounts, based either on regular scheduled transactions or your historical data</li>
+<li>Reports. Forecast, Schedule Information, Account Information, Loan Information, Reconciliation, Cash Flow, Investment Price, and Investment Moving Average Price</li>
+<li>Charts. Many of the reports produced by KMyMoney may now be displayed in chart form. Line, bar, stacked bar, pie and ring charts are supported where appropriate</li>
+<li>Schedules. More flexible occurrence periods</li>
+<li>Importer. A totally re-written Quicken (QIF) file importer and an improved GnuCash file importer. Also added OFX support for money market accounts</li>
+<li>PGP encryption. Added support for more than one key</li>
+<li>Database. The optional use of a database for data storage is supported (MySQL, PostgreSQL and SQLite version 3 have been extensively tested)</li>
+<li>CMake. Added support for compilation and tests</li>
+<li>Translations. Added translations for Swedish, Simplified Chinese, Turkish, Romanian, and Finnish</li>
+</ul>
+
+<p>Many enhancements have been made to existing functionality, to improve your user experience. Among the foremost of these are the following:</p>
+
+<ul>
+<li>User interface. Several new options have been provided to enable you to configure KMyMoney to your personal requirements. Multiple user interface improvements</li>
+<li>Accounts. New 'wizards' have been produced to simplify the setting up of new accounts, and complicated situations such as loans and mortgages. One wizard in particular will guide first time users through the setting up of their new file, and template lists of frequently-used accounts and categories are supplied, often tailored to nationality. Defunct accounts may now be marked as closed, so that they no longer clutter up your screens, though they are still available for viewing if required. Allow creation of additional Equity accounts and editing of Equity transactions. Added hierarchy management to New Account wizard. Warning messages can be displayed if the balance on an account exceeds, or falls below, a given value</li>
+<li>Currencies. Added Euro support for Slovakia. Better support for multiple currencies</li>
+<li>Ledgers. The views of the various ledgers have been revamped to provide better performance, and more facilities for sorting and searching transactions, including a 'quick search' option. A new multiple transaction selection function will allow you to do some 'bulk' changing of transactions. A new, more comprehensive, transaction autofill facility, based on payee name, has been introduced</li>
+<li>Payees. Deletion of 'non-empty' payees and categories is now allowed, with the transactions being re-assigned as required</li>
+<li>Schedules. Changes have been made to simplify the entry and maintenance of your regular scheduled transactions. Allow direct editing and entering of schedules from Home page. Allow viewing and entering schedules on the Ledger View</li>
+<li>Reports. Improved text filter for transactions. Various fixes related to Loans, and Budget reports. Some new reports have been added, new levels of detail have been included, and many of them have also been made more configurable. There have also been a lot of fixes related to multi-currency reports. Improved calculation of returns and multiple currencies in investment reports</li>
+<li>Online update. If you use OFX or HBCI for online banking, your setup has been made easier, and a manual transaction matching facility should simplify reconciliation of your downloaded statements. There is support for new versions of AqBanking and libofx, providing more flexibility and reliability. Improved QIF and OFX support, with significant improvements to the OFX import process. Improvements and enhancements to matching and error handling, among others. Improved investment transaction and online update dialog</li>
+<li>Improved documentation and README files</li>
+<li>Updated translations for Spanish, Argentinian Spanish, Brazilian Portuguese, simplified Chinese, Czech, Dutch, French, Galician, German, Italian and Portuguese</li>
+<li>Lots of code cleanup</li>
+<li>A lot of bug fixing and polishing rough edges to make this an outstanding release</li>
+</ul>
+
+<p>Let us know what you think. We hope that you enjoy using this version of KMyMoney.</p> <p>Please let us know about any abnormal behavior in the program by selecting <a href="/action?id=help_report_bug">"Report bug..."</a> from the help menu or by sending an e-mail to the developers mailing list. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">The KMyMoney Development Team</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_de.html b/kmymoney2/html/whats_new_de.html
new file mode 100644
index 0000000..c8bfc88
--- /dev/null
+++ b/kmymoney2/html/whats_new_de.html
@@ -0,0 +1,97 @@
+<!--
+*****************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+Thomas Baumgart ipwizard<at>users.sourceforge.net
+*****************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Was ist neu in diesem Release</h3>
+ <!-- <p id="tagline">Pers&ouml;nliche Finanzmanagement Software</p> -->
+ <div id="returnLink"><a href="/welcome"><img src="images/backarrow.png">Zurück zur Startseite</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+
+
+<p>Das KMyMoney Entwicklerteam ist erfreut, einen Meilenstein in der Entwicklung des als "Bester persönlicher Finanzmanager für freie Benutzer" bezeichneten Programmes zu präsentieren. Nach 3 Jahren Entwicklungszeit hat diese Version viele neue Funktionen, eine überarbeitete Benutzerschnittstelle.</p>
+
+<h4>Was ist neu seit 0.9.3:</h4>
+<ul>
+<li>Neue Benutzerschnittstelle und neue Icons</li>
+<li>Neue Investmentberichte für Kurshistorie und investment moving average price</li>
+<li>GUI option für Experten Modus</li>
+<li>Überarbeitete Auswahl von Zahlungswiederholungen</li>
+<li>Überarbeitete Unterstützung von CMake</li>
+<li>Überarbeitete Buchungsfilter</li>
+<li>Überarbeitete Berichtsgrafiken</li>
+<li>Verbesserte und performantere Datenbank Unterstützung</li>
+<li>Verbesserte Unterstützung für QIF und OFX Import</li>
+<li>Aktualisierte Dokumentation</li>
+<li>Aktualisierte Übersetzungen</li>
+<li>Viele Fehlerkorrekturen und Verbesserungen um ein ultimatives Release zu präsentieren</li>
+</ul>
+
+<h4>Was ist neu seit 0.8.9:</h4>
+<ul>
+<li>Startseite. Improved reports are available on the home page to give a quick glance on your financial situation</li>
+<li>Appearance. A refreshed home page and a new set of icons have been exclusively designed to celebrate the 1.0 release</li>
+<li>Budgets. A new budget feature allows you to specify your future expectations of income and expenditure, and then to compare your actual performance against these. You can use your historical data to have KMyMoney create a basic budget for you. Budget reports can be displayed as charts if desired. Monthly budget overruns can be displayed on your home page, but can be removed if you find it too depressing</li>
+<li>Forecasts. A forecast can be produced of the future balances of your critical accounts, based either on regular scheduled transactions or your historical data</li>
+<li>Reports. Forecast, Schedule Information, Account Information, Loan Information, Reconciliation, Cash Flow, Investment Price, and Investment Moving Average Price</li>
+<li>Charts. Many of the reports produced by KMyMoney may now be displayed in chart form. Line, bar, stacked bar, pie and ring charts are supported where appropriate</li>
+<li>Schedules. More flexible occurrence periods</li>
+<li>Importer. A totally re-written Quicken (QIF) file importer and an improved GnuCash file importer. Also added OFX support for money market accounts</li>
+<li>PGP encryption. Added support for more than one key</li>
+<li>Database. The optional use of a database for data storage is supported (MySQL, PostgreSQL and SQLite version 3 have been extensively tested)</li>
+<li>CMake. Added support for compilation and tests</li>
+<li>Translations. Added translations for Swedish, Simplified Chinese, Turkish, Romanian, and Finnish</li>
+</ul>
+
+<p>Many enhancements have been made to existing functionality, to improve your user experience. Among the foremost of these are the following:</p>
+
+<ul>
+<li>User interface. Several new options have been provided to enable you to configure KMyMoney to your personal requirements. Multiple user interface improvements</li>
+<li>Accounts. New 'wizards' have been produced to simplify the setting up of new accounts, and complicated situations such as loans and mortgages. One wizard in particular will guide first time users through the setting up of their new file, and template lists of frequently-used accounts and categories are supplied, often tailored to nationality. Defunct accounts may now be marked as closed, so that they no longer clutter up your screens, though they are still available for viewing if required. Allow creation of additional Equity accounts and editing of Equity transactions. Added hierarchy management to New Account wizard. Warning messages can be displayed if the balance on an account exceeds, or falls below, a given value</li>
+<li>Currencies. Added Euro support for Slovakia. Better support for multiple currencies</li>
+<li>Ledgers. The views of the various ledgers have been revamped to provide better performance, and more facilities for sorting and searching transactions, including a 'quick search' option. A new multiple transaction selection function will allow you to do some 'bulk' changing of transactions. A new, more comprehensive, transaction autofill facility, based on payee name, has been introduced</li>
+<li>Payees. Deletion of 'non-empty' payees and categories is now allowed, with the transactions being re-assigned as required</li>
+<li>Schedules. Changes have been made to simplify the entry and maintenance of your regular scheduled transactions. Allow direct editing and entering of schedules from Home page. Allow viewing and entering schedules on the Ledger View</li>
+<li>Reports. Improved text filter for transactions. Various fixes related to Loans, and Budget reports. Some new reports have been added, new levels of detail have been included, and many of them have also been made more configurable. There have also been a lot of fixes related to multi-currency reports. Improved calculation of returns and multiple currencies in investment reports</li>
+<li>Online update. If you use OFX or HBCI for online banking, your setup has been made easier, and a manual transaction matching facility should simplify reconciliation of your downloaded statements. There is support for new versions of AqBanking and libofx, providing more flexibility and reliability. Improved QIF and OFX support, with significant improvements to the OFX import process. Improvements and enhancements to matching and error handling, among others. Improved investment transaction and online update dialog</li>
+<li>Improved documentation and README files</li>
+<li>Updated translations for Spanish, Argentinian Spanish, Brazilian Portuguese, simplified Chinese, Czech, Dutch, French, Galician, German, Italian and Portuguese</li>
+<li>Lots of code cleanup</li>
+<li>A lot of bug fixing and polishing rough edges to make this an outstanding release</li>
+</ul>
+
+<p>Let us know what you think. We hope that you enjoy using this version of KMyMoney.</p> <p>Please let us know about any abnormal behavior in the program by selecting <a href="/action?id=help_report_bug">"Report bug..."</a> from the help menu or by sending an e-mail to the developers mailing list. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">Das KMyMoney Entwickler Team</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_es.html b/kmymoney2/html/whats_new_es.html
new file mode 100644
index 0000000..0472fa9
--- /dev/null
+++ b/kmymoney2/html/whats_new_es.html
@@ -0,0 +1,99 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<!-- <img id="background_image" src="images/background.png" height="900 px"> -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Novedades en la versi&oacute;n 1.0</h3>
+ <!--p id="tagline">Software de Finanzas Personales</p -->
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Regresar a la p&aacute;gina de Bienvenida</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+
+<p>El equipo de desarrollo de KMyMoney est&aacute; encantado de anunciar un gran avance para lo que ha sido descripto como "el MEJOR gestor de finanzas personales para usuarios LIBRES". Con m&aacute;s de 3 a&ntilde;os de desarrollo, esta nueva versi&oacute;n estable tiene gran cantidad de nuevas caracter&iacute;sticas y una interfaz de usuario renovada.</p>
+
+<h4>Novedades desde la versi&oacute;n 0.9.3:</h4>
+<ul>
+<li>Una nueva apariencia y un nuevo conjunto de iconos</li>
+<li>Nuevos reportes de precio y precio m&oacute;vil de inversiones</li>
+<li>Nueva opci&oacute;n gr&aacute;fica para configurar el modo experto</li>
+<li>Mejoras en las ocurrencias de los asientos planificados</li>
+<li>Mejoras en el soporte de CMake</li>
+<li>Mejoras en el filtro de texto de asientos</li>
+<li>Mejoras en la apariencia de los gr&aacute;ficos</li>
+<li>Mejor soporte y desempe&ntilde;o de la base de datos</li>
+<li>Mejor soporte de QIF y OFX</li>
+<li>Documentaci&oacute;n actualizada</li>
+<li>Traducciones actualizadas</li>
+<li>Gran cantidad de arreglos y pulido general, para que esta sea una excelente versi&oacute;n</li>
+</ul>
+
+<h4>Novedades desde la versi&oacute;n 0.8.9:</h4>
+<ul>
+<li>P&aacute;gina de inicio. Mejores reportes disponibles al inicio para brindarle una mirada rapida de su situaci&oacute;n financiera</li>
+<li>Apariencia. Una p&aacute;gina de inicio renovada y un nuevo conjunto de iconos han sido dise&ntilde;ados exclusivamente para la versi&oacute;n 1.0</li>
+<li>Presupuestos. Una nueva opci&oacute;n de presupuesto permite especificar sus expectativas de ingresos y gastos y luego comparar su desempe&ntilde;o real contra &eacute;stas. Puede utilizar sus datos hist&oacute;ricos para que KMyMoney cree un presupuesto b&aacute;sico para usted. Los reportes de presupuesto incluyen gráficos. Los excedentes del presupuesto mensual pueden mostrarse en la p&aacute;gina de inicio, pero pueden ocultarse si no son de su agrado</li>
+<li>Pron&oacute;stico. Se puede realizar un pron&oacute;stico de los saldos de sus cuentas cr&iacute;ticas, basado en sus planificaciones o en sus datos hist&oacute;ricos</li>
+<li>Reportes. Pron&oacute;stico, Informaci&oacute;n de Planificaciones, Informaci&oacute;n de Cuentas, Reconciliaci&oacute;n, Flujo de Caja, Precio de Inversiones y Precio Promedio M&oacute;vil de Inversiones</li>
+<li>Gr&aacute;ficos. Muchos de los reportes producidos por KMyMoney ahora pueden ser mostrados en forma gr&aacute;fica. Se pueden utilizar barras, barras apiladas, tortas gr&aacute;ficos de anillo.</li>
+<li>Planificaciones. Periodos de ocurrencia m&aacute;s flexibles</li>
+<li>Importador. Se reescribi&oacute; totalmente el importador de archivos de Quicken (QIF) y se mejoroacute; el importador de archivos de GNUCash. Se agreg&oacute; soporte de OFX para cuentas del mercado de divisas.</li>
+<li>Codificaci&oacute;n PGP. Se agreg&oacute; soporte para m&aacute;s de una clave</li>
+<li>Base de datos. Se soporta el uso opcional de una base de datos para almacenamiento (se han probado MySQL, PostgreSQL y SQLite)</li>
+<li>CMake. Se agreg&oacute; soporte para compilaci&oacute;n y pruebas</li>
+<li>Traducciones. Se agregaron traducciones para sueco, chino simplificado, rumano y fin&eacute;s</li>
+</ul>
+
+<p>Se han hecho muchas mejoras a la funcionalidad existente, para mejorar la experiencia del usuario. De ellas, las m&aacute;s importante son las siguientes:</p>
+
+<ul>
+<li>Interfaz de usuario. Varias nuevas opciones para permitirle configurar KMyMoney seg&uacute;n sus necesidades. M&uacute;ltiples mejoras a la interaz de usuario</li>
+<li>Cuentas. Nuevos asistentes para simplificar la configuraci&oacute;n de nuevas cuentas y situaciones complejas como pr&eacute;stamos y prendas. Un asistente que gu&iacute;a a los nuevos usuarios a trav&eacute;s de la configuraci&oacute;n de un archivo nuevo y las plantillas de cuentas y categor&iacute;as m&aacute;s usadas, a menudo adecuadas por nacionalidad. Las cuentas obsoletas ahora pueden ser marcadas como cerradas, para liberar espacio en las pantallas, aunque todav&iacute;a se pueden ver si es requerido. Se pueden crear cuentas patrimoniales adicionales y editar asientos de patrimonio. El asistente de nueva cuenta ahora tiene configuraci&oacute;n de jerarqu&iacute;a. Mensajes de advertencia avisan cuando el saldo de una cuenta est&aacute; por fuera de los valores fijados</li>
+<li>Divisas. Se agreg&oacute; el Euro para Eslovaquia. Mejor soporte para m&uacute;ltiples divisas</li>
+<li>Libros mayores. Vistas renovadas para brindar mejor desempe&ntilde;o y m&aacute;s facilidades para ordenar y buscar asientos, incluyendo opciones de b&uacute;squeda r&aacute;pida. La selecci&oacute;n m&uacute;ltiple de asientos permite la modificaci&oacute;n masiva de asientos. Nueva facilidad de autocompletado de asientos a partir del nombre del beneficiario</li>
+<li>Beneficiarios. Borrar beneficiarios y categor&iacute;as ahora est&aacute; soportado, reasignando los asientos</li>
+<li>Planificaciones. Se simplific&oacute; el ingreso y mantenimiento de las planificaciones. Se pueden ingresar y editar las planificaciones desde la p&aacute;gina de inicio y desde los libros mayores</li>
+<li>Reportes. Filtro de texto de asientos mejorado. Varios arreglos relacionados a reportes de pr&eacute;stamo y presupuesto. Se agregaron nuevos reportes, nuevos niveles de detalle y mayores opciones de configuraci&oacute;n de los reportes. Muchos arreglos en los reportes multidivisas. Mejor c&aacute;lculo de retorno y divisas en los reportes de inversiones</li>
+<li>Actualizaci&oacute;n online. Para aquellos que utilizan OFX &oacute; HBCI para banca online, la configuraci&oacute;n es m&aacute;s f&aacute;cil y la funcionalidad de conciliaci&oacute;n manual simplifica la reconciliaci&oacute;n de los resumenes. Hay soporte para nuevas versiones de AqBanking y libofx, brindando m&aacute;s flexibilidad y confiabilidad. Soporte de OFX y QIF mejorado, con mejoras significativas al proceso de importaci&oacute;n de OFX. Mejoras y agregados a la conciliaci&oacute;n y el manejo de errores, entre otros. Mejores cuadros de di&aacute;logo para asientos de inversiones y actualizaci&oacute;n online</li>
+<li>Mejores archivos de documentaci&oacute;n y README</li>
+<li>Traducciones actualizadas para espa&ntilde;ol, espa&ntilde;ol argentina, portugu&eacute;s brasileroo, chino simplificado, checo, holand&eacute;s, franc&eacute;s, gallego, alem&aacute;n, italiano y portugu&eacute;s</li>
+<li>Mucha limpieza de c&oacute;digo</li>
+<li>Gran cantidad de arreglos y pulido general, para que esta sea una excelente versi&oacute;n</li>
+</ul>
+
+
+<p>H&aacute;ganos saber lo que opina. Esperamos que disfrute esta versi&oacute;n de KMyMoney.</p> <p>Por favor, h&aacute;ganos saber de cualquier comportamiento anormal en el programa, seleccionando <a href="/action?id=help_report_bug">"Reportar error..."</a> del men&uacute; de Ayuda, o enviando un correo a la lista de distribuci&oacute;n de los desarrolladores. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">El Equipo de Desarrollo de KMyMoney</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
+ \ No newline at end of file
diff --git a/kmymoney2/html/whats_new_fr.html b/kmymoney2/html/whats_new_fr.html
new file mode 100644
index 0000000..bd0f99a
--- /dev/null
+++ b/kmymoney2/html/whats_new_fr.html
@@ -0,0 +1,104 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<!-- <img id="background_image" src="images/background.png" height="900 px"> -->
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Nouveauts de cette version</h3>
+ <p id="tagline">Logiciel de comptabilit personnelle</p>
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Retour vers la page d'accueil</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+<p><b>Ceci est une version de dveloppement</b>, du coup certaines nouvelles fonctionalits peuvent ne pas tre pleinement fonctionnelles.
+De telles version sont aussi dcrites comme <em>'instables'</em>, il est du coup recommand de garder plusieurs sauvegardes de vos fichiers, y compris de celui en version 0.8. <br>Ceci tant dit, la plupart de dveloppeurs l'utilisent quotidiennement dj depuis bien longtemps!</p>
+
+
+<h4>Notes pour la version 0.9.2 : </h4>
+<ul>
+<LI>Amliorations des importations OFX et HBCI, qui incluent une correspondance automatique des oprations avec une gestion des erreurs, entre autres,</LI>
+<LI>Support de l'OFX pour les comptes boursiers,</LI>
+<LI>Support de plus d'une cl de criptage PGP,</LI>
+<LI>Nouveaux rapports : Prvisions, Oprations Futures, Information sur les Comptes, Factures et Rapprochement,</LI>
+<LI>Gestion de la hirarchie dans l'assistant "Nouveau Compte",</LI>
+<LI>Nouvelles traductions : sudois, chinois, turc et roumain,</LI>
+<LI>Un premier support de la compilation par CMake,</LI>
+
+<LI>Permettre la cration de nouveaux comptes d'actions et l'dition
+ des oprations sur les actions,</LI>
+<li>Permettre directement l'dition et la saisie des chances partir
+ de la page d'Accueil,</li>
+
+ <li>Permettre la saisie et l'dition des chances dans la vue Registre, </li>
+
+ <li>Amlioration de la page d'Accueil et ajout d'informations
+ au Rsum Financier et aux Paiements,</li>
+
+ <li>Amlioration du calcul des gains et sur les multiples monnaies dans
+ les rapports sur les investissements,</li>
+
+ <li>Amlioration des fentres de dialogues pour les oprations d'investissements
+ et la mise jour en ligne,</li>
+
+ <li>Amlioration de la mise en page de la vue Prvisions,</li>
+
+ <li>Amlioration de l'interface DB, qui est encore en phase de test,</li>
+
+ <li>Amlioration de la documentation et des fichiers README,</li>
+
+ <li>De nombreuses simplifications de code,</li>
+
+ <li>Mise jour des traductions : argentin, allemand, nerlandais,
+ portugais, brsilien, italien, franais, espagnol,</li>
+
+ <li>De nombreux bugs corrigs dans plusieurs domaines : catgories, recherche,
+ registre, rapports, navigation l'aide du clavier, calculatrice, budgets,
+ importation, chances, comptes, prts,</li>
+
+</ul>
+
+
+<p>
+Essayez les nouvelles fonctionnalits et faites-nous savoir ce que vous en pensez.
+Nous esprons que vous apprciez cette nouvelle version de KMyMoney.
+Bien que nous ayons fait de notre mieux pour supprimer les erreurs dans cette version, il
+se peut qu'il en reste.
+S'il vous plat, avertissez-nous de tout comportement anormal du programme en
+slectionnant <a href="/action?id=help_report_bug">"Rapporter un bug..."</a>
+dans le menu "Aide" ou en envoyant un mail la liste de diffusion des dveloppeurs :
+<font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+
+<p><div align="right">L'quipe de dveloppement de KMyMoney</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
+
+
+
diff --git a/kmymoney2/html/whats_new_gl.html b/kmymoney2/html/whats_new_gl.html
new file mode 100644
index 0000000..e0d7e61
--- /dev/null
+++ b/kmymoney2/html/whats_new_gl.html
@@ -0,0 +1,65 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<!-- <img id="background_image" src="images/background.png" height="900 px"> -->
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Novidades na versin 0.8</h3>
+ <p id="tagline">Software de Finanzas Persoais</p>
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Voltar pxina de benvida</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+<p>Estivo-se traballando moi duro para facer esta versin mellor e mais fcil de usar no dia a dia.
+Foron engadidas multiples caractersticas novas e fixeron-se abundantes melloras. Confiamos en que goste
+do resultado.</p>
+
+<p>Estas son algunhas das novas caractersticas desta versin:</p>
+
+<ul>
+<LI>Investimentos </LI>
+<LI>Informes </LI>
+<LI>Multiples divisas </LI>
+<LI>Conversor de arquivos GnuCash </LI>
+<LI>Importazn OFX </LI>
+<LI>Web Connect</LI>
+<LI>Aspeito mellorado -incluindo novas iconas.</LI>
+<LI>Cifrado dos Arquivos de Dados </LI>
+<LI>Calculadora para a introduzn de importes </LI>
+<LI>Cotizazns online de Aczns e Divisas </LI>
+<LI>Recursos para xestionar o IVE </LI>
+<LI>Permite escreber plugins de importazn </LI>
+<LI>Formato de Arquivo &quot;Annimo&quot; para facilitar a depurazn de erros </LI>
+</ul>
+<p>Prove as novas caractersticas e faga-nos chegar a sua opinin. Esperamos que desfrute usando esta nova versin de KMyMoney. Apesar de que fixemos o posbel para eliminar os erros que pudese haber nesta versin, seguramente quedan alguns. Por favor, faga-nos saber calquer comportamento anormal no programa mediante a opzn <a href="/action?id=help_report_bug">"Informar de erro..."</a> do menu axuda ou enviando un e-mail lista de correo dos desenvolventes. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">A Equipa de Desenvolvimento de KMyMoney</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_it.html b/kmymoney2/html/whats_new_it.html
new file mode 100644
index 0000000..5d03b11
--- /dev/null
+++ b/kmymoney2/html/whats_new_it.html
@@ -0,0 +1,97 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Documento senza titolo</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title">Novit di KMyMoney 1.0</h3>
+ <!--p id="tagline">Personal Finance Software</p-->
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Ritorna alla pagina di benvenuto</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+
+
+<p>Gli sviluppatori di KMyMoney ha il piacere di annunciare un passo importante verso ci che stato descritto come "il MIGLIORE gestore delle finanze personali per gli utenti LIBERI". Con oltre 3 anni di sviluppo, questa nuova versione ha numerose nuove funzionalit e un'interfaccia utente aggiornata.</p>
+
+<h4>Novit rispetto alla versione 0.9.3:</h4>
+<ul>
+<li>Un nuovo aspetto, con nuove icone</li>
+<li>Aggiunti i report dei prezzi d'investimento e della media mobile del prezzo d'investimento</li>
+<li>Aggiunta un'opzione all'interfaccia grafica per la modalit esperta</li>
+<li>Migliorato il supporto alle ricorrenze pianificate</li>
+<li>Migliorato il supporto a CMake</li>
+<li>Migliorato il filtro di testo per le transazioni</li>
+<li>Migliorato l'aspetto dei grafici</li>
+<li>Migliorato il supporto di database e prestazioni</li>
+<li>Migliorato il supporto QIF e OFX</li>
+<li>Documentazione aggiornata</li>
+<li>Traduzioni aggiornate</li>
+<li>Numerosi bug corretti ed eliminate alcune imprecisioni per regalarvi una versione eccezionale</li>
+</ul>
+
+<h4>Novit rispetto alla versione 0.8.9:</h4>
+<ul>
+<li>Pagina principale. Report migliorati sono disponibili nella pagina principale per fornire una rapida panoramica della situazione finanziaria</li>
+<li>Aspetto. Una pagina principale aggiornata e nuove icone disegnate esclusivamente per celebrare il rilascio della 1.0</li>
+<li>Budget. Una nuova funzionalit di budget consente di specificare le aspettative future di entrate e uscite, per poi confrontare i risultati attuali con tali previsioni. KMyMoney pu utilizzare i dati storici per generare un budget base al posto vostro. I report di budget possono essere visualizzati come grafici se lo si desidera. Gli sforamenti mensili di budget possono essere visualizzati nella pagina principale, ma possono essere rimossi se ritenuti deprimenti</li>
+<li>Previsioni. Pu essere prodotta una previsione dei bilanci futuri dei conti critici, basata su transazioni regolarmente pianificate o su dati storici</li>
+<li>Report. Previsione, Informazioni sulla pianificazione, Informazioni sul conto, Informazioni sul prestito, Riconciliazione, Contante, Prezzo d'investimento e Media mobile del prezzo d'investimento</li>
+<li>Grafici. Molti dei report prodotti da KMyMoney ora possono essere rappresentati sotto forma di grafico. Linee, barre, barre sovrapposte, torte e grafici ad anelli sono supportati nei casi appropriati</li>
+<li>Pianificazioni. Periodi di ricorrenza pi flessibili</li>
+<li>Importatore. Un importatore di file Quicken (QIF) completamente riscritto e un importatore migliorato di file GnuCash. Aggiunto anche il supporto OFX per i conti di mercato monetario</li>
+<li>Cifratura PGP. Aggiunto il supporto per pi di una chiave</li>
+<li>Database. L'impiego facoltativo di un database per conservare i dati supportato (MySQL, PostgreSQL e SQLite versione 3 sono stati ampiamente testati)</li>
+<li>CMake. Aggiunto il supporto per compilazione e test</li>
+<li>Traduzioni. Aggiunte traduzioni per Svedese, Cinese semplificato, Turco, Rumeno e Finlandese</li>
+</ul>
+
+<p>Molte modifiche sono state apportate alle funzionalit esistenti, per accrescere il livello di esperienza dell'utente. Tra le principali sono le seguenti:</p>
+
+<ul>
+<li>Interfaccia utente. Sono state fornite numerose nuove opzioni per consentire una configurazione di KMyMoney a seconda delle proprie necessit. Diversi miglioramenti dell'interfaccia utente</li>
+<li>Conti. Sono state create nuove 'procedure guidate' per semplificare la configurazione di nuovi conti, e operazioni complesse quali prestiti e mutui. Una procedura guidata in particolare assister i novizi nell'impostazione del nuovo file, e sono forniti elenchi di modelli di conto utilizzati di frequente e categorie, spesso adattati alla nazionalit. I conti cessati ora possono essere marcati come chiusi, per mantenere uno schermo pi ordinato, anche se saranno ancora visualizzabili su richiesta. Consente la creazione di conti di capitale aggiuntivi e la modifica delle transazioni di capitale. Aggiunta una gestione gerarchica alla procedura di creazione di un nuovo conto. Messaggi di avviso possono essere visualizzati se il bilancio di un conto eccede, o scende al di sotto, di un determinato valore</li>
+<li>Valute. Aggiunto il supporto all'Euro per la Slovacchia. Supporto migliorato in caso di valute multiple</li>
+<li>Libri mastro. Le viste dei diversi libri mastro sono state ridisegnate per fornire prestazioni migliori, e altri strumenti di ordinamento e ricerca delle transazioni, inclusa un'opzione di 'ricerca rapida'. Una nuova funzione di selezione di transazioni multiple consentir di effettuare alcune modifiche 'in massa' delle transazioni. Un nuovo strumento, pi completo, di completamento automatico delle transazioni, basato sul nome del creditore, stato introdotto</li>
+<li>Creditori. L'eliminazione di creditori 'non-vuoti' e di categorie ora permessa, con il conseguente riassegnamento delle transazioni</li>
+<li>Pianificazioni. Modifiche sono state apportate per semplificare l'inserimento e la gestione delle transazioni regolarmente pianificate. Consente la modifica diretta e l'inserimento di pianificazioni dalla pagina principale. Consente la visualizzazione e l'inserimento di pianificazioni nella vista Libro mastro</li>
+<li>Report. Filtro di testo migliorato per le transazioni. Diverse correzioni relative ai report Prestiti e Budget. Sono stati aggiunti alcuni nuovi report, nuovi livelli di dettaglio sono stati inclusi, e molti di essi sono stati resi maggiormente configurabili. Molte correzioni sono state apportate ai report a valuta multipla. Migliorato il calcolo di rendimento e valute multiple nei report d'investimento</li>
+<li>Aggiornamento in linea. Se utilizzate OFX o HBCI per l'online banking, la configurazione stata semplificata, e uno strumento di verifica manuale delle transazioni dovrebbe semplificare la riconciliazione degli estratti conto scaricati. Introdotto il supporto per le nuove versioni di AqBanking e libofx, che forniscono maggiore flessibilit e affidabilit. Migliorato il supporto QIF e OFX, con aggiornamenti significativi del processo di importazione OFX. Tra gli altri miglioramenti, il rilevamento e la gestione degli errori. Transazioni d'investimento migliorare e finestra di dialogo per l'aggiornamento in linea</li>
+<li>Migliorata la documentazione e i file README</li>
+<li>Traduzioni aggiornate per Spagnolo, Spagnolo argentino, Portoghese brasiliano, Cinese semplificato, Ceco, Olandese, Francese, Galiziano, Tedesco, Italiano e Portoghese</li>
+<li>Pulizia del codice</li>
+<li>Numerosi bug corretti ed eliminate alcune imprecisioni per regalarvi una versione eccezionale</li>
+</ul>
+
+<p>Fateci sapere cosa ne pensate. Speriamo che questa nuova versione di KMyMoney sia di vostro gradimento.</p> <p>Vi preghiamo di segnalarci qualsiasi comportamento anomalo del programma selezionando "Segnala un bug..." dal menu Aiuto o inviando un'email alla lista di distribuzione degli sviluppatori. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">Gli sviluppatori di KMyMoney</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_nl.html b/kmymoney2/html/whats_new_nl.html
new file mode 100644
index 0000000..8701cba
--- /dev/null
+++ b/kmymoney2/html/whats_new_nl.html
@@ -0,0 +1,63 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<!-- <img id="background_image" src="images/background.png" height="900 px"> -->
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Wat is nieuwe in deze versie</h3>
+ <p id="tagline">Persoonlijke Financi&euml;le Software</p>
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Ga terug naar de startpagina</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+<p>Er is hard gewerkt om deze versie nog beter en makkelijker in het gebruik te maken. Er zijn vele nieuwe mogelijkheden en verbeteringen toegevoegd.
+Wij zijn er zeker van dat u blij zult zijn met deze nieuwe versie van KMyMoney.</p>
+
+<p>Een korte samenvatting van de nieuwe mogelijkheden in deze versie:</p>
+
+<ul>
+<LI>Investeringen </LI>
+<LI>Rapporten </LI>
+<LI>Gebruik van meerdere valuta </LI>
+<LI>GnuCash Bestands Converter </LI>
+<LI>OFX Importeer functie </LI>
+<LI>Internet Connectie </LI>
+<LI>Verbeterde look and feel -inclusief nieuwe iconen.</LI>
+<LI>Versleuteling van bestanden </LI>
+<LI>Rekenmachine widget bij het invoeren van getallen </LI>
+<LI>Online Koersen voor aandelen &amp; Valuta </LI>
+<LI>Ondersteuning voor BTW </LI>
+<LI>Mogelijkheid zelf importeer plugins te maken </LI>
+</ul>
+<p>Probeer de nieuwe mogelijkheden en laat ons weten wat u er van vindt. We hopen dat u veel plezier beleeft aan het gebruik van deze nieuwe versie van KMyMoney. Uiteraard hebben wij ons uiterste best gedaan alle fouten te vermijden in deze versie, het blijft echter mogelijk dat er toch iets niet goed gaat. Laat ons a.u.b. weten als er iets abnormaals gebeurt via <a href="/action?id=help_report_bug">"Bug rapporteren..."</a> in het help menu of door het zenden van een e-mail naar de ontwikkelaars via mailadres <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">Het KMyMoney Ontwikkel Team</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_pt_BR.html b/kmymoney2/html/whats_new_pt_BR.html
new file mode 100644
index 0000000..0ad86a4
--- /dev/null
+++ b/kmymoney2/html/whats_new_pt_BR.html
@@ -0,0 +1,98 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>O que h de novo</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title">O que h de novo no KMyMoney 1.0</h3>
+ <!--p id="tagline">Personal Finance Software</p-->
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Retornar Pgina Inicial</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+
+
+<p>A equipe de desenvolvimento do KMyMoney tem o prazor de anunciar um passo importante frente para o que tem sido descrito como "o MELHOR gerenciador de finanas pessoais para usurios LIVRES". Com mais de 3 anos de desenvolvimento, esta nova verso estvel possui diversos recursos novos e uma interface com o usurio renovada.</p>
+
+<h4>O que h de novo desde a verso 0.9.3:</h4>
+<ul>
+<li>Uma nova aparncia e um novo conjunto de cones</li>
+<li>Adicionado relatrios de cotao de investimentos e cotao mdia de investimentos</li>
+<li>Adicionado uma opo na interface para um modo avanado</li>
+<li>Melhorado o suporte a agendamentos</li>
+<li>Melhorado o suporte ao CMake</li>
+<li>Melhorado o filtro de texto para transaes</li>
+<li>Melhorada a aparncia dos grficos</li>
+<li>Melhorado o suporte e o desempenho ao acesso ao banco de dados</li>
+<li>Melhorado o suporte ao QIF e OFX</li>
+<li>Documentao atualizada</li>
+<li>Traduo atualizada</li>
+<li>Diversas correes de erros e polimento de arestas para tornar esta verso excelente</li>
+</ul>
+
+<h4>O que h de novo desde a verso 0.8.9:</h4>
+
+<ul>
+<li>Pgina Inicial. Relatrios melhorados esto disponveis na pgina inicial para fornecer uma rpida viso de sua situao financeira</li>
+<li>Aparncia. Uma pgina inicial renovada e um novo conjunto de cones foi exclusivamente desenhado para celebrar a verso 1.0</li>
+<li>Oramentos. Um novo recuro de oramento permite que voc especifique suas expectativas para rendimentos e gastos, e ento comparar seu desempenho atual em relao a estas expectativas. Voc pode usar seus dados de histrico para fazer com que o KMyMoney crie um oramento bsico para voc. Os relatrios de oramentos podem ser exibidos em sua pgina inicial, mas podem ser removidos se voc ach-los muito deprimentes</li>
+<li>Estimativas. Uma estimativa pode ser produzida para balanos futuros de suas contas crticas, baseadas seja nas transaes normais agendadas, seja nos dados do seu histrico</li>
+<li>Relatrios, Estimativas, Informaes de Agendamento, Informaes de Conta, Informaes de Emprstimos, Reconciliao, Fluxo de Caixa, Cotao de Investimento, e Tendncia de Cotao Mdia de Investimento</li>
+<li>Grficos. Muitos dos relatrios produzidos pelo KMyMoney podem agora ser exibidos na forma de grficos. Grficos tipo linha, barra, barra empilhada, pizza e anis so suportados quando apropriados</li>
+<li>Agendamentos. Perodos de ocorrncia mais flexveis</li>
+<li>Importao. Um filtro de importao totalmente re-escrito para o Quicken (QIF) e um filtro de importao melhorado para o GnuCash. Foi tambm adicionado suporte ao OFX para contas do mercado de aes</li>
+<li>Criptografia PGP. Adicionado suporte para mais de uma chave</li>
+<li>Banco de dados. O uso otimizado de um banco de dados para armazenamento de daods suportado (MySQL, PostgreSQL e SQLite na verso 3 foram extensivamente testados)</li>
+<li>CMake. Adicionado suporte para compilao e testes</li>
+<li>Tradues. Adicionado tradues para o Sueco, Chins Simplificado, Turco, Romeno e Finlands</li>
+</ul>
+
+<p>Muitas melhorias foram feitas nas funcionalidades existentes, de modo a melhorar a experincia do usurio. Dentre elas, as mais destacadas so as seguintes:</p>
+
+<ul>
+<li>Interface com o usurio. Diversas novas opes foram fornecidas para possibilitar que voc configure o KMyMoney para as suas preferncias pessoais. Melhorias na interface para mltiplos usurios</li>
+<li>Contas. Novos 'assistentes' foram produzidos para simplificar a configurao de contas novas, e situaes complicadas como emprstimos e hipotecas. Um assistente em particular guiar os usurios iniciantes atravs do processo de configurao de um novo arquivo, com uma lista de modelos das contas mais frequentemente usadas juntamente com categorias, frequentemente adequadas ao pas do usurio. Contas mortas podem agora serem marcadas como fechadas, de modo que elas no poluam mais sua tela, apesar de permanecerem disponveis para consulta caso necessrio. Permite a criao de contas de Participao nos Lucros adicionais e editar as transaes nesta conta. Adicionado o gerenciamento da hierarquia para o assistente de Nova Conta. Mensagens de alerta podem ser exibidas se o balano de uma conta exceder, ou ficar abaixo de um determinado valor</li>
+<li>Moedas. Adicionado o suporte ao Euro para a Eslovquia. Melhor suporte para mltiplas moedas</li>
+<li>Livros de registro. As vises dos diversos livros foram reformadas para fornecer melhor desempenho e mais facilidades para ordenao e busca de transaes, incluindo uma opo de 'busca rpida'. Uma nova funo de seleo mltipla de transaes permitir que voc realize algumas mudanas em 'lote' das transaes. Um novo e mais abrangente recurso de autocompletamento de transaes, baseado no nome do beneficirio, foi introduzido</li>
+<li>Beneficirios. Excluso de beneficirios e categorias 'no-vazias' no permitida, com as transaes sendo re-atribudas quando necessrio</li>
+<li>Agendamentos. Mudanas foram feitas para simplificar a entrada e manuteno de suas transaes agendadas regulares. Permite a edio direta e insero de agendamentos a partir da Pgina Inicial. Permite a visualizao e insero de agendamentos a partir da Viso do Livro de Registro</li>
+<li>Relatrios. Filtro de texto para transaes melhorado. Vrias correes relacionadas a Emprstimos e relatrios de Oramento. Alguns novos relatrios foram adicionados, novos nveis de detalhes foram includos e muitos deles tambm se tornaram mais personalizveis. Existem tambm diversas correes relacionadas com relatrios em mltiplas moedas. Melhorado o clculo do retorno em mltiplas moedas nos relatrios de investimentos</li>
+<li>Atualizao Online. Se voc usa o OFX ou o HBCI para banco online, sua configura~ao foi facilitada, e o recurso de correspondncia manual de transao deve simplificar a reconciliao dos extratos baixados. Melhoria do suporte ao QIF e OFX support, com melhorias significativas do processo de importao do OFX. Melhorias e novos recursos para correspondncia e manipulao de erros, dentre outros. Melhoria na janela de atualizao online de transaes de investimento</li>
+<li>Melhoria na documentao e no arquivo README</li>
+<li>Atualizao das tradues para o Espanhol, Espanhol da Argentina, Portugus do Brasil, Chins Simplificado, Tcheco, Holands, Francs, Galego, Alemo, Italiano e Portugus</li>
+<li>Limpeza do cdigo</li>
+<li>Diversas correes de erros e polimento de arestas para tornar esta verso excelente</li>
+</ul>
+
+<p>Diga-no o que voc acha. Ns esperamos que voc aprecie esta verso do KMyMoney.</p> <p>Por favor, informe-nos sobre qualquer comportamento anormal no programa selecionando a opo <a href="/action?id=help_report_bug">"Relatar falha..."</a> do menu de ajuda ou enviando um e-mail para a lista de correio dos desenvolvedores. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">A Equipe de Desenvolvimento do KMyMoney</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html> \ No newline at end of file
diff --git a/kmymoney2/html/whats_new_ro.html b/kmymoney2/html/whats_new_ro.html
new file mode 100644
index 0000000..61ecb0b
--- /dev/null
+++ b/kmymoney2/html/whats_new_ro.html
@@ -0,0 +1,97 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Ce este nou în această versiune</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="100%">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title">Ce este nou în KMyMoney 1.0</h3>
+ <!--p id="tagline">Personal Finance Software</p-->
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Întoarcere la pagina de bun venit</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+
+
+<p>Echipa de dezvoltare KMyMoney are plăcerea să anunţe un pas înainte important spre ceea ce a fost descris ca "CEA MAI BUNĂ aplicaţie de finanţe personale pentru utilizatorii de SOFTWARE LIBER". Cu peste 3 ani de dezvoltare, această nouă versiune stabilă are o mulţime de caracteristici noi, precum şi o interfaţă de utilizator reîmprospãtatã.</p>
+
+<h4>Noutăţi faţă de versiunea 0.9.3:</h4>
+<ul>
+<li>Un aspect şi un set de pictograme nou</li>
+<li>S-a adăugat un raport pentru cotaţiile investiţiilor cu posibilitatea vizualizării mediei mobile a cotaţiilor</li>
+<li>S-a adăugat o opţiune în interfaţă pentru a activa modul expert</li>
+<li>S-au îmbunătăţit variantele de perioade de recurenţă a plăţilor programate</li>
+<li>S-a îmbunătăţit compilarea cu CMake</li>
+<li>S-a îmbunătăţit filtrarea după text a tranzacţiilor</li>
+<li>S-a îmbunătăţit aspectul graficelor</li>
+<li>S-a îmbunătăţit performanţa în cazul folosirii unei baze de date</li>
+<li>S-a îmbunătăţit procesarea fişierelor în formatele de date QIF şi OFX</li>
+<li>S-a actualizat documentaţia (în engleză)</li>
+<li>S-au actualizat traducerile</li>
+<li>Au fost corectate multe probleme ceea ce face din această versiune una remarcabilă</li>
+</ul>
+
+<h4>Noutăţi faţă de versiunea 0.8.9:</h4>
+<ul>
+<li>Pagina de start: Sunt disponibile rapoarte îmbunătăţite pentru a vă oferi o prezentare rapidă a situaţiei financiare</li>
+<li>Aspectul: O nouă înfăţişare a paginii de start şi un nou set de pictograme au fost concepute exclusiv pentru a celebra versiunea 1.0</li>
+<li>Bugete. A fost adăugată o nouă funcţionalitate care vă permite să specificaţi aşteptările dumneavoastră viitoare de venituri şi cheltuieli, şi apoi să comparaţi performanţa reală a dumneavoastră faţă de acestea. Puteţi utiliza datele istorice din KMyMoney pentru a vă crea un buget de bază. Rapoartele despre buget pot fi afişate ca grafice, dacă doriţi. Depăşirile lunare de buget pot fi afişate pe pagina de start, dar pot fi eliminate dacă vi se par prea deprimante</li>
+<li>Estimări. O estimare poate fi produsă pentru soldurile conturilor dumneavoastră critice, aceasta poate fi bazată fie pe tranzacţiile programate fie pe date istorice</li>
+<li>Rapoarte. Bugete, Programări, Conturi, Împrumuturi, Reconciliere, Flux financiar, Cotaţii investiţii şi Media mobilă a cotaţiilor investiţiilor</li>
+<li>Grafice. Multe din rapoartele prezentate de către KMyMoney pot fi acum afişate în formă grafică. Grafice de tip linie, bară, bare aranjate, circular şi inel sunt acceptate, dacă este cazul</li>
+<li>Tranzacţii programate. S-au introdus perioade de recurenţă a plăţilor programate mai flexibile</li>
+<li>Import de date. Un modul de import Quicken (QIF) total rescris şi o mai bună tratare a importului de date din GnuCash. De asemenea, s-a adăugat suport OFX pentru conturile de pe piaţa monetară</li>
+<li>Cripatre PGP. Posibilitatea criptării cu mai multe chei</li>
+<li>Baza de date. Utilizarea opţională a unei baze de date pentru stocarea datelor (MySQL, PostgreSQL şi SQLite versiunea 3 au fost testate pe scară largă)</li>
+<li>CMake. Compilarea şi rularea testelor</li>
+<li>Tranduceri. S-au adăugat tracuceri în suedeză, chineză simplificată, turcă, română şi finlandeză</li>
+</ul>
+
+<p>S-au făcut multe îmbunătăţiri la funcţionalitatea existentă, pentru a îmbunătăţi satisfacţia utilizatorului. Printre cele mai semnificative dintre acestea sunt următoarele:</p>
+
+<ul>
+<li>Interfaţa cu utilizatorul. Au fost adăugate mai multe opţiuni noi pentru a vă permite să configuraţi KMyMoney conform cerinţelor dumneavoastră. S-au adus îmbunătăţiri multiple la interfaţa cu utilizatorul</li>
+<li>Conturi. Au fost adăugate "Experţi" pentru a simplifica crearea de conturi noi, şi situaţii complicate, cum ar fi împrumuturi şi credite ipotecare. Un expert de prima pornire va îndruma utilizatorii pentru prima dată prin creearea unui fişier nou, precum şi a conturilor şi categoriilor utilizate frecvent pentru care sunt furnizate şabloane, de multe ori adaptate la cetăţenie. Conturi nefolosite pot fi acum marcate ca fiind închise, astfel încât acestea să nu mai apară în ecrane, totuşi acestea vor fi disponibile pentru vizualizare, dacă este necesar. Se permite crearea de conturi de capital şi editarea tranzacţiilor de capital . S-a adăugat gestionarea ierarhiei din expertul de creeare a unui cont nou. Pot fi afişate mesaje de avertizare în cazul în care soldul unui cont este sub, depăşeşte sau are o anumită valoare</li>
+<li>Monede. S-a adăgat moneda Euro pentru Slovacia. S-a îmbunătăţit modul de lucru cu mai multe monede</li>
+<li>Registre. Modurile de vizualizare ale diferitelor registre au fost renovate pentru a oferi o performanţă mai bună, şi mai multe facilităţi pentru sortarea şi căutarea tranzacţiilor, inclusiv o funcţionalitate de "căutare rapidă". Un nouă functionalitate ce permite alegerea a mai multe tranzactii vă va permite efectuarea unor operaţii de modificare a tranzacţiilor în grup. O nouă, mai cuprinzătoare, funcţionalitate de completare automată a tranzacţiei, bazat pe numele beneficiarului, a fost introdusă</li>
+<li>Beneficiari/Plătitori. Ştergerea beneficiarilor şi categoriilor care mai sunt referite în tranzacţii acum este permisă, iar tranzacţiile afectate sunt reasignate corespunzător</li>
+<li>Tranzacţii programate. Au fost făcute modificări pentru a simplifica introducerea şi întreţinerea a tranzacţiilor programate. Se permite modificarea directă şi introducerea tranzacţiilor programate din prima pagină. Se permite vizualizarea şi introducerea a tranzacţiilor programate din registre</li>
+<li>Rapoarte. S-a îmbunătăţit filtrul text a tranzacţiilor. Diverse erori legate de rapoarte de împrumuturi şi bugete au fost corectate. S-au adăugat rapoarte noi, au fost incluse niveluri noi de detaliu şi multe rapoarte s-au făcut mai configurabile. Au fost, de asemenea, o mulţime de remedieri legate de rapoartele multi-valută. S-a îmbunătăţit calcularea câştigurilor în rapoartele de investiţii</li>
+<li>Actualizare on-line. Dacă utilizaţi OFX sau HBCI pentru online banking, configurarea a fost făcută mai uşoară, şi o funcţionalitate de potrivire manuală a tranzacţiei ar trebui să simplifice reconcilierea extraselor de cont descărcate. Aplicaţia este compatibilă cu noile versiuni ale AqBanking şi libofx, oferind o mai mare flexibilitate şi fiabilitate. S-a îmbunătăţit importul datelor în format QIF şi OFX, cu îmbunătăţiri semnificative în procesul de import OFX. Îmbunătăţirile ale operaţiei de portivire a tranzacţiilor şi tratarea erorilor, printre altele. A fost îmbunătăţit dialogul de investiţii şi de actualizare a tranzacţiilor online</li>
+<li>S-a îmbunătăţit documentaţia (în engleză) şi fişierele README</li>
+<li>S-au actualizat traducerile în spaniolă, spaniola argentiniană, portugheza braziliană, chineza simplificată, cehă, olandeză, franceză, galiţiană, germană, italiană şi portugheză</li>
+<li>S-a îmbunătăţit codul sursă</li>
+<li>Au fost corectate multe probleme ceea ce face din această versiune una remarcabilă</li>
+</ul>
+
+<p>Spuneţi-ne părerea dumneavoastră. Sperăm că vă va face plăcere folosirea acestei versiuni a aplicaţiei KMyMoney.</p>Vă rugăm să ne aduceţi la cunoştintă orice comportament anormal folosind <a href="/action?id=help_report_bug">"Raportează o eroare..."</a> din meniul de ajutor sau trimiţând o scrisoare electronică la lista dezvoltatorilor aplicaţiei. <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p><div align="right">Echipa de dezvoltare KMyMoney</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_ru.html b/kmymoney2/html/whats_new_ru.html
new file mode 100644
index 0000000..c5afafb
--- /dev/null
+++ b/kmymoney2/html/whats_new_ru.html
@@ -0,0 +1,76 @@
+<!--
+***************************************************************************************
+16.03.2007 KMyMoney What's New Page on Russian
+Andrey Cherepanov sibskull<at>mail.ru
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<img id="background_image" src="images/background.png" height="900 px">
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Что нового в KMyMoney 1.0</h3>
+ <p id="tagline">Программа учёта финансов</p>
+ <div id="returnLink"><img src="images/backarrow.png"> <a href="/welcome">Страница приветствия</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+<p>Команда разработчиков KMyMoney делает большой шаг навстречу пользователям к своей цели — созданию <strong>лучшей программы управления персональными финансами для свободных людей</strong>. После трёх лет разработки новая стабильная версия имеет множество новых возможностей и новый интерфейс пользователя.</p>
+
+<h4>Новые возможности с версии 0.9.3</h4>
+<ul>
+<li>Новый интерфейс и новые значки</li>
+<li>Отчёты о стоимости ценных бумаг и динамике изменения этой стоимости</li>
+<li>Экспертный режим интерфейса</li>
+<li>Улучшенная поддержка периодических платежей</li>
+<li>Улучшенный фильтр по операциям</li>
+<li>Более приятный внешний вид диаграмм</li>
+<li>Улучшенная поддержка и производительность работы с базой данных</li>
+<li>Улучшенная поддержка QIF и OFX</li>
+<li>Обновления документации</li>
+<li>Обновление переводов</li>
+<li>Исправление множества ошибок</li>
+</ul>
+
+<h4>Новые возможности с версии 0.8.9</h4>
+<ul>
+<li>Множество новых отчётов в сводке</li>
+<li>Эксклюзивный набор значков и оформление к версии 1.0</li>
+<li>Поддержка бюджетов для планирования будущих доходов и затрат и сравнения с реальными данными. Бюджет может быть создан автоматически на основании данных прошлых периодов.</li>
+<li>Прогноз будущих остатков на счетах</li>
+<li>Новые отчёты: прогнозы, платежи, информация о счёте или кредите, сверка, денежный поток, стоимость ценных бумаг и график её изменения</li>
+<li>Диаграммы. Теперь множество отчётов могут быть показаны не только в табличной форме, но и в виде диаграммы.</li>
+<li>Полностью переделанный модуль импорта из файлов Quicken (QIF) и GnuCash. Добавлена поддержка формата OFX.</li>
+<li>Шифрование одним или несколькими ключами PGP</li>
+<li>Использование для хранения данных сервера баз данных (проверялось на MySQL, PostgreSQL и SQLite версии 3)</li>
+<li>Добавлены переводы интерфейса программы на шведский, упрощённый китайский, турецкий, румынский и финский языки</li>
+</ul>
+
+<p>Опробуйте новые возможности и дайте нам знать о вашем мнении по их поводу. Мы надеемся, что вы получите удовольствие от новой версии KMyMoney. Если же вы обнаружите ошибки при работе программы, используйте пункт «<a href="/action?id=help_report_bug">Сообщить об ошибке...</a>» в меню «Справка», или направьте письмо в наш список рассылки: <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font></p>
+<p>Перевод на русский: Николай Шафоростов и Андрей Черепанов. Замечания по переводу направляйте по адресу: <font color="blue"><a href="mailto:kde-russian@lists.kde.ru">kde-russian@lists.kde.ru</a></font></p>
+<p><div align="right" style="font-style: italic;">Команда разработчиков KMyMoney</div></p>
+
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/html/whats_new_tr.html b/kmymoney2/html/whats_new_tr.html
new file mode 100644
index 0000000..0ad00a0
--- /dev/null
+++ b/kmymoney2/html/whats_new_tr.html
@@ -0,0 +1,63 @@
+<!--
+***************************************************************************************
+3/23/2005 KMyMoney What's New Page
+Robert Wadley rob<at>robntina.fastmail.us
+David Wadley mail<at>davidwadley.com
+
+***************************************************************************************
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-9">
+<link href="welcome.css" rel="stylesheet" type="text/css">
+</head>
+
+<body>
+<!--"background_image", if enabled, displays an image in the background of this page.
+If you wish to use a background, un-comment the following line -->
+<!-- <img id="background_image" src="images/background.png" height="900 px"> -->
+<img id="KMyMoneyLogo" src="images/trans_logo.png">
+ <h3 id="title" style="font-size: 20px;">Srm 0.8 Yenilikleri</h3>
+ <p id="tagline">Kiisel Finans Uygulamas</p>
+ <div id="returnLink"><img src="images/backarrow.png"><a href="/welcome">Hogeldiniz Sayfasna Geri Dn</a></div>
+
+
+<div id="topleft">
+ <div id="topright"><img src="images/spacer.gif"></div>
+ <div id="rightborder"><table><tr><td>
+<!-- This is where the content should be put to show up inside the decorative frame-->
+<!-- Begin content -->
+<p>Bu srm daha iyi ve daha kolay kullanlabilir olmas iin ok sk alyoruz. Bu srme bir ok yeni zellik ve gelitirimeler ekledik. Kendimize gveniyoruz, grdnz bu yeni srmden holanacaksnz.</p>
+
+<p>Bu srmde bulabileceiniz yeni zellikler:</p>
+
+<ul>
+<LI>Yatrmlar </LI>
+<LI>Raporlar </LI>
+<LI>oklu Para Birimi </LI>
+<LI>GnuCash Dosya Dntrcs </LI>
+<LI>OFX eri Aktarcs </LI>
+<LI>Web Balants </LI>
+<LI>Gelitirilmi yeni grnm ve yeni simge seti </LI>
+<LI>Veri Dosyalar ifrelemesi </LI>
+<LI>Deerleri girerken alan hesap makinesi </LI>
+<LI>Stok &amp; Para Birimleri iin evrimii aktarm zellii </LI>
+<LI>VAT Destei </LI>
+<LI>eri aktarm eklentileri yazabilme zellii. </LI>
+<LI>Hata ayklamaya yardmc olan &quot;Anonim&quot; Dosya biemi </LI>
+</ul>
+<p>Ltfen yeni zellikleri deneyin ve ne dndnz bize bildirin. KMyMoney uygulamasnn bu yeni srmn kullanmaktan holanacanz umuyoruz. Bu srmde hatalar dzeltmek iin elimizden gelenin en iyisini yaptk ancak tabii ki tm hatalar yakalayamam olabiliriz. Ltfen <a href="/action?id=help_report_bug">"Hata raporlayn..."</a> balantsn kullanarak ya da gelitirici e-posta listesine <font color="blue"><a href="mailto:kmymoney2-developer@lists.sourceforge.net">kmymoney2-developer@lists.sourceforge.net</a></font> bir e-posta gndererek programn gstermi olduu anormal davranlar bildirin.</p>
+<p><div align="right">KMyMoney Gelitirme Ekibi</div></p>
+<!-- End content -->
+ </td></tr></table>
+ </div>
+ <div id="bottomleft"><div id="bottomright"></div>
+ </div>
+</div>
+<div style="margin-bottom: 65px"></div>
+</body>
+</html>
diff --git a/kmymoney2/icons/Makefile.am b/kmymoney2/icons/Makefile.am
new file mode 100644
index 0000000..2d9d0cd
--- /dev/null
+++ b/kmymoney2/icons/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = hicolor oxygen Tango
diff --git a/kmymoney2/icons/Tango/128x128/Makefile.am b/kmymoney2/icons/Tango/128x128/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/Tango/128x128/apps/Makefile.am b/kmymoney2/icons/Tango/128x128/apps/Makefile.am
new file mode 100644
index 0000000..15cef33
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/128x128/apps
+
+icon_DATA = account_add.png account.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png budget.png categories.png forcast.png institution_add.png institutions.png investments.png ledger.png onlinebanking.png payee.png reconcile.png report.png schedule.png transaction_find.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_asset.png b/kmymoney2/icons/Tango/128x128/apps/account-types_asset.png
new file mode 100644
index 0000000..1ccec0f
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_cash.png b/kmymoney2/icons/Tango/128x128/apps/account-types_cash.png
new file mode 100644
index 0000000..306ebd3
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_checking.png b/kmymoney2/icons/Tango/128x128/apps/account-types_checking.png
new file mode 100644
index 0000000..91923ec
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_closed.png b/kmymoney2/icons/Tango/128x128/apps/account-types_closed.png
new file mode 100644
index 0000000..e2d054f
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_credit-card.png b/kmymoney2/icons/Tango/128x128/apps/account-types_credit-card.png
new file mode 100644
index 0000000..46aba46
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_expense.png b/kmymoney2/icons/Tango/128x128/apps/account-types_expense.png
new file mode 100644
index 0000000..be964ba
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_income.png b/kmymoney2/icons/Tango/128x128/apps/account-types_income.png
new file mode 100644
index 0000000..e9b725f
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_investments.png b/kmymoney2/icons/Tango/128x128/apps/account-types_investments.png
new file mode 100644
index 0000000..fda644c
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_liability.png b/kmymoney2/icons/Tango/128x128/apps/account-types_liability.png
new file mode 100644
index 0000000..58e81b6
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_loan.png b/kmymoney2/icons/Tango/128x128/apps/account-types_loan.png
new file mode 100644
index 0000000..3526151
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account-types_savings.png b/kmymoney2/icons/Tango/128x128/apps/account-types_savings.png
new file mode 100644
index 0000000..2466abb
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account.png b/kmymoney2/icons/Tango/128x128/apps/account.png
new file mode 100644
index 0000000..539122b
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/account_add.png b/kmymoney2/icons/Tango/128x128/apps/account_add.png
new file mode 100644
index 0000000..15c314f
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/accounts.png b/kmymoney2/icons/Tango/128x128/apps/accounts.png
new file mode 100644
index 0000000..539122b
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/budget.png b/kmymoney2/icons/Tango/128x128/apps/budget.png
new file mode 100644
index 0000000..b693b1f
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/categories.png b/kmymoney2/icons/Tango/128x128/apps/categories.png
new file mode 100644
index 0000000..0c917ba
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/forcast.png b/kmymoney2/icons/Tango/128x128/apps/forcast.png
new file mode 100644
index 0000000..edcdd62
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/institution_add.png b/kmymoney2/icons/Tango/128x128/apps/institution_add.png
new file mode 100644
index 0000000..5aeef7a
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/institutions.png b/kmymoney2/icons/Tango/128x128/apps/institutions.png
new file mode 100644
index 0000000..b9b4565
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/investments.png b/kmymoney2/icons/Tango/128x128/apps/investments.png
new file mode 100644
index 0000000..e2b1e7c
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/ledger.png b/kmymoney2/icons/Tango/128x128/apps/ledger.png
new file mode 100644
index 0000000..7f413ac
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/onlinebanking.png b/kmymoney2/icons/Tango/128x128/apps/onlinebanking.png
new file mode 100644
index 0000000..3118fc7
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/payee.png b/kmymoney2/icons/Tango/128x128/apps/payee.png
new file mode 100644
index 0000000..f6eb0bf
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/reconcile.png b/kmymoney2/icons/Tango/128x128/apps/reconcile.png
new file mode 100644
index 0000000..8117c68
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/report.png b/kmymoney2/icons/Tango/128x128/apps/report.png
new file mode 100644
index 0000000..08aae7a
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/schedule.png b/kmymoney2/icons/Tango/128x128/apps/schedule.png
new file mode 100644
index 0000000..2d0176c
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/128x128/apps/transaction_find.png b/kmymoney2/icons/Tango/128x128/apps/transaction_find.png
new file mode 100644
index 0000000..0cbb968
--- /dev/null
+++ b/kmymoney2/icons/Tango/128x128/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/Makefile.am b/kmymoney2/icons/Tango/16x16/Makefile.am
new file mode 100644
index 0000000..2af9bf4
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = actions
diff --git a/kmymoney2/icons/Tango/16x16/actions/Makefile.am b/kmymoney2/icons/Tango/16x16/actions/Makefile.am
new file mode 100644
index 0000000..18bb033
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/16x16/actions
+
+icon_DATA = account_add.png account.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png backup.png bank.png budget.png categories.png close_window.png delete.png forcast.png hide_categories.png hide_reconciled.png institution_add.png institutions.png investments.png ledger.png onlinebanking.png payee.png personal_data.png reconcile.png report.png schedule.png split_transaction.png transaction_find.png view_info.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_asset.png b/kmymoney2/icons/Tango/16x16/actions/account-types_asset.png
new file mode 100644
index 0000000..30d60a4
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_cash.png b/kmymoney2/icons/Tango/16x16/actions/account-types_cash.png
new file mode 100644
index 0000000..7b3e7ed
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_checking.png b/kmymoney2/icons/Tango/16x16/actions/account-types_checking.png
new file mode 100644
index 0000000..93a0800
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_closed.png b/kmymoney2/icons/Tango/16x16/actions/account-types_closed.png
new file mode 100644
index 0000000..750867f
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_credit-card.png b/kmymoney2/icons/Tango/16x16/actions/account-types_credit-card.png
new file mode 100644
index 0000000..4cbb7ce
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_expense.png b/kmymoney2/icons/Tango/16x16/actions/account-types_expense.png
new file mode 100644
index 0000000..919b445
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_income.png b/kmymoney2/icons/Tango/16x16/actions/account-types_income.png
new file mode 100644
index 0000000..e1c57f6
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_investments.png b/kmymoney2/icons/Tango/16x16/actions/account-types_investments.png
new file mode 100644
index 0000000..d37dfec
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_liability.png b/kmymoney2/icons/Tango/16x16/actions/account-types_liability.png
new file mode 100644
index 0000000..2caca98
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_loan.png b/kmymoney2/icons/Tango/16x16/actions/account-types_loan.png
new file mode 100644
index 0000000..31b6e4d
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account-types_savings.png b/kmymoney2/icons/Tango/16x16/actions/account-types_savings.png
new file mode 100644
index 0000000..c9cea17
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account.png b/kmymoney2/icons/Tango/16x16/actions/account.png
new file mode 100644
index 0000000..6abefad
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/account_add.png b/kmymoney2/icons/Tango/16x16/actions/account_add.png
new file mode 100644
index 0000000..60f7c95
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/accounts.png b/kmymoney2/icons/Tango/16x16/actions/accounts.png
new file mode 100644
index 0000000..6abefad
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/backup.png b/kmymoney2/icons/Tango/16x16/actions/backup.png
new file mode 100644
index 0000000..8ab6b2a
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/backup.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/bank.png b/kmymoney2/icons/Tango/16x16/actions/bank.png
new file mode 100644
index 0000000..6abefad
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/bank.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/budget.png b/kmymoney2/icons/Tango/16x16/actions/budget.png
new file mode 100644
index 0000000..7c34fa9
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/budget.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/categories.png b/kmymoney2/icons/Tango/16x16/actions/categories.png
new file mode 100644
index 0000000..df5aef8
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/close_window.png b/kmymoney2/icons/Tango/16x16/actions/close_window.png
new file mode 100644
index 0000000..50003a4
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/close_window.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/delete.png b/kmymoney2/icons/Tango/16x16/actions/delete.png
new file mode 100644
index 0000000..a51e735
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/delete.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/forcast.png b/kmymoney2/icons/Tango/16x16/actions/forcast.png
new file mode 100644
index 0000000..2782f0d
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/hide_categories.png b/kmymoney2/icons/Tango/16x16/actions/hide_categories.png
new file mode 100644
index 0000000..0907303
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/hide_categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/hide_reconciled.png b/kmymoney2/icons/Tango/16x16/actions/hide_reconciled.png
new file mode 100644
index 0000000..385fb72
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/hide_reconciled.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/institution_add.png b/kmymoney2/icons/Tango/16x16/actions/institution_add.png
new file mode 100644
index 0000000..fac686d
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/institutions.png b/kmymoney2/icons/Tango/16x16/actions/institutions.png
new file mode 100644
index 0000000..b32b276
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/investments.png b/kmymoney2/icons/Tango/16x16/actions/investments.png
new file mode 100644
index 0000000..44f14de
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/ledger.png b/kmymoney2/icons/Tango/16x16/actions/ledger.png
new file mode 100644
index 0000000..6606bfa
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/onlinebanking.png b/kmymoney2/icons/Tango/16x16/actions/onlinebanking.png
new file mode 100644
index 0000000..be48459
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/payee.png b/kmymoney2/icons/Tango/16x16/actions/payee.png
new file mode 100644
index 0000000..24d6d2d
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/payee.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/personal_data.png b/kmymoney2/icons/Tango/16x16/actions/personal_data.png
new file mode 100644
index 0000000..da8ddd9
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/personal_data.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/reconcile.png b/kmymoney2/icons/Tango/16x16/actions/reconcile.png
new file mode 100644
index 0000000..70fd366
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/report.png b/kmymoney2/icons/Tango/16x16/actions/report.png
new file mode 100644
index 0000000..5288b75
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/report.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/schedule.png b/kmymoney2/icons/Tango/16x16/actions/schedule.png
new file mode 100644
index 0000000..ad4cd49
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/split_transaction.png b/kmymoney2/icons/Tango/16x16/actions/split_transaction.png
new file mode 100644
index 0000000..0602343
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/split_transaction.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/transaction_find.png b/kmymoney2/icons/Tango/16x16/actions/transaction_find.png
new file mode 100644
index 0000000..e3e5c66
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/16x16/actions/view_info.png b/kmymoney2/icons/Tango/16x16/actions/view_info.png
new file mode 100644
index 0000000..22b3e6e
--- /dev/null
+++ b/kmymoney2/icons/Tango/16x16/actions/view_info.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/Makefile.am b/kmymoney2/icons/Tango/22x22/Makefile.am
new file mode 100644
index 0000000..2af9bf4
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = actions
diff --git a/kmymoney2/icons/Tango/22x22/actions/Makefile.am b/kmymoney2/icons/Tango/22x22/actions/Makefile.am
new file mode 100644
index 0000000..006feff
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/22x22/actions
+
+icon_DATA = account_add.png account.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png attention.png backup.png bank.png budget.png categories.png close_window.png delete.png forcast.png hide_categories.png hide_reconciled.png institution_add.png institutions.png investments.png ledger.png onlinebanking.png payee.png personal_data.png reconcile.png report.png schedule.png transaction_find.png view_info.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_asset.png b/kmymoney2/icons/Tango/22x22/actions/account-types_asset.png
new file mode 100644
index 0000000..00c42d7
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_cash.png b/kmymoney2/icons/Tango/22x22/actions/account-types_cash.png
new file mode 100644
index 0000000..5e2f200
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_checking.png b/kmymoney2/icons/Tango/22x22/actions/account-types_checking.png
new file mode 100644
index 0000000..e4edf0d
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_closed.png b/kmymoney2/icons/Tango/22x22/actions/account-types_closed.png
new file mode 100644
index 0000000..6522b4d
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_credit-card.png b/kmymoney2/icons/Tango/22x22/actions/account-types_credit-card.png
new file mode 100644
index 0000000..eb6991e
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_expense.png b/kmymoney2/icons/Tango/22x22/actions/account-types_expense.png
new file mode 100644
index 0000000..c1eb600
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_income.png b/kmymoney2/icons/Tango/22x22/actions/account-types_income.png
new file mode 100644
index 0000000..2a8926a
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_investments.png b/kmymoney2/icons/Tango/22x22/actions/account-types_investments.png
new file mode 100644
index 0000000..f062668
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_liability.png b/kmymoney2/icons/Tango/22x22/actions/account-types_liability.png
new file mode 100644
index 0000000..7b520c5
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_loan.png b/kmymoney2/icons/Tango/22x22/actions/account-types_loan.png
new file mode 100644
index 0000000..ea41eee
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account-types_savings.png b/kmymoney2/icons/Tango/22x22/actions/account-types_savings.png
new file mode 100644
index 0000000..2a097d2
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account.png b/kmymoney2/icons/Tango/22x22/actions/account.png
new file mode 100644
index 0000000..57cc544
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/account_add.png b/kmymoney2/icons/Tango/22x22/actions/account_add.png
new file mode 100644
index 0000000..3d9c30c
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/accounts.png b/kmymoney2/icons/Tango/22x22/actions/accounts.png
new file mode 100644
index 0000000..57cc544
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/attention.png b/kmymoney2/icons/Tango/22x22/actions/attention.png
new file mode 100644
index 0000000..e118279
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/attention.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/backup.png b/kmymoney2/icons/Tango/22x22/actions/backup.png
new file mode 100644
index 0000000..688c0d7
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/backup.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/bank.png b/kmymoney2/icons/Tango/22x22/actions/bank.png
new file mode 100644
index 0000000..57cc544
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/bank.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/budget.png b/kmymoney2/icons/Tango/22x22/actions/budget.png
new file mode 100644
index 0000000..61fe40b
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/budget.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/categories.png b/kmymoney2/icons/Tango/22x22/actions/categories.png
new file mode 100644
index 0000000..292bde6
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/close_window.png b/kmymoney2/icons/Tango/22x22/actions/close_window.png
new file mode 100644
index 0000000..9108ee7
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/close_window.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/delete.png b/kmymoney2/icons/Tango/22x22/actions/delete.png
new file mode 100644
index 0000000..1fe162e
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/delete.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/forcast.png b/kmymoney2/icons/Tango/22x22/actions/forcast.png
new file mode 100644
index 0000000..1f27a83
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/hide_categories.png b/kmymoney2/icons/Tango/22x22/actions/hide_categories.png
new file mode 100644
index 0000000..e1bb722
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/hide_categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/hide_reconciled.png b/kmymoney2/icons/Tango/22x22/actions/hide_reconciled.png
new file mode 100644
index 0000000..4e59757
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/hide_reconciled.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/institution_add.png b/kmymoney2/icons/Tango/22x22/actions/institution_add.png
new file mode 100644
index 0000000..c8bc1ce
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/institutions.png b/kmymoney2/icons/Tango/22x22/actions/institutions.png
new file mode 100644
index 0000000..88132f3
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/investments.png b/kmymoney2/icons/Tango/22x22/actions/investments.png
new file mode 100644
index 0000000..3647471
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/ledger.png b/kmymoney2/icons/Tango/22x22/actions/ledger.png
new file mode 100644
index 0000000..de58168
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/onlinebanking.png b/kmymoney2/icons/Tango/22x22/actions/onlinebanking.png
new file mode 100644
index 0000000..d6eb180
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/payee.png b/kmymoney2/icons/Tango/22x22/actions/payee.png
new file mode 100644
index 0000000..28173b7
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/payee.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/personal_data.png b/kmymoney2/icons/Tango/22x22/actions/personal_data.png
new file mode 100644
index 0000000..96f7333
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/personal_data.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/reconcile.png b/kmymoney2/icons/Tango/22x22/actions/reconcile.png
new file mode 100644
index 0000000..1e1d0dd
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/report.png b/kmymoney2/icons/Tango/22x22/actions/report.png
new file mode 100644
index 0000000..f3fc218
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/report.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/schedule.png b/kmymoney2/icons/Tango/22x22/actions/schedule.png
new file mode 100644
index 0000000..0fc38fb
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/transaction_find.png b/kmymoney2/icons/Tango/22x22/actions/transaction_find.png
new file mode 100644
index 0000000..e74509e
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/22x22/actions/view_info.png b/kmymoney2/icons/Tango/22x22/actions/view_info.png
new file mode 100644
index 0000000..30835cb
--- /dev/null
+++ b/kmymoney2/icons/Tango/22x22/actions/view_info.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/Makefile.am b/kmymoney2/icons/Tango/32x32/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/Tango/32x32/apps/Makefile.am b/kmymoney2/icons/Tango/32x32/apps/Makefile.am
new file mode 100644
index 0000000..520b4eb
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/32x32/apps
+
+icon_DATA = account_add.png account.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png budget.png categories.png forcast.png institution_add.png institutions.png investments.png ledger.png onlinebanking.png payee.png reconcile.png report.png schedule.png transaction_find.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_asset.png b/kmymoney2/icons/Tango/32x32/apps/account-types_asset.png
new file mode 100644
index 0000000..43bbf76
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_cash.png b/kmymoney2/icons/Tango/32x32/apps/account-types_cash.png
new file mode 100644
index 0000000..25bdbde
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_checking.png b/kmymoney2/icons/Tango/32x32/apps/account-types_checking.png
new file mode 100644
index 0000000..85c2a61
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_closed.png b/kmymoney2/icons/Tango/32x32/apps/account-types_closed.png
new file mode 100644
index 0000000..f393974
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_credit-card.png b/kmymoney2/icons/Tango/32x32/apps/account-types_credit-card.png
new file mode 100644
index 0000000..114ccd9
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_expense.png b/kmymoney2/icons/Tango/32x32/apps/account-types_expense.png
new file mode 100644
index 0000000..cb8232c
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_income.png b/kmymoney2/icons/Tango/32x32/apps/account-types_income.png
new file mode 100644
index 0000000..cb9390d
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_investments.png b/kmymoney2/icons/Tango/32x32/apps/account-types_investments.png
new file mode 100644
index 0000000..1a0a2c4
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_liability.png b/kmymoney2/icons/Tango/32x32/apps/account-types_liability.png
new file mode 100644
index 0000000..c12fc50
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_loan.png b/kmymoney2/icons/Tango/32x32/apps/account-types_loan.png
new file mode 100644
index 0000000..ccc94d6
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account-types_savings.png b/kmymoney2/icons/Tango/32x32/apps/account-types_savings.png
new file mode 100644
index 0000000..1c5defb
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account.png b/kmymoney2/icons/Tango/32x32/apps/account.png
new file mode 100644
index 0000000..1aa6524
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/account_add.png b/kmymoney2/icons/Tango/32x32/apps/account_add.png
new file mode 100644
index 0000000..0843acb
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/accounts.png b/kmymoney2/icons/Tango/32x32/apps/accounts.png
new file mode 100644
index 0000000..1aa6524
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/budget.png b/kmymoney2/icons/Tango/32x32/apps/budget.png
new file mode 100644
index 0000000..3a9e1d1
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/categories.png b/kmymoney2/icons/Tango/32x32/apps/categories.png
new file mode 100644
index 0000000..2b8b6ab
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/forcast.png b/kmymoney2/icons/Tango/32x32/apps/forcast.png
new file mode 100644
index 0000000..90b6a9f
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/institution_add.png b/kmymoney2/icons/Tango/32x32/apps/institution_add.png
new file mode 100644
index 0000000..e8afbc7
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/institutions.png b/kmymoney2/icons/Tango/32x32/apps/institutions.png
new file mode 100644
index 0000000..6f647a5
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/investments.png b/kmymoney2/icons/Tango/32x32/apps/investments.png
new file mode 100644
index 0000000..eb003cc
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/ledger.png b/kmymoney2/icons/Tango/32x32/apps/ledger.png
new file mode 100644
index 0000000..28e81e5
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/onlinebanking.png b/kmymoney2/icons/Tango/32x32/apps/onlinebanking.png
new file mode 100644
index 0000000..fdff8a9
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/payee.png b/kmymoney2/icons/Tango/32x32/apps/payee.png
new file mode 100644
index 0000000..221eea8
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/reconcile.png b/kmymoney2/icons/Tango/32x32/apps/reconcile.png
new file mode 100644
index 0000000..3ec2a25
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/report.png b/kmymoney2/icons/Tango/32x32/apps/report.png
new file mode 100644
index 0000000..656241f
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/schedule.png b/kmymoney2/icons/Tango/32x32/apps/schedule.png
new file mode 100644
index 0000000..24ea0c1
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/32x32/apps/transaction_find.png b/kmymoney2/icons/Tango/32x32/apps/transaction_find.png
new file mode 100644
index 0000000..268d367
--- /dev/null
+++ b/kmymoney2/icons/Tango/32x32/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/Makefile.am b/kmymoney2/icons/Tango/48x48/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/Tango/48x48/apps/Makefile.am b/kmymoney2/icons/Tango/48x48/apps/Makefile.am
new file mode 100644
index 0000000..181791a
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/48x48/apps
+
+icon_DATA = account_add.png account.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png budget.png categories.png forcast.png institution_add.png institutions.png investments.png ledger.png onlinebanking.png payee.png reconcile.png report.png schedule.png transaction_find.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_asset.png b/kmymoney2/icons/Tango/48x48/apps/account-types_asset.png
new file mode 100644
index 0000000..4384b29
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_cash.png b/kmymoney2/icons/Tango/48x48/apps/account-types_cash.png
new file mode 100644
index 0000000..ee6dae4
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_checking.png b/kmymoney2/icons/Tango/48x48/apps/account-types_checking.png
new file mode 100644
index 0000000..ce5e840
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_closed.png b/kmymoney2/icons/Tango/48x48/apps/account-types_closed.png
new file mode 100644
index 0000000..bfb04ac
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_credit-card.png b/kmymoney2/icons/Tango/48x48/apps/account-types_credit-card.png
new file mode 100644
index 0000000..cc6dd0e
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_expense.png b/kmymoney2/icons/Tango/48x48/apps/account-types_expense.png
new file mode 100644
index 0000000..02b0412
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_income.png b/kmymoney2/icons/Tango/48x48/apps/account-types_income.png
new file mode 100644
index 0000000..75c5a80
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_investments.png b/kmymoney2/icons/Tango/48x48/apps/account-types_investments.png
new file mode 100644
index 0000000..a567478
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_liability.png b/kmymoney2/icons/Tango/48x48/apps/account-types_liability.png
new file mode 100644
index 0000000..ffbecbd
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_loan.png b/kmymoney2/icons/Tango/48x48/apps/account-types_loan.png
new file mode 100644
index 0000000..cdf60d9
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account-types_savings.png b/kmymoney2/icons/Tango/48x48/apps/account-types_savings.png
new file mode 100644
index 0000000..5eaf97d
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account.png b/kmymoney2/icons/Tango/48x48/apps/account.png
new file mode 100644
index 0000000..a8dedf0
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/account_add.png b/kmymoney2/icons/Tango/48x48/apps/account_add.png
new file mode 100644
index 0000000..66f5f58
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/accounts.png b/kmymoney2/icons/Tango/48x48/apps/accounts.png
new file mode 100644
index 0000000..a8dedf0
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/budget.png b/kmymoney2/icons/Tango/48x48/apps/budget.png
new file mode 100644
index 0000000..607d504
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/categories.png b/kmymoney2/icons/Tango/48x48/apps/categories.png
new file mode 100644
index 0000000..54c1080
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/forcast.png b/kmymoney2/icons/Tango/48x48/apps/forcast.png
new file mode 100644
index 0000000..a034aa6
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/institution_add.png b/kmymoney2/icons/Tango/48x48/apps/institution_add.png
new file mode 100644
index 0000000..9b5d8e6
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/institutions.png b/kmymoney2/icons/Tango/48x48/apps/institutions.png
new file mode 100644
index 0000000..c79156b
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/investments.png b/kmymoney2/icons/Tango/48x48/apps/investments.png
new file mode 100644
index 0000000..24db317
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/ledger.png b/kmymoney2/icons/Tango/48x48/apps/ledger.png
new file mode 100644
index 0000000..1af0f1d
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/onlinebanking.png b/kmymoney2/icons/Tango/48x48/apps/onlinebanking.png
new file mode 100644
index 0000000..4eba265
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/payee.png b/kmymoney2/icons/Tango/48x48/apps/payee.png
new file mode 100644
index 0000000..5c78ae9
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/reconcile.png b/kmymoney2/icons/Tango/48x48/apps/reconcile.png
new file mode 100644
index 0000000..c48b588
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/report.png b/kmymoney2/icons/Tango/48x48/apps/report.png
new file mode 100644
index 0000000..cc54a41
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/schedule.png b/kmymoney2/icons/Tango/48x48/apps/schedule.png
new file mode 100644
index 0000000..5572b8f
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/48x48/apps/transaction_find.png b/kmymoney2/icons/Tango/48x48/apps/transaction_find.png
new file mode 100644
index 0000000..6293d9e
--- /dev/null
+++ b/kmymoney2/icons/Tango/48x48/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/Makefile.am b/kmymoney2/icons/Tango/64x64/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/Tango/64x64/apps/Makefile.am b/kmymoney2/icons/Tango/64x64/apps/Makefile.am
new file mode 100644
index 0000000..f0b1d9a
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/64x64/apps
+
+icon_DATA = account_add.png account.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png budget.png categories.png forcast.png institution_add.png institutions.png investments.png ledger.png onlinebanking.png payee.png reconcile.png report.png schedule.png transaction_find.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_asset.png b/kmymoney2/icons/Tango/64x64/apps/account-types_asset.png
new file mode 100644
index 0000000..af17498
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_cash.png b/kmymoney2/icons/Tango/64x64/apps/account-types_cash.png
new file mode 100644
index 0000000..82ad69b
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_checking.png b/kmymoney2/icons/Tango/64x64/apps/account-types_checking.png
new file mode 100644
index 0000000..8608763
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_closed.png b/kmymoney2/icons/Tango/64x64/apps/account-types_closed.png
new file mode 100644
index 0000000..6700e0b
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_credit-card.png b/kmymoney2/icons/Tango/64x64/apps/account-types_credit-card.png
new file mode 100644
index 0000000..61af127
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_expense.png b/kmymoney2/icons/Tango/64x64/apps/account-types_expense.png
new file mode 100644
index 0000000..90bde8f
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_income.png b/kmymoney2/icons/Tango/64x64/apps/account-types_income.png
new file mode 100644
index 0000000..c7a5a00
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_investments.png b/kmymoney2/icons/Tango/64x64/apps/account-types_investments.png
new file mode 100644
index 0000000..115deab
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_liability.png b/kmymoney2/icons/Tango/64x64/apps/account-types_liability.png
new file mode 100644
index 0000000..cf4f813
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_loan.png b/kmymoney2/icons/Tango/64x64/apps/account-types_loan.png
new file mode 100644
index 0000000..f60fca9
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account-types_savings.png b/kmymoney2/icons/Tango/64x64/apps/account-types_savings.png
new file mode 100644
index 0000000..a5217c1
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account.png b/kmymoney2/icons/Tango/64x64/apps/account.png
new file mode 100644
index 0000000..63ad620
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/account_add.png b/kmymoney2/icons/Tango/64x64/apps/account_add.png
new file mode 100644
index 0000000..4f94e1e
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/accounts.png b/kmymoney2/icons/Tango/64x64/apps/accounts.png
new file mode 100644
index 0000000..63ad620
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/budget.png b/kmymoney2/icons/Tango/64x64/apps/budget.png
new file mode 100644
index 0000000..f89c5f1
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/categories.png b/kmymoney2/icons/Tango/64x64/apps/categories.png
new file mode 100644
index 0000000..e5d039a
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/forcast.png b/kmymoney2/icons/Tango/64x64/apps/forcast.png
new file mode 100644
index 0000000..2a926a5
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/institution_add.png b/kmymoney2/icons/Tango/64x64/apps/institution_add.png
new file mode 100644
index 0000000..f6f8efb
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/institutions.png b/kmymoney2/icons/Tango/64x64/apps/institutions.png
new file mode 100644
index 0000000..3ec4dc6
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/investments.png b/kmymoney2/icons/Tango/64x64/apps/investments.png
new file mode 100644
index 0000000..43ccdb4
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/ledger.png b/kmymoney2/icons/Tango/64x64/apps/ledger.png
new file mode 100644
index 0000000..0d6c083
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/onlinebanking.png b/kmymoney2/icons/Tango/64x64/apps/onlinebanking.png
new file mode 100644
index 0000000..15f9648
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/payee.png b/kmymoney2/icons/Tango/64x64/apps/payee.png
new file mode 100644
index 0000000..75e86af
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/reconcile.png b/kmymoney2/icons/Tango/64x64/apps/reconcile.png
new file mode 100644
index 0000000..07ba00e
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/report.png b/kmymoney2/icons/Tango/64x64/apps/report.png
new file mode 100644
index 0000000..d30c9b3
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/schedule.png b/kmymoney2/icons/Tango/64x64/apps/schedule.png
new file mode 100644
index 0000000..b8882c6
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/64x64/apps/transaction_find.png b/kmymoney2/icons/Tango/64x64/apps/transaction_find.png
new file mode 100644
index 0000000..af7c0f1
--- /dev/null
+++ b/kmymoney2/icons/Tango/64x64/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/Tango/Makefile.am b/kmymoney2/icons/Tango/Makefile.am
new file mode 100644
index 0000000..a088af8
--- /dev/null
+++ b/kmymoney2/icons/Tango/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = 16x16 48x48 32x32 128x128 scalable 64x64 22x22
diff --git a/kmymoney2/icons/Tango/scalable/Makefile.am b/kmymoney2/icons/Tango/scalable/Makefile.am
new file mode 100644
index 0000000..1159059
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/Tango/scalable
+
+icon_DATA = account_add.svgz accounts.svgz account.svgz account-types_asset.svgz account-types_cash.svgz account-types_checking.svgz account-types_closed.svgz account-types_credit-card.svgz account-types_expense.svgz account-types_income.svgz account-types_investments.svgz account-types_liability.svgz account-types_loan.svgz account-types_savings.svgz backup.svgz bank.svgz budget.svgz categories.svgz forcast.svgz hide_categories.svgz hide_reconciled.svgz institution_add.svgz institutions.svgz investments.svgz ledger.svgz onlinebanking.svgz payee.svgz personal_data.svgz reconcile.svgz report.svgz schedule.svgz transaction_find.svgz view_info.svgz
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/Tango/scalable/account-types_asset.svgz b/kmymoney2/icons/Tango/scalable/account-types_asset.svgz
new file mode 100644
index 0000000..b4a0039
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_asset.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_cash.svgz b/kmymoney2/icons/Tango/scalable/account-types_cash.svgz
new file mode 100644
index 0000000..1b9060c
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_cash.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_checking.svgz b/kmymoney2/icons/Tango/scalable/account-types_checking.svgz
new file mode 100644
index 0000000..00f97b3
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_checking.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_closed.svgz b/kmymoney2/icons/Tango/scalable/account-types_closed.svgz
new file mode 100644
index 0000000..619992c
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_closed.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_credit-card.svgz b/kmymoney2/icons/Tango/scalable/account-types_credit-card.svgz
new file mode 100644
index 0000000..3c0e50d
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_credit-card.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_expense.svgz b/kmymoney2/icons/Tango/scalable/account-types_expense.svgz
new file mode 100644
index 0000000..290a7c0
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_expense.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_income.svgz b/kmymoney2/icons/Tango/scalable/account-types_income.svgz
new file mode 100644
index 0000000..57f7cdb
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_income.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_investments.svgz b/kmymoney2/icons/Tango/scalable/account-types_investments.svgz
new file mode 100644
index 0000000..d152c2d
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_investments.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_liability.svgz b/kmymoney2/icons/Tango/scalable/account-types_liability.svgz
new file mode 100644
index 0000000..2ff3771
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_liability.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_loan.svgz b/kmymoney2/icons/Tango/scalable/account-types_loan.svgz
new file mode 100644
index 0000000..00efd5e
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_loan.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account-types_savings.svgz b/kmymoney2/icons/Tango/scalable/account-types_savings.svgz
new file mode 100644
index 0000000..f56f44e
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account-types_savings.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account.svgz b/kmymoney2/icons/Tango/scalable/account.svgz
new file mode 100644
index 0000000..fe49ce8
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/account_add.svgz b/kmymoney2/icons/Tango/scalable/account_add.svgz
new file mode 100644
index 0000000..e1f33d2
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/account_add.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/accounts.svgz b/kmymoney2/icons/Tango/scalable/accounts.svgz
new file mode 100644
index 0000000..fe49ce8
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/accounts.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/backup.svgz b/kmymoney2/icons/Tango/scalable/backup.svgz
new file mode 100644
index 0000000..bc31903
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/backup.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/bank.svgz b/kmymoney2/icons/Tango/scalable/bank.svgz
new file mode 100644
index 0000000..fe49ce8
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/bank.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/budget.svgz b/kmymoney2/icons/Tango/scalable/budget.svgz
new file mode 100644
index 0000000..f17906a
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/budget.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/categories.svgz b/kmymoney2/icons/Tango/scalable/categories.svgz
new file mode 100644
index 0000000..dea910a
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/categories.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/forcast.svgz b/kmymoney2/icons/Tango/scalable/forcast.svgz
new file mode 100644
index 0000000..d156f0f
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/forcast.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/hide_categories.svgz b/kmymoney2/icons/Tango/scalable/hide_categories.svgz
new file mode 100644
index 0000000..74a5264
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/hide_categories.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/hide_reconciled.svgz b/kmymoney2/icons/Tango/scalable/hide_reconciled.svgz
new file mode 100644
index 0000000..a483b48
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/hide_reconciled.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/institution_add.svgz b/kmymoney2/icons/Tango/scalable/institution_add.svgz
new file mode 100644
index 0000000..2c91c73
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/institution_add.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/institutions.svgz b/kmymoney2/icons/Tango/scalable/institutions.svgz
new file mode 100644
index 0000000..5733e25
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/institutions.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/investments.svgz b/kmymoney2/icons/Tango/scalable/investments.svgz
new file mode 100644
index 0000000..d152c2d
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/investments.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/ledger.svgz b/kmymoney2/icons/Tango/scalable/ledger.svgz
new file mode 100644
index 0000000..2302d00
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/ledger.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/onlinebanking.svgz b/kmymoney2/icons/Tango/scalable/onlinebanking.svgz
new file mode 100644
index 0000000..f1032c0
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/onlinebanking.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/payee.svgz b/kmymoney2/icons/Tango/scalable/payee.svgz
new file mode 100644
index 0000000..c039c79
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/payee.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/personal_data.svgz b/kmymoney2/icons/Tango/scalable/personal_data.svgz
new file mode 100644
index 0000000..6438c3a
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/personal_data.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/reconcile.svgz b/kmymoney2/icons/Tango/scalable/reconcile.svgz
new file mode 100644
index 0000000..7025964
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/reconcile.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/report.svgz b/kmymoney2/icons/Tango/scalable/report.svgz
new file mode 100644
index 0000000..ca68980
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/report.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/schedule.svgz b/kmymoney2/icons/Tango/scalable/schedule.svgz
new file mode 100644
index 0000000..d7007a5
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/schedule.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/transaction_find.svgz b/kmymoney2/icons/Tango/scalable/transaction_find.svgz
new file mode 100644
index 0000000..343e90f
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/transaction_find.svgz
Binary files differ
diff --git a/kmymoney2/icons/Tango/scalable/view_info.svgz b/kmymoney2/icons/Tango/scalable/view_info.svgz
new file mode 100644
index 0000000..faf451d
--- /dev/null
+++ b/kmymoney2/icons/Tango/scalable/view_info.svgz
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/Makefile.am b/kmymoney2/icons/hicolor/16x16/Makefile.am
new file mode 100644
index 0000000..cb1ac82
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = actions
+
+LOCAL_DIR=kmymoney2/icons/hicolor/16x16
+
+uninstall-local:
+ for i in $(SUBDIRS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$i; \
+ done
diff --git a/kmymoney2/icons/hicolor/16x16/actions/Makefile.am b/kmymoney2/icons/hicolor/16x16/actions/Makefile.am
new file mode 100644
index 0000000..6073bb0
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/Makefile.am
@@ -0,0 +1,17 @@
+
+LOCAL_DIR=kmymoney2/icons/hicolor/16x16/actions
+
+FILES = bank.png categories.png pay_edit.png transaction_export.png transaction_find.png transaction_import.png reconcile.png backup.png close_window.png delete.png personal_data.png transaction.png view_info.png account_add.png account_open.png ledger.png account-type_asset.png account-type_liability.png account-type_expense.png account-type_income.png institution_add.png unreconciled.png hide_categories.png hide_reconciled.png update_prices.png split_transaction.png
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+
+uninstall-local:
+ for file in $(FILES); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
diff --git a/kmymoney2/icons/hicolor/16x16/actions/account-type_asset.png b/kmymoney2/icons/hicolor/16x16/actions/account-type_asset.png
new file mode 100644
index 0000000..fdfff9f
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/account-type_asset.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/account-type_expense.png b/kmymoney2/icons/hicolor/16x16/actions/account-type_expense.png
new file mode 100644
index 0000000..1ae99e9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/account-type_expense.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/account-type_income.png b/kmymoney2/icons/hicolor/16x16/actions/account-type_income.png
new file mode 100644
index 0000000..7cb9c7a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/account-type_income.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/account-type_liability.png b/kmymoney2/icons/hicolor/16x16/actions/account-type_liability.png
new file mode 100644
index 0000000..3c083f3
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/account-type_liability.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/account_add.png b/kmymoney2/icons/hicolor/16x16/actions/account_add.png
new file mode 100644
index 0000000..8f826ce
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/account_open.png b/kmymoney2/icons/hicolor/16x16/actions/account_open.png
new file mode 100644
index 0000000..9d58c5c
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/account_open.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/backup.png b/kmymoney2/icons/hicolor/16x16/actions/backup.png
new file mode 100644
index 0000000..71dab66
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/backup.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/bank.png b/kmymoney2/icons/hicolor/16x16/actions/bank.png
new file mode 100644
index 0000000..4918b7f
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/bank.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/categories.png b/kmymoney2/icons/hicolor/16x16/actions/categories.png
new file mode 100644
index 0000000..5dda50f
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/close_window.png b/kmymoney2/icons/hicolor/16x16/actions/close_window.png
new file mode 100644
index 0000000..50003a4
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/close_window.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/delete.png b/kmymoney2/icons/hicolor/16x16/actions/delete.png
new file mode 100644
index 0000000..a51e735
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/delete.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/hide_categories.png b/kmymoney2/icons/hicolor/16x16/actions/hide_categories.png
new file mode 100644
index 0000000..5cc1c35
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/hide_categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/hide_reconciled.png b/kmymoney2/icons/hicolor/16x16/actions/hide_reconciled.png
new file mode 100644
index 0000000..4800c1e
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/hide_reconciled.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/institution_add.png b/kmymoney2/icons/hicolor/16x16/actions/institution_add.png
new file mode 100644
index 0000000..7379d45
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/ledger.png b/kmymoney2/icons/hicolor/16x16/actions/ledger.png
new file mode 100644
index 0000000..e5fd55d
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/pay_edit.png b/kmymoney2/icons/hicolor/16x16/actions/pay_edit.png
new file mode 100644
index 0000000..7b26ed5
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/pay_edit.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/personal_data.png b/kmymoney2/icons/hicolor/16x16/actions/personal_data.png
new file mode 100644
index 0000000..937c61f
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/personal_data.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/reconcile.png b/kmymoney2/icons/hicolor/16x16/actions/reconcile.png
new file mode 100644
index 0000000..1433cc3
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/split_transaction.png b/kmymoney2/icons/hicolor/16x16/actions/split_transaction.png
new file mode 100644
index 0000000..0602343
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/split_transaction.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/transaction.png b/kmymoney2/icons/hicolor/16x16/actions/transaction.png
new file mode 100644
index 0000000..3e12f68
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/transaction.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/transaction_export.png b/kmymoney2/icons/hicolor/16x16/actions/transaction_export.png
new file mode 100644
index 0000000..78f390e
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/transaction_export.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/transaction_find.png b/kmymoney2/icons/hicolor/16x16/actions/transaction_find.png
new file mode 100644
index 0000000..1066d61
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/transaction_import.png b/kmymoney2/icons/hicolor/16x16/actions/transaction_import.png
new file mode 100644
index 0000000..bf4eb18
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/transaction_import.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/unreconciled.png b/kmymoney2/icons/hicolor/16x16/actions/unreconciled.png
new file mode 100644
index 0000000..e7f7c28
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/unreconciled.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/update_prices.png b/kmymoney2/icons/hicolor/16x16/actions/update_prices.png
new file mode 100644
index 0000000..9122c95
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/update_prices.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/16x16/actions/view_info.png b/kmymoney2/icons/hicolor/16x16/actions/view_info.png
new file mode 100644
index 0000000..882ec10
--- /dev/null
+++ b/kmymoney2/icons/hicolor/16x16/actions/view_info.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/Makefile.am b/kmymoney2/icons/hicolor/22x22/Makefile.am
new file mode 100644
index 0000000..13a8aee
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = actions
+
+LOCAL_DIR=kmymoney2/icons/hicolor/22x22
+
+uninstall-local:
+ for i in $(SUBDIRS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$i; \
+ done
diff --git a/kmymoney2/icons/hicolor/22x22/actions/Makefile.am b/kmymoney2/icons/hicolor/22x22/actions/Makefile.am
new file mode 100644
index 0000000..6344545
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/Makefile.am
@@ -0,0 +1,17 @@
+
+LOCAL_DIR=kmymoney2/icons/hicolor/22x22/actions
+
+FILES = bank.png categories.png pay_edit.png transaction_export.png transaction_find.png transaction_import.png reconcile.png backup.png close_window.png delete.png personal_data.png transaction.png view_info.png account_add.png account_open.png ledger.png account-types_asset.png account-types_liability.png account-types_expense.png account-types_income.png institution_add.png unreconciled.png account-types_closed.png hide_categories.png hide_reconciled.png update_prices.png account-types_reconcile.png attention.png account-types_online.png
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+
+uninstall-local:
+ for file in $(FILES); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_asset.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_asset.png
new file mode 100644
index 0000000..0483be2
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_closed.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_closed.png
new file mode 100644
index 0000000..6ace80a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_expense.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_expense.png
new file mode 100644
index 0000000..9379f83
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_income.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_income.png
new file mode 100644
index 0000000..2a22b28
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_liability.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_liability.png
new file mode 100644
index 0000000..9e750e2
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_online.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_online.png
new file mode 100644
index 0000000..22fb143
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_online.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account-types_reconcile.png b/kmymoney2/icons/hicolor/22x22/actions/account-types_reconcile.png
new file mode 100644
index 0000000..690abb2
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account-types_reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account_add.png b/kmymoney2/icons/hicolor/22x22/actions/account_add.png
new file mode 100644
index 0000000..271d3f8
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/account_open.png b/kmymoney2/icons/hicolor/22x22/actions/account_open.png
new file mode 100644
index 0000000..8c27082
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/account_open.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/attention.png b/kmymoney2/icons/hicolor/22x22/actions/attention.png
new file mode 100644
index 0000000..e118279
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/attention.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/backup.png b/kmymoney2/icons/hicolor/22x22/actions/backup.png
new file mode 100644
index 0000000..7fe56b6
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/backup.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/bank.png b/kmymoney2/icons/hicolor/22x22/actions/bank.png
new file mode 100644
index 0000000..fa494ff
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/bank.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/categories.png b/kmymoney2/icons/hicolor/22x22/actions/categories.png
new file mode 100644
index 0000000..0804448
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/cleared.png b/kmymoney2/icons/hicolor/22x22/actions/cleared.png
new file mode 100644
index 0000000..b5690c9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/cleared.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/close_window.png b/kmymoney2/icons/hicolor/22x22/actions/close_window.png
new file mode 100644
index 0000000..9108ee7
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/close_window.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/delete.png b/kmymoney2/icons/hicolor/22x22/actions/delete.png
new file mode 100644
index 0000000..1fe162e
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/delete.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/hide_categories.png b/kmymoney2/icons/hicolor/22x22/actions/hide_categories.png
new file mode 100644
index 0000000..b044e16
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/hide_categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/hide_reconciled.png b/kmymoney2/icons/hicolor/22x22/actions/hide_reconciled.png
new file mode 100644
index 0000000..1bcd345
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/hide_reconciled.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/institution_add.png b/kmymoney2/icons/hicolor/22x22/actions/institution_add.png
new file mode 100644
index 0000000..ac1d258
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/ledger.png b/kmymoney2/icons/hicolor/22x22/actions/ledger.png
new file mode 100644
index 0000000..49477da
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/pay_edit.png b/kmymoney2/icons/hicolor/22x22/actions/pay_edit.png
new file mode 100644
index 0000000..2d82c6b
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/pay_edit.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/personal_data.png b/kmymoney2/icons/hicolor/22x22/actions/personal_data.png
new file mode 100644
index 0000000..5ae2d71
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/personal_data.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/reconcile.png b/kmymoney2/icons/hicolor/22x22/actions/reconcile.png
new file mode 100644
index 0000000..80911e6
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/report-bar.png b/kmymoney2/icons/hicolor/22x22/actions/report-bar.png
new file mode 100644
index 0000000..b2d1782
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/report-bar.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/report-line.png b/kmymoney2/icons/hicolor/22x22/actions/report-line.png
new file mode 100644
index 0000000..9d506dc
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/report-line.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/report-pie.png b/kmymoney2/icons/hicolor/22x22/actions/report-pie.png
new file mode 100644
index 0000000..0cd8577
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/report-pie.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/report-solid.png b/kmymoney2/icons/hicolor/22x22/actions/report-solid.png
new file mode 100644
index 0000000..d89cd7b
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/report-solid.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/report-text.png b/kmymoney2/icons/hicolor/22x22/actions/report-text.png
new file mode 100644
index 0000000..5d53e1a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/report-text.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/set_as.png b/kmymoney2/icons/hicolor/22x22/actions/set_as.png
new file mode 100644
index 0000000..b5690c9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/set_as.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/transaction.png b/kmymoney2/icons/hicolor/22x22/actions/transaction.png
new file mode 100644
index 0000000..b95eafd
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/transaction.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/transaction_export.png b/kmymoney2/icons/hicolor/22x22/actions/transaction_export.png
new file mode 100644
index 0000000..fe7681f
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/transaction_export.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/transaction_find.png b/kmymoney2/icons/hicolor/22x22/actions/transaction_find.png
new file mode 100644
index 0000000..4cba2df
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/transaction_import.png b/kmymoney2/icons/hicolor/22x22/actions/transaction_import.png
new file mode 100644
index 0000000..ebd7d85
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/transaction_import.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/unreconciled.png b/kmymoney2/icons/hicolor/22x22/actions/unreconciled.png
new file mode 100644
index 0000000..004a3ec
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/unreconciled.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/update_prices.png b/kmymoney2/icons/hicolor/22x22/actions/update_prices.png
new file mode 100644
index 0000000..a69578a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/update_prices.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/22x22/actions/view_info.png b/kmymoney2/icons/hicolor/22x22/actions/view_info.png
new file mode 100644
index 0000000..e4a9962
--- /dev/null
+++ b/kmymoney2/icons/hicolor/22x22/actions/view_info.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/Makefile.am b/kmymoney2/icons/hicolor/32x32/Makefile.am
new file mode 100644
index 0000000..1907dee
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = apps
+
+LOCAL_DIR=kmymoney2/icons/hicolor/32x32
+
+uninstall-local:
+ for i in $(SUBDIRS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$i; \
+ done
diff --git a/kmymoney2/icons/hicolor/32x32/apps/Makefile.am b/kmymoney2/icons/hicolor/32x32/apps/Makefile.am
new file mode 100644
index 0000000..adab201
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/Makefile.am
@@ -0,0 +1,18 @@
+
+LOCAL_DIR = kmymoney2/icons/hicolor/32x32/apps
+
+FILES = accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_credit-card.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png categories.png forcast.png home.png institutions.png investments.png ledger.png payee.png report.png schedule.png onlinebanking.png budget.png account-types_reconciled.png
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+
+uninstall-local:
+ for file in $(FILES); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
+
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_asset.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_asset.png
new file mode 100644
index 0000000..62b30fb
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_cash.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_cash.png
new file mode 100644
index 0000000..b10c8cc
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_checking.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_checking.png
new file mode 100644
index 0000000..92820ff
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_credit-card.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_credit-card.png
new file mode 100644
index 0000000..6636200
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_investments.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_investments.png
new file mode 100644
index 0000000..57e0d65
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_liability.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_liability.png
new file mode 100644
index 0000000..93ff071
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_loan.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_loan.png
new file mode 100644
index 0000000..6e475cc
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_reconciled.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_reconciled.png
new file mode 100644
index 0000000..3be1a71
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_reconciled.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/account-types_savings.png b/kmymoney2/icons/hicolor/32x32/apps/account-types_savings.png
new file mode 100644
index 0000000..6a528a3
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/accounts.png b/kmymoney2/icons/hicolor/32x32/apps/accounts.png
new file mode 100644
index 0000000..86199c4
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/budget.png b/kmymoney2/icons/hicolor/32x32/apps/budget.png
new file mode 100644
index 0000000..3d39241
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/categories.png b/kmymoney2/icons/hicolor/32x32/apps/categories.png
new file mode 100644
index 0000000..dd030a7
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/forcast.png b/kmymoney2/icons/hicolor/32x32/apps/forcast.png
new file mode 100644
index 0000000..43df58a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/home.png b/kmymoney2/icons/hicolor/32x32/apps/home.png
new file mode 100644
index 0000000..baa8912
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/home.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/institutions.png b/kmymoney2/icons/hicolor/32x32/apps/institutions.png
new file mode 100644
index 0000000..7a46aff
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/investments.png b/kmymoney2/icons/hicolor/32x32/apps/investments.png
new file mode 100644
index 0000000..8dd81fe
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/ledger.png b/kmymoney2/icons/hicolor/32x32/apps/ledger.png
new file mode 100644
index 0000000..e93b6c7
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/onlinebanking.png b/kmymoney2/icons/hicolor/32x32/apps/onlinebanking.png
new file mode 100644
index 0000000..9190f0a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/payee.png b/kmymoney2/icons/hicolor/32x32/apps/payee.png
new file mode 100644
index 0000000..ce926ac
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/report.png b/kmymoney2/icons/hicolor/32x32/apps/report.png
new file mode 100644
index 0000000..fd3094d
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/32x32/apps/schedule.png b/kmymoney2/icons/hicolor/32x32/apps/schedule.png
new file mode 100644
index 0000000..aa8d318
--- /dev/null
+++ b/kmymoney2/icons/hicolor/32x32/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/Makefile.am b/kmymoney2/icons/hicolor/48x48/Makefile.am
new file mode 100644
index 0000000..d18fb92
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = apps
+
+LOCAL_DIR=kmymoney2/icons/hicolor/48x48
+
+uninstall-local:
+ for i in $(SUBDIRS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$i; \
+ done
diff --git a/kmymoney2/icons/hicolor/48x48/apps/Makefile.am b/kmymoney2/icons/hicolor/48x48/apps/Makefile.am
new file mode 100644
index 0000000..cd9f057
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/Makefile.am
@@ -0,0 +1,18 @@
+
+LOCAL_DIR = kmymoney2/icons/hicolor/48x48/apps
+
+FILES = accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_credit-card.png account-types_investment.png account-types_liability.png account-types_loan.png account-types_savings.png categories.png forcast.png home.png institutions.png investments.png ledger.png payee.png report.png schedule.png onlinebanking.png budget.png
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+
+uninstall-local:
+ for file in $(FILES); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
+
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_asset.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_asset.png
new file mode 100644
index 0000000..fc2a8a9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_cash.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_cash.png
new file mode 100644
index 0000000..d9ba5f7
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_checking.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_checking.png
new file mode 100644
index 0000000..5e7c3f3
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_credit-card.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_credit-card.png
new file mode 100644
index 0000000..5d73911
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_investment.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_investment.png
new file mode 100644
index 0000000..d2c7101
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_investment.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_liability.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_liability.png
new file mode 100644
index 0000000..5971fbc
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_loan.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_loan.png
new file mode 100644
index 0000000..e0ef75d
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/account-types_savings.png b/kmymoney2/icons/hicolor/48x48/apps/account-types_savings.png
new file mode 100644
index 0000000..421b049
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/accounts.png b/kmymoney2/icons/hicolor/48x48/apps/accounts.png
new file mode 100644
index 0000000..46bb27a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/budget.png b/kmymoney2/icons/hicolor/48x48/apps/budget.png
new file mode 100644
index 0000000..84c78a0
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/categories.png b/kmymoney2/icons/hicolor/48x48/apps/categories.png
new file mode 100644
index 0000000..3763121
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/forcast.png b/kmymoney2/icons/hicolor/48x48/apps/forcast.png
new file mode 100644
index 0000000..7c220ca
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/home.png b/kmymoney2/icons/hicolor/48x48/apps/home.png
new file mode 100644
index 0000000..d08e6ab
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/home.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/institutions.png b/kmymoney2/icons/hicolor/48x48/apps/institutions.png
new file mode 100644
index 0000000..c5fe486
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/investments.png b/kmymoney2/icons/hicolor/48x48/apps/investments.png
new file mode 100644
index 0000000..a8f9970
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/ledger.png b/kmymoney2/icons/hicolor/48x48/apps/ledger.png
new file mode 100644
index 0000000..49a7f09
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/onlinebanking.png b/kmymoney2/icons/hicolor/48x48/apps/onlinebanking.png
new file mode 100644
index 0000000..b85a090
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/payee.png b/kmymoney2/icons/hicolor/48x48/apps/payee.png
new file mode 100644
index 0000000..75807e5
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/report.png b/kmymoney2/icons/hicolor/48x48/apps/report.png
new file mode 100644
index 0000000..94369c6
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/48x48/apps/schedule.png b/kmymoney2/icons/hicolor/48x48/apps/schedule.png
new file mode 100644
index 0000000..ed65196
--- /dev/null
+++ b/kmymoney2/icons/hicolor/48x48/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/Makefile.am b/kmymoney2/icons/hicolor/64x64/Makefile.am
new file mode 100644
index 0000000..e5c1f4d
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = apps
+
+LOCAL_DIR=kmymoney2/icons/hicolor/64x64
+
+uninstall-local:
+ for i in $(SUBDIRS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$i; \
+ done
diff --git a/kmymoney2/icons/hicolor/64x64/apps/Makefile.am b/kmymoney2/icons/hicolor/64x64/apps/Makefile.am
new file mode 100644
index 0000000..7b8afca
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/Makefile.am
@@ -0,0 +1,18 @@
+
+LOCAL_DIR = kmymoney2/icons/hicolor/64x64/apps
+
+FILES = accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_credit-card.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png categories.png forcast.png home.png institutions.png investments.png ledger.png payee.png report.png schedule.png onlinebanking.png budget.png
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+
+uninstall-local:
+ for file in $(FILES); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
+
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_asset.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_asset.png
new file mode 100644
index 0000000..0eff909
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_cash.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_cash.png
new file mode 100644
index 0000000..397780b
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_checking.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_checking.png
new file mode 100644
index 0000000..56b3ae5
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_credit-card.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_credit-card.png
new file mode 100644
index 0000000..12e5788
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_investments.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_investments.png
new file mode 100644
index 0000000..b345061
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_liability.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_liability.png
new file mode 100644
index 0000000..92d0d75
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_loan.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_loan.png
new file mode 100644
index 0000000..93cac29
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/account-types_savings.png b/kmymoney2/icons/hicolor/64x64/apps/account-types_savings.png
new file mode 100644
index 0000000..5f6f96f
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/accounts.png b/kmymoney2/icons/hicolor/64x64/apps/accounts.png
new file mode 100644
index 0000000..ca002c9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/budget.png b/kmymoney2/icons/hicolor/64x64/apps/budget.png
new file mode 100644
index 0000000..9177851
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/categories.png b/kmymoney2/icons/hicolor/64x64/apps/categories.png
new file mode 100644
index 0000000..11efdd4
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/forcast.png b/kmymoney2/icons/hicolor/64x64/apps/forcast.png
new file mode 100644
index 0000000..92cb9cd
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/home.png b/kmymoney2/icons/hicolor/64x64/apps/home.png
new file mode 100644
index 0000000..acf3e4a
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/home.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/institutions.png b/kmymoney2/icons/hicolor/64x64/apps/institutions.png
new file mode 100644
index 0000000..36db2d9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/investments.png b/kmymoney2/icons/hicolor/64x64/apps/investments.png
new file mode 100644
index 0000000..9558979
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/ledger.png b/kmymoney2/icons/hicolor/64x64/apps/ledger.png
new file mode 100644
index 0000000..54c08d4
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/onlinebanking.png b/kmymoney2/icons/hicolor/64x64/apps/onlinebanking.png
new file mode 100644
index 0000000..719895c
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/payee.png b/kmymoney2/icons/hicolor/64x64/apps/payee.png
new file mode 100644
index 0000000..840afa9
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/report.png b/kmymoney2/icons/hicolor/64x64/apps/report.png
new file mode 100644
index 0000000..580af91
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/64x64/apps/schedule.png b/kmymoney2/icons/hicolor/64x64/apps/schedule.png
new file mode 100644
index 0000000..d5b7912
--- /dev/null
+++ b/kmymoney2/icons/hicolor/64x64/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/hicolor/Makefile.am b/kmymoney2/icons/hicolor/Makefile.am
new file mode 100644
index 0000000..e831a2c
--- /dev/null
+++ b/kmymoney2/icons/hicolor/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = 16x16 22x22 32x32 48x48 64x64
+
+LOCAL_DIR=kmymoney2/icons/hicolor
+
+uninstall-local:
+ for i in $(SUBDIRS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$i; \
+ done
diff --git a/kmymoney2/icons/oxygen/128x128/Makefile.am b/kmymoney2/icons/oxygen/128x128/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/oxygen/128x128/apps/Makefile.am b/kmymoney2/icons/oxygen/128x128/apps/Makefile.am
new file mode 100644
index 0000000..38545b3
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/128x128/apps
+
+icon_DATA = account-add.png accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_investments.png account-types_liability.png account-types_loan.png budget.png categories.png forcast.png institutions.png investments.png ledger.png onlinebanking.png payee.png reconcile.png report.png schedule.png transaction_find.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-add.png b/kmymoney2/icons/oxygen/128x128/apps/account-add.png
new file mode 100644
index 0000000..6ee87e4
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-add.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_asset.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_asset.png
new file mode 100644
index 0000000..926bb0f
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_cash.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_cash.png
new file mode 100644
index 0000000..42e858e
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_checking.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_checking.png
new file mode 100644
index 0000000..856dc8d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_closed.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_closed.png
new file mode 100644
index 0000000..0a2424b
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_credit-card.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_credit-card.png
new file mode 100644
index 0000000..442914c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_investments.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_investments.png
new file mode 100644
index 0000000..3409195
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_liability.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_liability.png
new file mode 100644
index 0000000..d2a12ee
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/account-types_loan.png b/kmymoney2/icons/oxygen/128x128/apps/account-types_loan.png
new file mode 100644
index 0000000..5b61797
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/accounts.png b/kmymoney2/icons/oxygen/128x128/apps/accounts.png
new file mode 100644
index 0000000..a331570
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/budget.png b/kmymoney2/icons/oxygen/128x128/apps/budget.png
new file mode 100644
index 0000000..1e933ca
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/categories.png b/kmymoney2/icons/oxygen/128x128/apps/categories.png
new file mode 100644
index 0000000..f798b1c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/forcast.png b/kmymoney2/icons/oxygen/128x128/apps/forcast.png
new file mode 100644
index 0000000..03b571a
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/institutions.png b/kmymoney2/icons/oxygen/128x128/apps/institutions.png
new file mode 100644
index 0000000..e40889c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/investments.png b/kmymoney2/icons/oxygen/128x128/apps/investments.png
new file mode 100644
index 0000000..3409195
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/ledger.png b/kmymoney2/icons/oxygen/128x128/apps/ledger.png
new file mode 100644
index 0000000..442079a
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/onlinebanking.png b/kmymoney2/icons/oxygen/128x128/apps/onlinebanking.png
new file mode 100644
index 0000000..b887aaa
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/payee.png b/kmymoney2/icons/oxygen/128x128/apps/payee.png
new file mode 100644
index 0000000..ad77914
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/reconcile.png b/kmymoney2/icons/oxygen/128x128/apps/reconcile.png
new file mode 100644
index 0000000..8120fec
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/report.png b/kmymoney2/icons/oxygen/128x128/apps/report.png
new file mode 100644
index 0000000..6b5ba61
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/schedule.png b/kmymoney2/icons/oxygen/128x128/apps/schedule.png
new file mode 100644
index 0000000..ed998b5
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/128x128/apps/transaction_find.png b/kmymoney2/icons/oxygen/128x128/apps/transaction_find.png
new file mode 100644
index 0000000..cbf37ed
--- /dev/null
+++ b/kmymoney2/icons/oxygen/128x128/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/Makefile.am b/kmymoney2/icons/oxygen/16x16/Makefile.am
new file mode 100644
index 0000000..2af9bf4
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = actions
diff --git a/kmymoney2/icons/oxygen/16x16/actions/Makefile.am b/kmymoney2/icons/oxygen/16x16/actions/Makefile.am
new file mode 100644
index 0000000..5d79467
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/16x16/actions
+
+icon_DATA = accounts.png account-types_asset.png account-types_cash.png account-types_checking.png account-types_closed.png account-types_credit-card.png account-types_expense.png account-types_income.png account-types_investments.png account-types_liability.png account-types_loan.png account-types_savings.png budget.png forcast.png institutions.png investments.png ledger.png onlinebanking.png payee.png report.png schedule.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_asset.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_asset.png
new file mode 100644
index 0000000..cd85608
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_asset.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_cash.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_cash.png
new file mode 100644
index 0000000..39b0e00
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_checking.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_checking.png
new file mode 100644
index 0000000..595f832
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_closed.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_closed.png
new file mode 100644
index 0000000..0d26c8e
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_credit-card.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_credit-card.png
new file mode 100644
index 0000000..3445468
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_expense.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_expense.png
new file mode 100644
index 0000000..17e5b10
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_income.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_income.png
new file mode 100644
index 0000000..3bd0bd8
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_investments.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_investments.png
new file mode 100644
index 0000000..9296d9a
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_liability.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_liability.png
new file mode 100644
index 0000000..b28cb08
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_liability.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_loan.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_loan.png
new file mode 100644
index 0000000..1dbd958
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/account-types_savings.png b/kmymoney2/icons/oxygen/16x16/actions/account-types_savings.png
new file mode 100644
index 0000000..444088b
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/accounts.png b/kmymoney2/icons/oxygen/16x16/actions/accounts.png
new file mode 100644
index 0000000..5c2c5b2
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/budget.png b/kmymoney2/icons/oxygen/16x16/actions/budget.png
new file mode 100644
index 0000000..2234dae
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/budget.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/forcast.png b/kmymoney2/icons/oxygen/16x16/actions/forcast.png
new file mode 100644
index 0000000..0685923
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/institutions.png b/kmymoney2/icons/oxygen/16x16/actions/institutions.png
new file mode 100644
index 0000000..5dd8bd0
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/investments.png b/kmymoney2/icons/oxygen/16x16/actions/investments.png
new file mode 100644
index 0000000..9296d9a
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/ledger.png b/kmymoney2/icons/oxygen/16x16/actions/ledger.png
new file mode 100644
index 0000000..9f9ee21
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/onlinebanking.png b/kmymoney2/icons/oxygen/16x16/actions/onlinebanking.png
new file mode 100644
index 0000000..a15e2b1
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/payee.png b/kmymoney2/icons/oxygen/16x16/actions/payee.png
new file mode 100644
index 0000000..2fc7a99
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/payee.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/report.png b/kmymoney2/icons/oxygen/16x16/actions/report.png
new file mode 100644
index 0000000..e1d833f
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/report.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/16x16/actions/schedule.png b/kmymoney2/icons/oxygen/16x16/actions/schedule.png
new file mode 100644
index 0000000..b8e106a
--- /dev/null
+++ b/kmymoney2/icons/oxygen/16x16/actions/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/Makefile.am b/kmymoney2/icons/oxygen/22x22/Makefile.am
new file mode 100644
index 0000000..2af9bf4
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = actions
diff --git a/kmymoney2/icons/oxygen/22x22/actions/Makefile.am b/kmymoney2/icons/oxygen/22x22/actions/Makefile.am
new file mode 100644
index 0000000..71e81ad
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/22x22/actions
+
+icon_DATA = accounts.png account-types_cash.png account-types_checking.png account-types_credit-card.png account-types_investments.png account-types_loan.png account-types_savings.png budget.png forcast.png institutions.png investments.png ledger.png onlinebanking.png payee.png report.png schedule.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/22x22/actions/account-types_cash.png b/kmymoney2/icons/oxygen/22x22/actions/account-types_cash.png
new file mode 100644
index 0000000..f59a6f8
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/account-types_cash.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/account-types_checking.png b/kmymoney2/icons/oxygen/22x22/actions/account-types_checking.png
new file mode 100644
index 0000000..94c7ed3
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/account-types_checking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/account-types_credit-card.png b/kmymoney2/icons/oxygen/22x22/actions/account-types_credit-card.png
new file mode 100644
index 0000000..ba62cb7
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/account-types_credit-card.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/account-types_investments.png b/kmymoney2/icons/oxygen/22x22/actions/account-types_investments.png
new file mode 100644
index 0000000..6436870
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/account-types_investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/account-types_loan.png b/kmymoney2/icons/oxygen/22x22/actions/account-types_loan.png
new file mode 100644
index 0000000..3600c8d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/account-types_loan.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/account-types_savings.png b/kmymoney2/icons/oxygen/22x22/actions/account-types_savings.png
new file mode 100644
index 0000000..6dc8194
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/account-types_savings.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/accounts.png b/kmymoney2/icons/oxygen/22x22/actions/accounts.png
new file mode 100644
index 0000000..d71e2c2
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/budget.png b/kmymoney2/icons/oxygen/22x22/actions/budget.png
new file mode 100644
index 0000000..9720dc4
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/budget.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/forcast.png b/kmymoney2/icons/oxygen/22x22/actions/forcast.png
new file mode 100644
index 0000000..f8f6fce
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/institutions.png b/kmymoney2/icons/oxygen/22x22/actions/institutions.png
new file mode 100644
index 0000000..06e2edc
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/investments.png b/kmymoney2/icons/oxygen/22x22/actions/investments.png
new file mode 100644
index 0000000..6436870
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/ledger.png b/kmymoney2/icons/oxygen/22x22/actions/ledger.png
new file mode 100644
index 0000000..6d67daa
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/onlinebanking.png b/kmymoney2/icons/oxygen/22x22/actions/onlinebanking.png
new file mode 100644
index 0000000..aa8efea
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/payee.png b/kmymoney2/icons/oxygen/22x22/actions/payee.png
new file mode 100644
index 0000000..3d669e6
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/payee.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/report.png b/kmymoney2/icons/oxygen/22x22/actions/report.png
new file mode 100644
index 0000000..d6c319d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/report.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/22x22/actions/schedule.png b/kmymoney2/icons/oxygen/22x22/actions/schedule.png
new file mode 100644
index 0000000..0fe35ad
--- /dev/null
+++ b/kmymoney2/icons/oxygen/22x22/actions/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/Makefile.am b/kmymoney2/icons/oxygen/32x32/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/oxygen/32x32/apps/Makefile.am b/kmymoney2/icons/oxygen/32x32/apps/Makefile.am
new file mode 100644
index 0000000..ef08a86
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/32x32/apps
+
+icon_DATA = account_add.png account-types_closed.png account-types_expense.png account-types_income.png institution_add.png reconcile.png transaction_find.png report.png budget.png ledger.png accounts.png forcast.png onlinebanking.png investments.png schedule.png categories.png payee.png institutions.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/32x32/apps/account-types_closed.png b/kmymoney2/icons/oxygen/32x32/apps/account-types_closed.png
new file mode 100644
index 0000000..14c3bb2
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/account-types_expense.png b/kmymoney2/icons/oxygen/32x32/apps/account-types_expense.png
new file mode 100644
index 0000000..47412a2
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/account-types_income.png b/kmymoney2/icons/oxygen/32x32/apps/account-types_income.png
new file mode 100644
index 0000000..e62a0e2
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/account_add.png b/kmymoney2/icons/oxygen/32x32/apps/account_add.png
new file mode 100644
index 0000000..fabdcbc
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/accounts.png b/kmymoney2/icons/oxygen/32x32/apps/accounts.png
new file mode 100644
index 0000000..6745ef4
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/budget.png b/kmymoney2/icons/oxygen/32x32/apps/budget.png
new file mode 100644
index 0000000..943b9f6
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/categories.png b/kmymoney2/icons/oxygen/32x32/apps/categories.png
new file mode 100644
index 0000000..8a07415
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/forcast.png b/kmymoney2/icons/oxygen/32x32/apps/forcast.png
new file mode 100644
index 0000000..bf45b5c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/institution_add.png b/kmymoney2/icons/oxygen/32x32/apps/institution_add.png
new file mode 100644
index 0000000..114e171
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/institutions.png b/kmymoney2/icons/oxygen/32x32/apps/institutions.png
new file mode 100644
index 0000000..85cb0df
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/investments.png b/kmymoney2/icons/oxygen/32x32/apps/investments.png
new file mode 100644
index 0000000..7ffc1c3
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/ledger.png b/kmymoney2/icons/oxygen/32x32/apps/ledger.png
new file mode 100644
index 0000000..33bb0be
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/onlinebanking.png b/kmymoney2/icons/oxygen/32x32/apps/onlinebanking.png
new file mode 100644
index 0000000..5a3ec01
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/payee.png b/kmymoney2/icons/oxygen/32x32/apps/payee.png
new file mode 100644
index 0000000..3ce240f
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/reconcile.png b/kmymoney2/icons/oxygen/32x32/apps/reconcile.png
new file mode 100644
index 0000000..01ae342
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/report.png b/kmymoney2/icons/oxygen/32x32/apps/report.png
new file mode 100644
index 0000000..e08a6b2
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/schedule.png b/kmymoney2/icons/oxygen/32x32/apps/schedule.png
new file mode 100644
index 0000000..7d144b7
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/32x32/apps/transaction_find.png b/kmymoney2/icons/oxygen/32x32/apps/transaction_find.png
new file mode 100644
index 0000000..0761a3a
--- /dev/null
+++ b/kmymoney2/icons/oxygen/32x32/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/Makefile.am b/kmymoney2/icons/oxygen/48x48/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/oxygen/48x48/apps/Makefile.am b/kmymoney2/icons/oxygen/48x48/apps/Makefile.am
new file mode 100644
index 0000000..49b0488
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/48x48/apps
+
+icon_DATA = account_add.png account-types_closed.png account-types_expense.png account-types_income.png institution_add.png reconcile.png transaction_find.png report.png budget.png ledger.png accounts.png forcast.png onlinebanking.png investments.png schedule.png categories.png payee.png institutions.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/48x48/apps/account-types_closed.png b/kmymoney2/icons/oxygen/48x48/apps/account-types_closed.png
new file mode 100644
index 0000000..be93882
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/account-types_expense.png b/kmymoney2/icons/oxygen/48x48/apps/account-types_expense.png
new file mode 100644
index 0000000..d768b20
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/account-types_expense.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/account-types_income.png b/kmymoney2/icons/oxygen/48x48/apps/account-types_income.png
new file mode 100644
index 0000000..77b8919
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/account-types_income.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/account_add.png b/kmymoney2/icons/oxygen/48x48/apps/account_add.png
new file mode 100644
index 0000000..4d2ed78
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/account_add.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/accounts.png b/kmymoney2/icons/oxygen/48x48/apps/accounts.png
new file mode 100644
index 0000000..089b9ee
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/budget.png b/kmymoney2/icons/oxygen/48x48/apps/budget.png
new file mode 100644
index 0000000..2bb6ace
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/categories.png b/kmymoney2/icons/oxygen/48x48/apps/categories.png
new file mode 100644
index 0000000..6c6954f
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/forcast.png b/kmymoney2/icons/oxygen/48x48/apps/forcast.png
new file mode 100644
index 0000000..047caa0
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/institution_add.png b/kmymoney2/icons/oxygen/48x48/apps/institution_add.png
new file mode 100644
index 0000000..3b4f0ed
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/institution_add.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/institutions.png b/kmymoney2/icons/oxygen/48x48/apps/institutions.png
new file mode 100644
index 0000000..ac82c53
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/investments.png b/kmymoney2/icons/oxygen/48x48/apps/investments.png
new file mode 100644
index 0000000..c7ebb67
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/ledger.png b/kmymoney2/icons/oxygen/48x48/apps/ledger.png
new file mode 100644
index 0000000..7ac3aed
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/onlinebanking.png b/kmymoney2/icons/oxygen/48x48/apps/onlinebanking.png
new file mode 100644
index 0000000..a24e339
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/payee.png b/kmymoney2/icons/oxygen/48x48/apps/payee.png
new file mode 100644
index 0000000..9e121f1
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/reconcile.png b/kmymoney2/icons/oxygen/48x48/apps/reconcile.png
new file mode 100644
index 0000000..063b7e7
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/report.png b/kmymoney2/icons/oxygen/48x48/apps/report.png
new file mode 100644
index 0000000..583f340
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/schedule.png b/kmymoney2/icons/oxygen/48x48/apps/schedule.png
new file mode 100644
index 0000000..80d890d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/48x48/apps/transaction_find.png b/kmymoney2/icons/oxygen/48x48/apps/transaction_find.png
new file mode 100644
index 0000000..922eb4c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/48x48/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/Makefile.am b/kmymoney2/icons/oxygen/64x64/Makefile.am
new file mode 100644
index 0000000..284a700
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps
diff --git a/kmymoney2/icons/oxygen/64x64/apps/Makefile.am b/kmymoney2/icons/oxygen/64x64/apps/Makefile.am
new file mode 100644
index 0000000..8e64c24
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/64x64/apps
+
+icon_DATA = account-add.png account-types_closed.png reconcile.png transaction_find.png report.png budget.png ledger.png accounts.png forcast.png onlinebanking.png investments.png schedule.png categories.png payee.png institutions.png
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/64x64/apps/account-add.png b/kmymoney2/icons/oxygen/64x64/apps/account-add.png
new file mode 100644
index 0000000..58a6219
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/account-add.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/account-types_closed.png b/kmymoney2/icons/oxygen/64x64/apps/account-types_closed.png
new file mode 100644
index 0000000..912a531
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/account-types_closed.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/accounts.png b/kmymoney2/icons/oxygen/64x64/apps/accounts.png
new file mode 100644
index 0000000..10d5da1
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/accounts.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/budget.png b/kmymoney2/icons/oxygen/64x64/apps/budget.png
new file mode 100644
index 0000000..a0d5753
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/budget.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/categories.png b/kmymoney2/icons/oxygen/64x64/apps/categories.png
new file mode 100644
index 0000000..8d225bb
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/categories.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/forcast.png b/kmymoney2/icons/oxygen/64x64/apps/forcast.png
new file mode 100644
index 0000000..17e3c98
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/forcast.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/institutions.png b/kmymoney2/icons/oxygen/64x64/apps/institutions.png
new file mode 100644
index 0000000..52a5cc0
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/institutions.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/investments.png b/kmymoney2/icons/oxygen/64x64/apps/investments.png
new file mode 100644
index 0000000..94d06c8
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/investments.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/ledger.png b/kmymoney2/icons/oxygen/64x64/apps/ledger.png
new file mode 100644
index 0000000..dbfb0a4
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/ledger.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/onlinebanking.png b/kmymoney2/icons/oxygen/64x64/apps/onlinebanking.png
new file mode 100644
index 0000000..dc7cca1
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/onlinebanking.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/payee.png b/kmymoney2/icons/oxygen/64x64/apps/payee.png
new file mode 100644
index 0000000..320bc71
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/payee.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/reconcile.png b/kmymoney2/icons/oxygen/64x64/apps/reconcile.png
new file mode 100644
index 0000000..6c92d5d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/reconcile.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/report.png b/kmymoney2/icons/oxygen/64x64/apps/report.png
new file mode 100644
index 0000000..3da4358
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/report.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/schedule.png b/kmymoney2/icons/oxygen/64x64/apps/schedule.png
new file mode 100644
index 0000000..54e63fe
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/schedule.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/64x64/apps/transaction_find.png b/kmymoney2/icons/oxygen/64x64/apps/transaction_find.png
new file mode 100644
index 0000000..b1f40da
--- /dev/null
+++ b/kmymoney2/icons/oxygen/64x64/apps/transaction_find.png
Binary files differ
diff --git a/kmymoney2/icons/oxygen/Makefile.am b/kmymoney2/icons/oxygen/Makefile.am
new file mode 100644
index 0000000..a088af8
--- /dev/null
+++ b/kmymoney2/icons/oxygen/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = 16x16 48x48 32x32 128x128 scalable 64x64 22x22
diff --git a/kmymoney2/icons/oxygen/scalable/Makefile.am b/kmymoney2/icons/oxygen/scalable/Makefile.am
new file mode 100644
index 0000000..4953a83
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/Makefile.am
@@ -0,0 +1,6 @@
+icondir=$(kde_icondir)/oxygen/scalable
+
+icon_DATA = account-add.svgz accounts.svgz account-types_asset.svgz account-types_checking.svgz account-types_cash.svgz account-types_closed.svgz account-types_credit-card.svgz account-types_expense.svgz account-types_income.svgz account-types_investments.svgz account-types_liability.svgz account-types_loan.svgz account-types_savings.svgz budget.svgz categories.svgz forcast.svgz hide_categories.svgz hide_reconciled.svgz institution_add.svgz institutions.svgz investments.svgz ledger.svgz onlinebanking.svgz payee.svgz personal_data.svgz reconcile.svgz report.svgz schedule.svgz transaction_find.svgz
+
+EXTRA_DIST = $(icon_DATA)
+
diff --git a/kmymoney2/icons/oxygen/scalable/account-add.svgz b/kmymoney2/icons/oxygen/scalable/account-add.svgz
new file mode 100644
index 0000000..ebd43f0
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-add.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_asset.svgz b/kmymoney2/icons/oxygen/scalable/account-types_asset.svgz
new file mode 100644
index 0000000..5d72b8f
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_asset.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_cash.svgz b/kmymoney2/icons/oxygen/scalable/account-types_cash.svgz
new file mode 100644
index 0000000..ca891a3
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_cash.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_checking.svgz b/kmymoney2/icons/oxygen/scalable/account-types_checking.svgz
new file mode 100644
index 0000000..8102c31
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_checking.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_closed.svgz b/kmymoney2/icons/oxygen/scalable/account-types_closed.svgz
new file mode 100644
index 0000000..64e1ad8
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_closed.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_credit-card.svgz b/kmymoney2/icons/oxygen/scalable/account-types_credit-card.svgz
new file mode 100644
index 0000000..efea607
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_credit-card.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_expense.svgz b/kmymoney2/icons/oxygen/scalable/account-types_expense.svgz
new file mode 100644
index 0000000..16d1370
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_expense.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_income.svgz b/kmymoney2/icons/oxygen/scalable/account-types_income.svgz
new file mode 100644
index 0000000..74f6575
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_income.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_investments.svgz b/kmymoney2/icons/oxygen/scalable/account-types_investments.svgz
new file mode 100644
index 0000000..5d49b27
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_investments.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_liability.svgz b/kmymoney2/icons/oxygen/scalable/account-types_liability.svgz
new file mode 100644
index 0000000..af9a682
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_liability.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_loan.svgz b/kmymoney2/icons/oxygen/scalable/account-types_loan.svgz
new file mode 100644
index 0000000..24b0f41
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_loan.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/account-types_savings.svgz b/kmymoney2/icons/oxygen/scalable/account-types_savings.svgz
new file mode 100644
index 0000000..d10fe7e
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/account-types_savings.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/accounts.svgz b/kmymoney2/icons/oxygen/scalable/accounts.svgz
new file mode 100644
index 0000000..961ba6d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/accounts.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/budget.svgz b/kmymoney2/icons/oxygen/scalable/budget.svgz
new file mode 100644
index 0000000..9c7e78d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/budget.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/categories.svgz b/kmymoney2/icons/oxygen/scalable/categories.svgz
new file mode 100644
index 0000000..588dd39
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/categories.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/forcast.svgz b/kmymoney2/icons/oxygen/scalable/forcast.svgz
new file mode 100644
index 0000000..84aca85
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/forcast.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/hide_categories.svgz b/kmymoney2/icons/oxygen/scalable/hide_categories.svgz
new file mode 100644
index 0000000..a3280fa
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/hide_categories.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/hide_reconciled.svgz b/kmymoney2/icons/oxygen/scalable/hide_reconciled.svgz
new file mode 100644
index 0000000..ccd94a6
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/hide_reconciled.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/institution_add.svgz b/kmymoney2/icons/oxygen/scalable/institution_add.svgz
new file mode 100644
index 0000000..745bfc8
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/institution_add.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/institutions.svgz b/kmymoney2/icons/oxygen/scalable/institutions.svgz
new file mode 100644
index 0000000..e38ca0e
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/institutions.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/investments.svgz b/kmymoney2/icons/oxygen/scalable/investments.svgz
new file mode 100644
index 0000000..5d49b27
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/investments.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/ledger.svgz b/kmymoney2/icons/oxygen/scalable/ledger.svgz
new file mode 100644
index 0000000..2128284
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/ledger.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/onlinebanking.svgz b/kmymoney2/icons/oxygen/scalable/onlinebanking.svgz
new file mode 100644
index 0000000..928c46c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/onlinebanking.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/payee.svgz b/kmymoney2/icons/oxygen/scalable/payee.svgz
new file mode 100644
index 0000000..9287d85
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/payee.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/personal_data.svgz b/kmymoney2/icons/oxygen/scalable/personal_data.svgz
new file mode 100644
index 0000000..7a5b34d
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/personal_data.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/reconcile.svgz b/kmymoney2/icons/oxygen/scalable/reconcile.svgz
new file mode 100644
index 0000000..a4b501e
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/reconcile.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/report.svgz b/kmymoney2/icons/oxygen/scalable/report.svgz
new file mode 100644
index 0000000..e2c46b6
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/report.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/schedule.svgz b/kmymoney2/icons/oxygen/scalable/schedule.svgz
new file mode 100644
index 0000000..c725c9c
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/schedule.svgz
Binary files differ
diff --git a/kmymoney2/icons/oxygen/scalable/transaction_find.svgz b/kmymoney2/icons/oxygen/scalable/transaction_find.svgz
new file mode 100644
index 0000000..a74f620
--- /dev/null
+++ b/kmymoney2/icons/oxygen/scalable/transaction_find.svgz
Binary files differ
diff --git a/kmymoney2/kmymoney2.cpp b/kmymoney2/kmymoney2.cpp
new file mode 100644
index 0000000..40cc1d6
--- /dev/null
+++ b/kmymoney2/kmymoney2.cpp
@@ -0,0 +1,6209 @@
+/***************************************************************************
+ kmymoney2.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ (C) 2007 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// Std C++ / STL Includes
+
+#include <typeinfo>
+#include <cstdio>
+#include <iostream>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdir.h>
+#include <qprinter.h>
+#include <qlayout.h>
+#include <qsignalmapper.h>
+#include <qclipboard.h> // temp for problem 1105503
+#include <qdatetime.h> // only for performance tests
+#include <qtimer.h>
+#include <qsqlpropertymap.h>
+#include <qvbox.h>
+#include <qeventloop.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kshortcut.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kstatusbar.h>
+#include <ktip.h>
+#include <kkeydialog.h>
+#include <kprogress.h>
+#include <kio/netaccess.h>
+#include <dcopclient.h>
+#include <kstartupinfo.h>
+#include <kparts/componentfactory.h>
+#include <krun.h>
+#include <kconfigdialog.h>
+#include <kinputdialog.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoney2.h"
+#include "kmymoneyglobalsettings.h"
+#include "kmymoney2_stub.h"
+
+#include "dialogs/kstartdlg.h"
+#include "dialogs/settings/ksettingsgeneral.h"
+#include "dialogs/settings/ksettingsregister.h"
+#include "dialogs/settings/ksettingsgpg.h"
+#include "dialogs/settings/ksettingscolors.h"
+#include "dialogs/settings/ksettingsfonts.h"
+#include "dialogs/settings/ksettingsschedules.h"
+#include "dialogs/settings/ksettingsonlinequotes.h"
+#include "dialogs/settings/ksettingshome.h"
+#include "dialogs/settings/ksettingsforecast.h"
+#include "dialogs/settings/ksettingsplugins.h"
+#include "dialogs/kbackupdlg.h"
+#include "dialogs/kexportdlg.h"
+#include "dialogs/kimportdlg.h"
+#include "dialogs/mymoneyqifprofileeditor.h"
+#include "dialogs/kenterscheduledlg.h"
+#include "dialogs/kconfirmmanualenterdlg.h"
+#include "dialogs/kmymoneypricedlg.h"
+#include "dialogs/kcurrencyeditdlg.h"
+#include "dialogs/kequitypriceupdatedlg.h"
+#include "dialogs/ksecuritylisteditor.h"
+#include "dialogs/kmymoneyfileinfodlg.h"
+#include "dialogs/kfindtransactiondlg.h"
+#include "dialogs/knewbankdlg.h"
+#include "dialogs/knewinvestmentwizard.h"
+#include "dialogs/knewaccountdlg.h"
+#include "dialogs/knewfiledlg.h"
+#include "dialogs/kselectdatabasedlg.h"
+#include "dialogs/kcurrencycalculator.h"
+#include "dialogs/keditscheduledlg.h"
+#include "dialogs/knewloanwizard.h"
+#include "dialogs/keditloanwizard.h"
+#include "dialogs/kpayeereassigndlg.h"
+#include "dialogs/kcategoryreassigndlg.h"
+#include "dialogs/kmergetransactionsdlg.h"
+#include "dialogs/kendingbalancedlg.h"
+#include "dialogs/kbalancechartdlg.h"
+#include "dialogs/kplugindlg.h"
+#include "dialogs/kloadtemplatedlg.h"
+#include "dialogs/kgpgkeyselectiondlg.h"
+#include "dialogs/transactionmatcher.h"
+#include "wizards/newuserwizard/knewuserwizard.h"
+#include "wizards/newaccountwizard/knewaccountwizard.h"
+#include "dialogs/kbalancewarning.h"
+
+#include "widgets/kmymoneycombo.h"
+#include "widgets/kmymoneycompletion.h"
+
+#include "views/kmymoneyview.h"
+
+#include "mymoney/mymoneyutils.h"
+#include "mymoney/mymoneystatement.h"
+#include "mymoney/storage/mymoneystoragedump.h"
+#include "mymoney/mymoneyforecast.h"
+
+#include "converter/mymoneyqifwriter.h"
+#include "converter/mymoneyqifreader.h"
+#include "converter/mymoneystatementreader.h"
+#include "converter/mymoneytemplate.h"
+
+#include "plugins/interfaces/kmmviewinterface.h"
+#include "plugins/interfaces/kmmstatementinterface.h"
+#include "plugins/interfaces/kmmimportinterface.h"
+#include "plugins/pluginloader.h"
+
+#include <libkgpgfile/kgpgfile.h>
+
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/kmymoneylistviewitem.h>
+
+#include "kmymoneyutils.h"
+#include "kdecompat.h"
+
+#define RECOVER_KEY_ID "59B0F826D2B08440"
+#define ID_STATUS_MSG 1
+
+class KMyMoney2App::Private
+{
+public:
+ Private() :
+ m_ft(0), m_moveToAccountSelector(0), statementXMLindex(0), m_collectingStatements(false)
+ {}
+ void unlinkStatementXML(void);
+ void moveInvestmentTransaction(const QString& fromId,
+ const QString& toId,
+ const MyMoneyTransaction& t);
+
+ MyMoneyFileTransaction* m_ft;
+ kMyMoneyAccountSelector* m_moveToAccountSelector;
+ int statementXMLindex;
+ KBalanceWarning* m_balanceWarning;
+
+ bool m_collectingStatements;
+ QStringList m_statementResults;
+ KMyMoneyPlugin::PluginLoader* m_pluginLoader;
+ QString m_lastPayeeEntered;
+};
+
+KMyMoney2App::KMyMoney2App(QWidget * /*parent*/ , const char* name) :
+ KMainWindow(0, name),
+ DCOPObject("kmymoney2app"),
+ d(new Private),
+ myMoneyView(0),
+ m_searchDlg(0),
+ m_autoSaveTimer(0),
+ m_inAutoSaving(false),
+ m_saveEncrypted(0),
+ m_transactionEditor(0),
+ m_endingBalanceDlg(0)
+{
+ ::timetrace("start kmymoney2app constructor");
+ // preset the pointer because we need it during the course of this constructor
+ kmymoney2 = this;
+ config = kapp->config();
+
+ MyMoneyTransactionFilter::setFiscalYearStart(KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay());
+
+ updateCaption(true);
+
+ QFrame* frame = new QFrame(this);
+ frame->setFrameStyle(QFrame::NoFrame);
+ // values for margin (11) and spacing(6) taken from KDialog implementation
+ QBoxLayout* layout = new QBoxLayout(frame, QBoxLayout::TopToBottom, 2, 6);
+
+ ::timetrace("init statusbar");
+ initStatusBar();
+ ::timetrace("init actions");
+ initActions();
+
+ initDynamicMenus();
+
+ ::timetrace("create view");
+ myMoneyView = new KMyMoneyView(frame, "KMyMoneyView");
+ layout->addWidget(myMoneyView, 10);
+ connect(myMoneyView, SIGNAL(aboutToShowPage(QWidget*)), this, SLOT(slotResetSelections()));
+
+ ///////////////////////////////////////////////////////////////////
+ // call inits to invoke all other construction parts
+ ::timetrace("init options");
+ readOptions();
+
+#if 0
+ m_pluginSignalMapper = new QSignalMapper( this );
+ connect( m_pluginSignalMapper, SIGNAL( mapped( const QString& ) ), this, SLOT( slotPluginImport( const QString& ) ) );
+#endif
+
+ // now initialize the plugin structure
+ ::timetrace("load plugins");
+ createInterfaces();
+ loadPlugins();
+
+ setCentralWidget(frame);
+
+ ::timetrace("done");
+
+ connect(&proc,SIGNAL(processExited(KProcess *)),this,SLOT(slotProcessExited()));
+
+ // force to show the home page if the file is closed
+ connect(action("view_show_transaction_detail"), SIGNAL(toggled(bool)), myMoneyView, SLOT(slotShowTransactionDetail(bool)));
+
+ m_backupState = BACKUP_IDLE;
+
+ m_qifReader = 0;
+ m_smtReader = 0;
+
+ m_autoSaveEnabled = KMyMoneyGlobalSettings::autoSaveFile();
+ m_autoSavePeriod = KMyMoneyGlobalSettings::autoSavePeriod();
+
+ m_autoSaveTimer = new QTimer(this);
+ connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
+
+ // make sure, we get a note when the engine changes state
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotDataChanged()));
+
+ // make sure we have a balance warning object
+ d->m_balanceWarning = new KBalanceWarning(this);
+
+ // kickstart date change timer
+ slotDateChanged();
+}
+
+KMyMoney2App::~KMyMoney2App()
+{
+ delete m_searchDlg;
+ delete m_qifReader;
+ delete m_transactionEditor;
+ delete m_endingBalanceDlg;
+ delete d->m_moveToAccountSelector;
+ delete d;
+ delete myMoneyView;
+}
+
+const KURL KMyMoney2App::lastOpenedURL(void)
+{
+ KURL url = m_startDialog ? KURL() : m_fileName;
+
+ if(!url.isValid())
+ {
+ url = readLastUsedFile();
+ }
+
+ ready();
+
+ return url;
+}
+
+void KMyMoney2App::initDynamicMenus(void)
+{
+ QWidget* w = factory()->container("transaction_move_menu", this);
+ QPopupMenu *menu = dynamic_cast<QPopupMenu*>(w);
+ if(menu) {
+ d->m_moveToAccountSelector = new kMyMoneyAccountSelector(menu, 0, 0, false);
+ menu->insertItem(d->m_moveToAccountSelector);
+ connect(d->m_moveToAccountSelector, SIGNAL(itemSelected(const QString&)), this, SLOT(slotMoveToAccount(const QString&)));
+ connect(this, SIGNAL(accountSelected(const MyMoneyAccount&)), this, SLOT(slotUpdateMoveToAccountMenu()));
+ connect(this, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)), this, SLOT(slotUpdateMoveToAccountMenu()));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotUpdateMoveToAccountMenu()));
+ }
+}
+
+void KMyMoney2App::initActions(void)
+{
+ KAction* p;
+
+ // *************
+ // The File menu
+ // *************
+ KStdAction::openNew(this, SLOT(slotFileNew()), actionCollection());
+ KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
+ KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection());
+ KStdAction::save(this, SLOT(slotFileSave()), actionCollection());
+ KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
+ KStdAction::close(this, SLOT(slotFileClose()), actionCollection());
+ KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection());
+ KStdAction::print(this, SLOT(slotPrintView()), actionCollection());
+
+ new KAction(i18n("Open database..."), "",0,this,SLOT(slotOpenDatabase()),actionCollection(),"open_database");
+ new KAction(i18n("Save as database..."), "",0,this,SLOT(slotSaveAsDatabase()),actionCollection(),"saveas_database");
+ new KAction(i18n("Backup..."), "backup",0,this,SLOT(slotFileBackup()),actionCollection(),"file_backup");
+ new KAction(i18n("QIF..."), "", 0, this, SLOT(slotQifImport()), actionCollection(), "file_import_qif");
+ new KAction(i18n("Gnucash..."), "", 0, this, SLOT(slotGncImport()), actionCollection(), "file_import_gnc");
+ new KAction(i18n("Statement file..."), "", 0, this, SLOT(slotStatementImport()), actionCollection(), "file_import_statement");
+
+ new KAction(i18n("Account Template..."), "", 0, this, SLOT(slotLoadAccountTemplates()), actionCollection(), "file_import_template");
+ new KAction(i18n("Account Template..."), "", 0, this, SLOT(slotSaveAccountTemplates()), actionCollection(), "file_export_template");
+ new KAction(i18n("QIF..."), "", 0, this, SLOT(slotQifExport()), actionCollection(), "file_export_qif");
+ new KAction(i18n("Personal Data..."), "personal_data", 0, this, SLOT(slotFileViewPersonal()), actionCollection(), "view_personal_data");
+
+#if KMM_DEBUG
+ new KAction(i18n("Dump Memory"), "", 0, this, SLOT(slotFileFileInfo()), actionCollection(), "file_dump");
+#endif
+ new KAction(i18n("File-Information..."), "info", 0, this, SLOT(slotFileInfoDialog()), actionCollection(), "view_file_info");
+
+ // *************
+ // The Edit menu
+ // *************
+ new KAction(i18n("Find transaction..."), "transaction_find", KShortcut("Ctrl+F"), this, SLOT(slotFindTransaction()), actionCollection(), "edit_find_transaction");
+
+ // *************
+ // The View menu
+ // *************
+ new KToggleAction(i18n("Show Transaction Detail"), KShortcut("Ctrl+T"), actionCollection(), "view_show_transaction_detail");
+ new KToggleAction(i18n("Hide reconciled transactions"), "hide_reconciled", KShortcut("Ctrl+R"), this, SLOT(slotHideReconciledTransactions()), actionCollection(), "view_hide_reconciled_transactions");
+ new KToggleAction(i18n("Hide unused categories"), "hide_categories", KShortcut("Ctrl+U"), this, SLOT(slotHideUnusedCategories()), actionCollection(), "view_hide_unused_categories");
+ new KToggleAction(i18n("Show all accounts"), "", KShortcut("Ctrl+Shift+A"), this, SLOT(slotShowAllAccounts()), actionCollection(), "view_show_all_accounts");
+
+ // *********************
+ // The institutions menu
+ // *********************
+ new KAction(i18n("New institution..."), "institution_add", 0, this, SLOT(slotInstitutionNew()), actionCollection(), "institution_new");
+ new KAction(i18n("Edit institution..."), "edit", 0, this, SLOT(slotInstitutionEdit()), actionCollection(), "institution_edit");
+ new KAction(i18n("Delete institution..."), "delete", 0, this, SLOT(slotInstitutionDelete()), actionCollection(), "institution_delete");
+
+ // *****************
+ // The accounts menu
+ // *****************
+ new KAction(i18n("New account..."), "account_add", 0, this, SLOT(slotAccountNew()), actionCollection(), "account_new");
+ // note : action "category_new" is included in this menu but defined below
+ new KAction(i18n("Open ledger"), "ledger", 0, this, SLOT(slotAccountOpen()), actionCollection(), "account_open");
+ new KAction(i18n("Reconcile..."), "reconcile", KShortcut("Ctrl+Shift+R"), this, SLOT(slotAccountReconcileStart()), actionCollection(), "account_reconcile");
+ new KAction(i18n("Finish reconciliation", "Finish"), "player_end", 0, this, SLOT(slotAccountReconcileFinish()), actionCollection(), "account_reconcile_finish");
+ new KAction(i18n("Postpone reconciliation", "Postpone"), "player_pause", 0, this, SLOT(slotAccountReconcilePostpone()), actionCollection(), "account_reconcile_postpone");
+ new KAction(i18n("Edit account..."), "edit", 0, this, SLOT(slotAccountEdit()), actionCollection(), "account_edit");
+ new KAction(i18n("Delete account..."), "delete", 0, this, SLOT(slotAccountDelete()), actionCollection(), "account_delete");
+ new KAction(i18n("Close account"), "", 0, this, SLOT(slotAccountClose()), actionCollection(), "account_close");
+ new KAction(i18n("Reopen account"), "", 0, this, SLOT(slotAccountReopen()), actionCollection(), "account_reopen");
+ new KAction(i18n("Transaction report"), "view_info", 0, this, SLOT(slotAccountTransactionReport()), actionCollection(), "account_transaction_report");
+#ifdef HAVE_KDCHART
+ new KAction(i18n("Show balance chart..."), "kchart_chrt", 0, this, SLOT(slotAccountChart()), actionCollection(), "account_chart");
+#endif
+ new KAction(i18n("Map to online account"), "news_subscribe", 0, this, SLOT(slotAccountMapOnline()), actionCollection(), "account_online_map");
+ new KAction(i18n("Unmap account"), "", 0, this, SLOT(slotAccountUnmapOnline()), actionCollection(), "account_online_unmap");
+ KActionMenu* menu = new KActionMenu(i18n("Update"), QIconSet(KGlobal::iconLoader()->loadIcon("reload", KIcon::Small,
+ KIcon::SizeSmall)), actionCollection(), "account_online_update_menu");
+ // activating the menu button is the same as selecting the current account
+ connect( menu, SIGNAL( activated() ), this, SLOT(slotAccountUpdateOnline()));
+ menu->insert(new KAction(i18n("Update account..."), "", 0, this, SLOT(slotAccountUpdateOnline()), actionCollection(), "account_online_update"));
+ menu->insert(new KAction(i18n("Update all accounts..."), "", 0, this, SLOT(slotAccountUpdateOnlineAll()), actionCollection(), "account_online_update_all"));
+
+ // *******************
+ // The categories menu
+ // *******************
+ new KAction(i18n("New category..."), "account_add", 0, this, SLOT(slotCategoryNew()), actionCollection(), "category_new");
+ new KAction(i18n("Edit category..."), "edit", 0, this, SLOT(slotAccountEdit()), actionCollection(), "category_edit");
+ new KAction(i18n("Delete category..."), "delete", 0, this, SLOT(slotAccountDelete()), actionCollection(), "category_delete");
+
+
+ // **************
+ // The tools menu
+ // **************
+ new KAction(i18n("QIF Profile Editor..."), "edit", 0, this, SLOT(slotQifProfileEditor()), actionCollection(), "tools_qif_editor");
+ new KAction(i18n("Securities..."), "", 0, this, SLOT(slotSecurityEditor()), actionCollection(), "tools_security_editor");
+ new KAction(i18n("Currencies..."), "", 0, this, SLOT(slotCurrencyDialog()), actionCollection(), "tools_currency_editor");
+ new KAction(i18n("Prices..."), "", 0, this, SLOT(slotPriceDialog()), actionCollection(), "tools_price_editor");
+ new KAction(i18n("Update Stock and Currency Prices..."), "", 0, this, SLOT(slotEquityPriceUpdate()), actionCollection(), "tools_update_prices");
+ new KAction(i18n("Consistency Check"), "", 0, this, SLOT(slotFileConsitencyCheck()), actionCollection(), "tools_consistency_check");
+ new KAction(i18n("Performance-Test"), "fork", 0, this, SLOT(slotPerformanceTest()), actionCollection(), "tools_performancetest");
+ new KAction(i18n("KCalc..."), "kcalc", 0, this, SLOT(slotToolsStartKCalc()), actionCollection(), "tools_kcalc");
+
+ // *****************
+ // The settings menu
+ // *****************
+ KStdAction::preferences(this, SLOT( slotSettings() ), actionCollection());
+ new KAction(i18n("Enable all messages"), "", 0, this, SLOT(slotEnableMessages()), actionCollection(), "settings_enable_messages");
+ new KAction(i18n("KDE language settings..."), "", 0, this, SLOT(slotKDELanguageSettings()), actionCollection(), "settings_language");
+
+ // *************
+ // The help menu
+ // *************
+ new KAction(i18n("&Show tip of the day"), "idea", 0, this, SLOT(slotShowTipOfTheDay()), actionCollection(), "help_show_tip");
+
+ // ***************************
+ // Actions w/o main menu entry
+ // ***************************
+ new KAction(i18n("New transaction button", "New"), "filenew", QKeySequence(Qt::CTRL | Qt::Key_Insert), this, SLOT(slotTransactionsNew()), actionCollection(), "transaction_new");
+
+ // we use Return as the same shortcut for Edit and Enter. Therefore, we don't allow
+ // to change them (The standard KDE dialog complains anyway if you want to assign
+ // the same shortcut to two actions)
+ p = new KAction(i18n("Edit transaction button", "Edit"), "edit", 0, this, SLOT(slotTransactionsEdit()), actionCollection(), "transaction_edit");
+ p->setShortcutConfigurable(false);
+ p = new KAction(i18n("Enter transaction", "Enter"), "button_ok", 0, this, SLOT(slotTransactionsEnter()), actionCollection(), "transaction_enter");
+ p->setShortcutConfigurable(false);
+
+ new KAction(i18n("Edit split button", "Edit splits"), "split_transaction", 0, this, SLOT(slotTransactionsEditSplits()), actionCollection(), "transaction_editsplits");
+ new KAction(i18n("Cancel transaction edit", "Cancel"), "button_cancel", 0, this, SLOT(slotTransactionsCancel()), actionCollection(), "transaction_cancel");
+ new KAction(i18n("Delete transaction", "Delete"), "delete", 0, this, SLOT(slotTransactionsDelete()), actionCollection(), "transaction_delete");
+ new KAction(i18n("Duplicate transaction", "Duplicate"), "editcopy", 0, this, SLOT(slotTransactionDuplicate()), actionCollection(), "transaction_duplicate");
+
+ new KAction(i18n("Button text for match transaction", "Match"), "stop", 0, this, SLOT(slotTransactionMatch()), actionCollection(), "transaction_match");
+ new KAction(i18n("Accept 'imported' and 'matched' transaction", "Accept"), "apply", 0, this, SLOT(slotTransactionsAccept()), actionCollection(), "transaction_accept");
+
+ new KAction(i18n("Toggle reconciliation flag", "Toggle"), 0, KShortcut("Ctrl+Space"), this, SLOT(slotToggleReconciliationFlag()), actionCollection(), "transaction_mark_toggle");
+ new KAction(i18n("Mark transaction cleared", "Cleared"), 0, KShortcut("Ctrl+Alt+Space"), this, SLOT(slotMarkTransactionCleared()), actionCollection(), "transaction_mark_cleared");
+ new KAction(i18n("Mark transaction reconciled", "Reconciled"), "", KShortcut("Ctrl+Shift+Space"), this, SLOT(slotMarkTransactionReconciled()), actionCollection(), "transaction_mark_reconciled");
+ new KAction(i18n("Mark transaction not reconciled", "Not reconciled"), "", 0, this, SLOT(slotMarkTransactionNotReconciled()), actionCollection(), "transaction_mark_notreconciled");
+ new KAction(i18n("Select all transactions", "Select all"), 0, KShortcut("Ctrl+A"), this, SIGNAL(selectAllTransactions()), actionCollection(), "transaction_select_all");
+
+ new KAction(i18n("Goto account"), "goto", 0, this, SLOT(slotTransactionGotoAccount()), actionCollection(), "transaction_goto_account");
+ new KAction(i18n("Goto payee"), "goto", 0, this, SLOT(slotTransactionGotoPayee()), actionCollection(), "transaction_goto_payee");
+ new KAction(i18n("Create scheduled transaction..."), "bookmark_add", 0, this, SLOT(slotTransactionCreateSchedule()), actionCollection(), "transaction_create_schedule");
+ new KAction(i18n("Assign next number"), "", KShortcut("Ctrl+Shift+N"), this, SLOT(slotTransactionAssignNumber()), actionCollection(), "transaction_assign_number");
+ new KAction(i18n("Combine transactions", "Combine"), "", 0, this, SLOT(slotTransactionCombine()), actionCollection(), "transaction_combine");
+
+ new KAction(i18n("New investment"), "filenew", 0, this, SLOT(slotInvestmentNew()), actionCollection(), "investment_new");
+ new KAction(i18n("Edit investment..."), "edit", 0, this, SLOT(slotInvestmentEdit()), actionCollection(), "investment_edit");
+ new KAction(i18n("Delete investment..."), "delete", 0, this, SLOT(slotInvestmentDelete()), actionCollection(), "investment_delete");
+ new KAction(i18n("Online price update..."), "", 0, this, SLOT(slotOnlinePriceUpdate()), actionCollection(), "investment_online_price_update");
+ new KAction(i18n("Manual price update..."), "", 0, this, SLOT(slotManualPriceUpdate()), actionCollection(), "investment_manual_price_update");
+
+ new KAction(i18n("New scheduled transaction..."), "filenew", 0, this, SLOT(slotScheduleNew()), actionCollection(), "schedule_new");
+ new KAction(i18n("Edit scheduled transaction..."), "edit", 0, this, SLOT(slotScheduleEdit()), actionCollection(), "schedule_edit");
+ new KAction(i18n("Delete scheduled transaction..."), "delete", 0, this, SLOT(slotScheduleDelete()), actionCollection(), "schedule_delete");
+ new KAction(i18n("Duplicate scheduled transaction"), "editcopy", 0, this, SLOT(slotScheduleDuplicate()), actionCollection(), "schedule_duplicate");
+ new KAction(i18n("Enter next transaction..."), "key_enter", 0, this, SLOT(slotScheduleEnter()), actionCollection(), "schedule_enter");
+ new KAction(i18n("Skip next transaction..."), "player_fwd", 0, this, SLOT(slotScheduleSkip()), actionCollection(), "schedule_skip");
+
+ new KAction(i18n("New payee"), "filenew", 0, this, SLOT(slotPayeeNew()), actionCollection(), "payee_new");
+ new KAction(i18n("Rename payee"), "edit", 0, this, SIGNAL(payeeRename()), actionCollection(), "payee_rename");
+ new KAction(i18n("Delete payee"), "delete", 0, this, SLOT(slotPayeeDelete()), actionCollection(), "payee_delete");
+
+ new KAction(i18n("New budget"), "filenew", 0, this, SLOT(slotBudgetNew()), actionCollection(), "budget_new");
+ new KAction(i18n("Rename budget"), "edit", 0, this, SIGNAL(budgetRename()), actionCollection(), "budget_rename");
+ new KAction(i18n("Delete budget"), "delete", 0, this, SLOT(slotBudgetDelete()), actionCollection(), "budget_delete");
+ new KAction(i18n("Copy budget"), "editcopy", 0, this, SLOT(slotBudgetCopy()), actionCollection(), "budget_copy");
+ new KAction(i18n("Change budget year"), "", 0, this, SLOT(slotBudgetChangeYear()), actionCollection(), "budget_change_year");
+ new KAction(i18n("Budget based on forecast", "Forecast"), "forcast", 0, this, SLOT(slotBudgetForecast()), actionCollection(), "budget_forecast");
+
+ // ************************
+ // Currency actions
+ // ************************
+ new KAction(i18n("New currency"), "filenew", 0, this, SLOT(slotCurrencyNew()), actionCollection(), "currency_new");
+ new KAction(i18n("Rename currency"), "edit", 0, this, SIGNAL(currencyRename()), actionCollection(), "currency_rename");
+ new KAction(i18n("Delete currency"), "delete", 0, this, SLOT(slotCurrencyDelete()), actionCollection(), "currency_delete");
+ new KAction(i18n("Select as base currency"), "kmymoney2", 0, this, SLOT(slotCurrencySetBase()), actionCollection(), "currency_setbase");
+
+#ifdef KMM_DEBUG
+ new KAction("Test new feature", "", KShortcut("Ctrl+G"), this, SLOT(slotNewFeature()), actionCollection(), "new_user_wizard");
+ new KToggleAction("Debug Traces", "", 0, this, SLOT(slotToggleTraces()), actionCollection(), "debug_traces");
+ new KToggleAction("Debug Timers", "", 0, this, SLOT(slotToggleTimers()), actionCollection(), "debug_timers");
+#endif
+ // ************************
+ // Currently unused actions
+ // ************************
+#if 0
+ new KToolBarPopupAction(i18n("View back"), "back", 0, this, SLOT(slotShowPreviousView()), actionCollection(), "go_back");
+ new KToolBarPopupAction(i18n("View forward"), "forward", 0, this, SLOT(slotShowNextView()), actionCollection(), "go_forward");
+
+ action("go_back")->setEnabled(false);
+ action("go_forward")->setEnabled(false);
+#endif
+
+ // Setup transaction detail switch
+ toggleAction("view_show_transaction_detail")->setChecked(KMyMoneyGlobalSettings::showRegisterDetailed());
+ toggleAction("view_hide_reconciled_transactions")->setChecked(KMyMoneyGlobalSettings::hideReconciledTransactions());
+ toggleAction("view_hide_unused_categories")->setChecked(KMyMoneyGlobalSettings::hideUnusedCategory());
+ toggleAction("view_show_all_accounts")->setChecked(false);
+
+ // use the absolute path to your kmymoney2ui.rc file for testing purpose in createGUI();
+ // createGUI(QString::null, false);
+ setupGUI();
+}
+
+void KMyMoney2App::dumpActions(void) const
+{
+ KActionPtrList list = actionCollection()->actions();
+ KActionPtrList::const_iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ std::cout << (*it)->name() << ": " << (*it)->text() << std::endl;
+ }
+}
+
+KAction* KMyMoney2App::action(const QString& actionName) const
+{
+ static KShortcut shortcut("");
+ static KAction dummyAction(QString("Dummy"), QString(), shortcut, static_cast<const QObject*>(this), 0, static_cast<KActionCollection*>(0), "");
+
+ KAction* p = actionCollection()->action(actionName.latin1());
+ if(p)
+ return p;
+
+ qWarning("Action with name '%s' not found!", actionName.latin1());
+ return &dummyAction;
+}
+
+KToggleAction* KMyMoney2App::toggleAction(const QString& actionName) const
+{
+ static KShortcut shortcut("");
+ static KToggleAction dummyAction(QString("Dummy"), QString(), shortcut, static_cast<const QObject*>(this), 0, static_cast<KActionCollection*>(0), "");
+
+ KAction* q = actionCollection()->action(actionName.latin1());
+
+ if(q) {
+ KToggleAction* p = dynamic_cast<KToggleAction*>(q);
+ if(!p) {
+ qWarning("Action '%s' is not of type KToggleAction", actionName.latin1());
+ p = &dummyAction;
+ }
+ return p;
+ }
+
+ qWarning("Action with name '%s' not found!", actionName.latin1());
+ return &dummyAction;
+}
+
+
+void KMyMoney2App::initStatusBar(void)
+{
+ ///////////////////////////////////////////////////////////////////
+ // STATUSBAR
+
+ statusBar()->insertItem("", ID_STATUS_MSG);
+ ready();
+
+ // Initialization of progress bar taken from KDevelop ;-)
+ progressBar = new KProgress(statusBar());
+ progressBar->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
+ progressBar->setMargin(0);
+ progressBar->setLineWidth(0);
+ progressBar->setBackgroundMode(QWidget::PaletteBackground);
+ statusBar()->addWidget(progressBar);
+ progressBar->setFixedHeight(progressBar->sizeHint().height() - 8);
+
+ // hide the progress bar for now
+ slotStatusProgressBar(-1, -1);
+}
+
+void KMyMoney2App::saveOptions(void)
+{
+ config->setGroup("General Options");
+ config->writeEntry("Geometry", size());
+ // config->writeEntry("Show Statusbar", toggleAction("options_show_statusbar")->isChecked());
+ // toolBar("mainToolBar")->saveSettings(config, "mainToolBar");
+
+ dynamic_cast<KRecentFilesAction*>(action("file_open_recent"))->saveEntries(config,"Recent Files");
+}
+
+
+void KMyMoney2App::readOptions(void)
+{
+ config->setGroup("General Options");
+
+ toggleAction("view_hide_reconciled_transactions")->setChecked(KMyMoneyGlobalSettings::hideReconciledTransactions());
+ toggleAction("view_hide_unused_categories")->setChecked(KMyMoneyGlobalSettings::hideUnusedCategory());
+
+ // initialize the recent file list
+ KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action("file_open_recent"));
+ if(p)
+ p->loadEntries(config,"Recent Files");
+
+ QSize defaultSize(800, 600);
+ QSize size=config->readSizeEntry("Geometry", &defaultSize);
+ if(!size.isEmpty())
+ {
+ resize(size);
+ }
+
+ // Startdialog is written in the settings dialog
+ m_startDialog = config->readBoolEntry("StartDialog", true);
+
+ config->setGroup("Schedule Options");
+ m_bCheckSchedules = config->readBoolEntry("CheckSchedules", true);
+}
+
+void KMyMoney2App::resizeEvent(QResizeEvent* ev)
+{
+ KMainWindow::resizeEvent(ev);
+ updateCaption(true);
+}
+
+bool KMyMoney2App::queryClose(void)
+{
+ if(!isReady())
+ return false;
+
+ if (myMoneyView->dirty()) {
+ int ans = KMessageBox::warningYesNoCancel(this, i18n("KMyMoney file needs saving. Save ?"));
+ if (ans==KMessageBox::Cancel)
+ return false;
+ else if (ans==KMessageBox::Yes)
+ return slotFileSave();
+ }
+ if (myMoneyView->isDatabase())
+ slotFileClose(); // close off the database
+ return true;
+}
+
+bool KMyMoney2App::queryExit(void)
+{
+ saveOptions();
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// SLOT IMPLEMENTATION
+/////////////////////////////////////////////////////////////////////
+void KMyMoney2App::slotFileInfoDialog(void)
+{
+ KMyMoneyFileInfoDlg dlg(0);
+ dlg.exec();
+}
+
+void KMyMoney2App::slotPerformanceTest(void)
+{
+ // dump performance report to stderr
+
+ int measurement[2];
+ QTime timer;
+ MyMoneyAccount acc;
+
+ qDebug("--- Starting performance tests ---");
+
+ // AccountList
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ timer.start();
+ for(int i = 0; i < 1000; ++i) {
+ QValueList<MyMoneyAccount> list;
+ MyMoneyFile::instance()->accountList(list);
+ measurement[i != 0] = timer.elapsed();
+ }
+ std::cerr << "accountList()" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl;
+
+ // Balance of asset account(s)
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ acc = MyMoneyFile::instance()->asset();
+ for(int i = 0; i < 1000; ++i) {
+ timer.start();
+ MyMoneyMoney result = MyMoneyFile::instance()->balance(acc.id());
+ measurement[i != 0] += timer.elapsed();
+ }
+ std::cerr << "balance(Asset)" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl;
+
+ // total balance of asset account
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ acc = MyMoneyFile::instance()->asset();
+ for(int i = 0; i < 1000; ++i) {
+ timer.start();
+ MyMoneyMoney result = MyMoneyFile::instance()->totalBalance(acc.id());
+ measurement[i != 0] += timer.elapsed();
+ }
+ std::cerr << "totalBalance(Asset)" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl;
+
+ // Balance of expense account(s)
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ acc = MyMoneyFile::instance()->expense();
+ for(int i = 0; i < 1000; ++i) {
+ timer.start();
+ MyMoneyMoney result = MyMoneyFile::instance()->balance(acc.id());
+ measurement[i != 0] += timer.elapsed();
+ }
+ std::cerr << "balance(Expense)" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl;
+
+ // total balance of expense account
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ acc = MyMoneyFile::instance()->expense();
+ timer.start();
+ for(int i = 0; i < 1000; ++i) {
+ MyMoneyMoney result = MyMoneyFile::instance()->totalBalance(acc.id());
+ measurement[i != 0] = timer.elapsed();
+ }
+ std::cerr << "totalBalance(Expense)" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl;
+
+ // transaction list
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ if(MyMoneyFile::instance()->asset().accountCount()) {
+ MyMoneyTransactionFilter filter(MyMoneyFile::instance()->asset().accountList()[0]);
+ filter.setDateFilter(QDate(), QDate::currentDate());
+ QValueList<MyMoneyTransaction> list;
+
+ timer.start();
+ for(int i = 0; i < 100; ++i) {
+ list = MyMoneyFile::instance()->transactionList(filter);
+ measurement[i != 0] = timer.elapsed();
+ }
+ std::cerr << "transactionList()" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 100 << " msec" << std::endl;
+ }
+
+ // transaction list
+ MyMoneyFile::instance()->preloadCache();
+ measurement[0] = measurement[1] = 0;
+ if(MyMoneyFile::instance()->asset().accountCount()) {
+ MyMoneyTransactionFilter filter(MyMoneyFile::instance()->asset().accountList()[0]);
+ filter.setDateFilter(QDate(), QDate::currentDate());
+ QValueList<MyMoneyTransaction> list;
+
+ timer.start();
+ for(int i = 0; i < 100; ++i) {
+ MyMoneyFile::instance()->transactionList(list, filter);
+ measurement[i != 0] = timer.elapsed();
+ }
+ std::cerr << "transactionList(list)" << std::endl;
+ std::cerr << "First time: " << measurement[0] << " msec" << std::endl;
+ std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl;
+ std::cerr << "Average : " << (measurement[0] + measurement[1]) / 100 << " msec" << std::endl;
+ }
+ MyMoneyFile::instance()->preloadCache();
+}
+
+void KMyMoney2App::slotFileNew(void)
+{
+ KMSTATUS(i18n("Creating new document..."));
+
+ slotFileClose();
+
+ if(!myMoneyView->fileOpen()) {
+ // next line required until we move all file handling out of KMyMoneyView
+ myMoneyView->newFile();
+
+ m_fileName = KURL();
+ updateCaption();
+
+ // before we create the wizard, we need to preload the currencies
+ MyMoneyFileTransaction ft;
+ myMoneyView->loadDefaultCurrencies();
+ myMoneyView->loadAncientCurrencies();
+ ft.commit();
+
+ NewUserWizard::Wizard *wizard = new NewUserWizard::Wizard();
+
+ if(wizard->exec() == QDialog::Accepted) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ ft.restart();
+ try {
+ // store the user info
+ file->setUser(wizard->user());
+
+ // setup base currency
+ file->setBaseCurrency(wizard->baseCurrency());
+
+ // create a possible institution
+ MyMoneyInstitution inst = wizard->institution();
+ if(inst.name().length()) {
+ file->addInstitution(inst);
+ }
+
+ // create a possible checking account
+ MyMoneyAccount acc = wizard->account();
+ if(acc.name().length()) {
+ acc.setInstitutionId(inst.id());
+ MyMoneyAccount asset = file->asset();
+ file->addAccount(acc, asset);
+
+ // create possible opening balance transaction
+ if(!wizard->openingBalance().isZero()) {
+ file->createOpeningBalanceTransaction(acc, wizard->openingBalance());
+ }
+ }
+
+ // import the account templates
+ QValueList<MyMoneyTemplate> templates = wizard->templates();
+ QValueList<MyMoneyTemplate>::iterator it_t;
+ for(it_t = templates.begin(); it_t != templates.end(); ++it_t) {
+ (*it_t).importTemplate(&progressCallback);
+ }
+
+ m_fileName = KURL(wizard->url());
+ ft.commit();
+ KMyMoneyGlobalSettings::setFirstTimeRun(false);
+
+ // FIXME This is a bit clumsy. We re-read the freshly
+ // created file to be able to run through all the
+ // fixup logic and then save it to keep the modified
+ // flag off.
+ slotFileSave();
+ myMoneyView->readFile(m_fileName);
+ slotFileSave();
+
+ // now keep the filename in the recent files used list
+ KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action("file_open_recent"));
+ if(p)
+ p->addURL( m_fileName );
+ writeLastUsedFile(m_fileName.url());
+
+ } catch(MyMoneyException* e) {
+ delete e;
+ // next line required until we move all file handling out of KMyMoneyView
+ myMoneyView->closeFile();
+ }
+
+ } else {
+ // next line required until we move all file handling out of KMyMoneyView
+ myMoneyView->closeFile();
+ }
+ delete wizard;
+ updateCaption();
+
+ emit fileLoaded(m_fileName);
+ }
+}
+
+KURL KMyMoney2App::selectFile(const QString& title, const QString& _path, const QString& mask, KFile::Mode mode)
+{
+ KURL url;
+ QString path(_path);
+
+ if(path.isEmpty())
+ path = KGlobalSettings::documentPath();
+
+ KFileDialog* dialog = new KFileDialog(path, mask, this, title, true);
+ dialog->setMode(mode);
+
+ if(dialog->exec() == QDialog::Accepted) {
+ url = dialog->selectedURL();
+ }
+ delete dialog;
+
+ return url;
+}
+
+// General open
+void KMyMoney2App::slotFileOpen(void)
+{
+ KMSTATUS(i18n("Open a file."));
+
+ KFileDialog* dialog = new KFileDialog(KGlobalSettings::documentPath(),
+ i18n("%1|KMyMoney files\n%2|All files (*.*)").arg("*.kmy *.xml").arg("*"),
+ this, i18n("Open File..."), true);
+ dialog->setMode(KFile::File | KFile::ExistingOnly);
+
+ if(dialog->exec() == QDialog::Accepted) {
+ slotFileOpenRecent(dialog->selectedURL());
+ }
+ delete dialog;
+}
+
+void KMyMoney2App::slotOpenDatabase(void)
+{
+ KMSTATUS(i18n("Open a file."));
+ KSelectDatabaseDlg dialog;
+ dialog.setMode(IO_ReadWrite);
+
+ if(dialog.exec() == QDialog::Accepted) {
+ slotFileOpenRecent(dialog.selectedURL());
+ }
+}
+
+bool KMyMoney2App::isImportableFile( const KURL& url )
+{
+ bool result = false;
+
+ // Iterate through the plugins and see if there's a loaded plugin who can handle it
+ QMap<QString,KMyMoneyPlugin::ImporterPlugin*>::const_iterator it_plugin = m_importerPlugins.begin();
+ while ( it_plugin != m_importerPlugins.end() )
+ {
+ if ( (*it_plugin)->isMyFormat(url.path()) )
+ {
+ result = true;
+ break;
+ }
+ ++it_plugin;
+ }
+
+ // If we did not find a match, try importing it as a KMM statement file,
+ // which is really just for testing. the statement file is not exposed
+ // to users.
+ if ( it_plugin == m_importerPlugins.end() )
+ if ( MyMoneyStatement::isStatementFile( url.path() ) )
+ result = true;
+
+ // Place code here to test for QIF and other locally-supported formats
+ // (i.e. not a plugin). If you add them here, be sure to add it to
+ // the webConnect function.
+
+ return result;
+}
+
+void KMyMoney2App::slotFileOpenRecent(const KURL& url)
+{
+ KMSTATUS(i18n("Loading file..."));
+ KURL lastFile = m_fileName;
+
+ // check if there are other instances which might have this file open
+ QValueList<QCString> list = instanceList();
+ QValueList<QCString>::ConstIterator it;
+ bool duplicate = false;
+
+ for(it = list.begin(); duplicate == false && it != list.end(); ++it) {
+ KMyMoney2App_stub* remoteApp = new KMyMoney2App_stub(kapp->dcopClient(), (*it), "kmymoney2app");
+ QString remoteFile = remoteApp->filename();
+ if(!remoteApp->ok()) {
+ qDebug("DCOP error while calling app->filename()");
+ } else {
+ if(remoteFile == url.url()) {
+ duplicate = true;
+ }
+ }
+ delete remoteApp;
+ }
+
+ if(!duplicate) {
+
+#if KDE_IS_VERSION(3,2,0)
+ if((url.protocol() == "sql") || (url.isValid() && KIO::NetAccess::exists(url, true, this))) {
+#else
+ if((url.protocol() == "sql") || (url.isValid() && KIO::NetAccess::exists(url))) {
+#endif
+ KURL dburl = url;
+ // check if a password is needed. it may be if the URL came from the last/recent file list
+ if ((dburl.queryItem("secure") == "yes") && dburl.pass().isEmpty()) {
+ KSelectDatabaseDlg dialog(dburl);
+ dialog.setMode(IO_ReadWrite);
+
+ if(dialog.exec() == QDialog::Accepted) dburl = dialog.selectedURL();
+ }
+ slotFileClose();
+ if(!myMoneyView->fileOpen()) {
+ if(myMoneyView->readFile(dburl)) {
+ if((myMoneyView->isNativeFile())) {
+ m_fileName = dburl;
+ KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action("file_open_recent"));
+ if(p)
+ p->addURL(dburl.prettyURL(0, KURL::StripFileProtocol));
+ writeLastUsedFile(dburl.prettyURL(0, KURL::StripFileProtocol));
+ } else {
+ m_fileName = KURL(); // imported files have no filename
+ }
+ ::timetrace("Start checking schedules");
+ // Check the schedules
+ slotCheckSchedules();
+ ::timetrace("Done checking schedules");
+ }
+
+ updateCaption();
+ ::timetrace("Announcing new filename");
+ emit fileLoaded(m_fileName);
+ ::timetrace("Announcing new filename done");
+ }
+ } else {
+ slotFileClose();
+ KMessageBox::sorry(this, QString("<p>")+i18n("<b>%1</b> is either an invalid filename or the file does not exist. You can open another file or create a new one.").arg(url.prettyURL(0, KURL::StripFileProtocol)), i18n("File not found"));
+ }
+ } else {
+ KMessageBox::sorry(this, QString("<p>")+i18n("File <b>%1</b> is already opened in another instance of KMyMoney").arg(url.prettyURL(0, KURL::StripFileProtocol)), i18n("Duplicate open"));
+ }
+}
+
+bool KMyMoney2App::slotFileSave(void)
+{
+ // if there's nothing changed, there's no need to save anything
+ if(!myMoneyView->dirty())
+ return true;
+
+ bool rc = false;
+
+ KMSTATUS(i18n("Saving file..."));
+
+ if (m_fileName.isEmpty())
+ return slotFileSaveAs();
+
+ /*if (myMoneyView->isDatabase()) {
+ rc = myMoneyView->saveDatabase(m_fileName);
+ // the 'save' function is no longer relevant for a database*/
+ setEnabled(false);
+ rc = myMoneyView->saveFile(m_fileName, MyMoneyFile::instance()->value("kmm-encryption-key"));
+ setEnabled(true);
+
+ m_autoSaveTimer->stop();
+
+ updateCaption();
+ return rc;
+}
+
+void KMyMoney2App::slotFileSaveAsFilterChanged(const QString& filter)
+{
+ if(m_saveEncrypted) {
+ if(filter != "*.kmy") {
+ m_saveEncrypted->setCurrentItem(0);
+ m_saveEncrypted->setEnabled(false);
+ } else {
+ m_saveEncrypted->setEnabled(true);
+ }
+ }
+}
+
+void KMyMoney2App::slotManageGpgKeys(void)
+{
+ KGpgKeySelectionDlg dlg(this);
+ dlg.setKeys(m_additionalGpgKeys);
+ if(dlg.exec() == QDialog::Accepted) {
+ m_additionalGpgKeys = dlg.keys();
+ m_additionalKeyLabel->setText(i18n("Additional encryption key(s) to be used: %1").arg(m_additionalGpgKeys.count()));
+ }
+}
+
+void KMyMoney2App::slotKeySelected(int idx)
+{
+ int cnt = 0;
+ if(idx != 0) {
+ cnt = m_additionalGpgKeys.count();
+ }
+ m_additionalKeyLabel->setEnabled(idx != 0);
+ m_additionalKeyButton->setEnabled(idx != 0);
+ m_additionalKeyLabel->setText(i18n("Additional encryption key(s) to be used: %1").arg(cnt));
+}
+
+bool KMyMoney2App::slotFileSaveAs(void)
+{
+ bool rc = false;
+ // in event of it being a database, ensure that all data is read into storage for saveas
+ if (myMoneyView->isDatabase())
+ dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage())->fillStorage();
+ KMSTATUS(i18n("Saving file with a new filename..."));
+ QString prevDir= ""; // don't prompt file name if not a native file
+ if (myMoneyView->isNativeFile())
+ prevDir = readLastUsedDir();
+
+ // fill the additional key list with the default
+ m_additionalGpgKeys = KMyMoneyGlobalSettings::gpgRecipientList();
+
+ QVBox* vbox = new QVBox();
+ if(KGPGFile::GPGAvailable()) {
+ QHBox* keyBox = new QHBox(vbox);
+ new QLabel(i18n("Encryption key to be used"), keyBox);
+ m_saveEncrypted = new KComboBox(keyBox);
+
+ QHBox* labelBox = new QHBox(vbox);
+ m_additionalKeyLabel = new QLabel(i18n("Additional encryption key(s) to be used: %1").arg(m_additionalGpgKeys.count()), labelBox);
+ m_additionalKeyButton = new KPushButton(i18n("Manage additional keys"), labelBox);
+ connect(m_additionalKeyButton, SIGNAL(clicked()), this, SLOT(slotManageGpgKeys()));
+ connect(m_saveEncrypted, SIGNAL(activated(int)), this, SLOT(slotKeySelected(int)));
+
+ // fill the secret key list and combo box
+ QStringList keyList;
+ KGPGFile::secretKeyList(keyList);
+ m_saveEncrypted->insertItem(i18n("No encryption"));
+
+ for(QStringList::iterator it = keyList.begin(); it != keyList.end(); ++it) {
+ QStringList fields = QStringList::split(":", *it);
+ if(fields[0] != RECOVER_KEY_ID) {
+ // replace parenthesis in name field with brackets
+ QString name = fields[1];
+ name.replace('(', "[");
+ name.replace(')', "]");
+ name = QString("%1 (0x%2)").arg(name).arg(fields[0]);
+ m_saveEncrypted->insertItem(name);
+ if(name.contains(KMyMoneyGlobalSettings::gpgRecipient())) {
+ m_saveEncrypted->setCurrentItem(name);
+ }
+ }
+ }
+ }
+
+ // the following code is copied from KFileDialog::getSaveFileName,
+ // adjust to our local needs (filetypes etc.) and
+ // enhanced to show the m_saveEncrypted combo box
+ bool specialDir = prevDir.at(0) == ':';
+ KFileDialog dlg( specialDir ? prevDir : QString::null,
+ QString("%1|%2\n").arg("*.kmy").arg(i18n("KMyMoney (Filefilter)", "KMyMoney files")) +
+ QString("%1|%2\n").arg("*.xml").arg(i18n("XML (Filefilter)", "XML files")) +
+ QString("%1|%2\n").arg("*.anon.xml").arg(i18n("Anonymous (Filefilter)", "Anonymous files")) +
+ QString("%1|%2\n").arg("*").arg(i18n("All files")),
+ this, "filedialog", true, vbox);
+ connect(&dlg, SIGNAL(filterChanged(const QString&)), this, SLOT(slotFileSaveAsFilterChanged(const QString&)));
+
+ if ( !specialDir )
+ dlg.setSelection( prevDir ); // may also be a filename
+
+ dlg.setOperationMode( KFileDialog::Saving );
+ dlg.setCaption(i18n("Save As"));
+
+ if(dlg.exec() == QDialog::Accepted) {
+
+ KURL newURL = dlg.selectedURL();
+ if (!newURL.isEmpty()) {
+ QString newName = newURL.prettyURL(0, KURL::StripFileProtocol);
+
+ // end of copy
+
+ // find last . delimiter
+ int nLoc = newName.findRev('.');
+ if(nLoc != -1)
+ {
+ QString strExt, strTemp;
+ strTemp = newName.left(nLoc + 1);
+ strExt = newName.right(newName.length() - (nLoc + 1));
+ if((strExt.find("kmy", 0, FALSE) == -1) && (strExt.find("xml", 0, FALSE) == -1))
+ {
+
+ strTemp.append("kmy");
+ //append to make complete file name
+ newName = strTemp;
+ }
+ }
+ else
+ {
+ newName.append(".kmy");
+ }
+
+ if(okToWriteFile(newName)) {
+ KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action("file_open_recent"));
+ if(p)
+ p->addURL( newName );
+
+ setEnabled(false);
+ // If this is the anonymous file export, just save it, don't actually take the
+ // name, or remember it! Don't even try to encrypt it
+ if (newName.right(9).lower() == ".anon.xml")
+ {
+ rc = myMoneyView->saveFile(newName);
+ }
+ else
+ {
+
+ m_fileName = newName;
+ QString encryptionKeys;
+ if(m_saveEncrypted && m_saveEncrypted->currentItem() != 0) {
+ QRegExp keyExp(".* \\((.*)\\)");
+ if(keyExp.search(m_saveEncrypted->currentText()) != -1) {
+ encryptionKeys = keyExp.cap(1);
+ }
+ if(!m_additionalGpgKeys.isEmpty()) {
+ if(!encryptionKeys.isEmpty())
+ encryptionKeys += ",";
+ encryptionKeys += m_additionalGpgKeys.join(",");
+ }
+ }
+ rc = myMoneyView->saveFile(newName, encryptionKeys);
+ //write the directory used for this file as the default one for next time.
+ writeLastUsedDir(newName);
+ writeLastUsedFile(newName);
+ }
+ m_autoSaveTimer->stop();
+ setEnabled(true);
+ }
+ }
+ }
+
+ updateCaption();
+ return rc;
+}
+
+bool KMyMoney2App::slotSaveAsDatabase(void)
+{
+
+ bool rc = false;
+ // in event of it being a database, ensure that all data is read into storage for saveas
+ if (myMoneyView->isDatabase())
+ dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage())->fillStorage();
+ KMSTATUS(i18n("Saving file to database..."));
+ KSelectDatabaseDlg dialog;
+ dialog.setMode(IO_WriteOnly);
+ KURL oldUrl = m_fileName.isEmpty() ? lastOpenedURL() : m_fileName;
+ KURL url = oldUrl;
+
+ while (oldUrl == url && dialog.exec() == QDialog::Accepted) {
+ url = dialog.selectedURL();
+ // If the protocol is SQL for the old and new, and the hostname and database names match
+ // Let the user know that the current database cannot be saved on top of itself.
+ if (url.protocol() == "sql" && oldUrl.protocol() == "sql"
+ && oldUrl.host() == url.host()
+ && oldUrl.queryItem("driver") == url.queryItem("driver")
+ && oldUrl.path().right(oldUrl.path().length() - 1) == url.path().right(url.path().length() - 1)) {
+ KMessageBox::sorry(this, i18n("Cannot save to current database."));
+ } else {
+ rc = myMoneyView->saveAsDatabase(url);
+ }
+ }
+ if (rc) {
+ KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action("file_open_recent"));
+ if(p)
+ p->addURL(url.prettyURL(0, KURL::StripFileProtocol));
+ writeLastUsedFile(url.prettyURL(0, KURL::StripFileProtocol));
+ }
+ m_autoSaveTimer->stop();
+ updateCaption();
+ return rc;
+}
+
+void KMyMoney2App::slotFileCloseWindow(void)
+{
+ KMSTATUS(i18n("Closing window..."));
+
+ if (myMoneyView->dirty()) {
+ int answer = KMessageBox::warningYesNoCancel(this, i18n("The file has been changed, save it ?"));
+ if (answer == KMessageBox::Cancel)
+ return;
+ else if (answer == KMessageBox::Yes)
+ slotFileSave();
+ }
+ close();
+}
+
+void KMyMoney2App::slotFileClose(void)
+{
+ bool okToSelect = true;
+
+ // check if transaction editor is open and ask user what he wants to do
+ slotTransactionsCancelOrEnter(okToSelect);
+
+ if(!okToSelect)
+ return;
+
+ // no update status here, as we might delete the status too early.
+ if (myMoneyView->dirty()) {
+ int answer = KMessageBox::warningYesNoCancel(this, i18n("The file has been changed, save it ?"));
+ if (answer == KMessageBox::Cancel)
+ return;
+ else if (answer == KMessageBox::Yes)
+ slotFileSave();
+ }
+
+ slotSelectAccount();
+ slotSelectInstitution();
+ slotSelectInvestment();
+ slotSelectSchedule();
+ slotSelectCurrency();
+ slotSelectBudget(QValueList<MyMoneyBudget>());
+ slotSelectPayees(QValueList<MyMoneyPayee>());
+ slotSelectTransactions(KMyMoneyRegister::SelectedTransactions());
+
+ m_reconciliationAccount = MyMoneyAccount();
+ myMoneyView->finishReconciliation(m_reconciliationAccount);
+
+ myMoneyView->closeFile();
+ m_fileName = KURL();
+ updateCaption();
+
+ // just create a new balance warning object
+ delete d->m_balanceWarning;
+ d->m_balanceWarning = new KBalanceWarning(this);
+
+ emit fileLoaded(m_fileName);
+}
+
+void KMyMoney2App::slotFileQuit(void)
+{
+ // don't modify the status message here as this will prevent quit from working!!
+ // See the beginning of queryClose() and isReady() why. Thomas Baumgart 2005-10-17
+
+ KMainWindow* w = 0;
+
+ if(memberList) {
+
+ for(w=memberList->first(); w!=0; w=memberList->next()) {
+ // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog,
+
+ // the window and the application stay open.
+ if(!w->close())
+ break;
+ }
+ // We will only quit if all windows were processed and not cancelled
+ if(w == 0)
+ kapp->quit();
+
+ } else
+ kapp->quit();
+}
+
+void KMyMoney2App::slotHideReconciledTransactions(void)
+{
+ KMyMoneyGlobalSettings::setHideReconciledTransactions(toggleAction("view_hide_reconciled_transactions")->isChecked());
+ myMoneyView->slotRefreshViews();
+}
+
+void KMyMoney2App::slotHideUnusedCategories(void)
+{
+ KMyMoneyGlobalSettings::setHideUnusedCategory(toggleAction("view_hide_unused_categories")->isChecked());
+ myMoneyView->slotRefreshViews();
+}
+
+void KMyMoney2App::slotShowAllAccounts(void)
+{
+ myMoneyView->slotRefreshViews();
+}
+
+void KMyMoney2App::slotToggleTraces(void)
+{
+ MyMoneyTracer::onOff(toggleAction("debug_traces")->isChecked() ? 1 : 0);
+}
+
+void KMyMoney2App::slotToggleTimers(void)
+{
+ extern bool timersOn; // main.cpp
+ timersOn = toggleAction("debug_timers")->isChecked();
+}
+
+const QString KMyMoney2App::slotStatusMsg(const QString &text)
+{
+ ///////////////////////////////////////////////////////////////////
+ // change status message permanently
+ QString msg = m_statusMsg;
+
+ m_statusMsg = text;
+ if(m_statusMsg.isEmpty())
+ m_statusMsg = i18n("Ready.");
+ statusBar()->clear();
+ statusBar()->changeItem(text, ID_STATUS_MSG);
+ return msg;
+}
+
+void KMyMoney2App::ready(void)
+{
+ slotStatusMsg(QString());
+}
+
+bool KMyMoney2App::isReady(void)
+{
+ return m_statusMsg == i18n("Ready.");
+}
+
+void KMyMoney2App::slotStatusProgressBar(int current, int total)
+{
+ if(total == -1 && current == -1) { // reset
+ progressBar->reset();
+ progressBar->hide();
+ m_nextUpdate = 0;
+
+ } else if(total != 0) { // init
+ progressBar->setTotalSteps(total);
+ progressBar->show();
+
+ // make sure, we don't waste too much time for updateing the screen.
+ // if we have more than 1000 steps, we update the progress bar
+ // every 100 steps. If we have less, we allow to update
+ // every 10 steps.
+ m_progressUpdate = 1;
+ if(total > 100)
+ m_progressUpdate = 10;
+ if(total > 1000)
+ m_progressUpdate = 100;
+ m_nextUpdate = 0;
+
+ } else { // update
+ if(current > m_nextUpdate) {
+ progressBar->setProgress(current);
+ QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 10);
+ m_nextUpdate += m_progressUpdate;
+ }
+ }
+}
+
+void KMyMoney2App::progressCallback(int current, int total, const QString& msg)
+{
+ if(!msg.isEmpty())
+ kmymoney2->slotStatusMsg(msg);
+
+ kmymoney2->slotStatusProgressBar(current, total);
+}
+
+void KMyMoney2App::slotFileViewPersonal(void)
+{
+ if ( !myMoneyView->fileOpen() ) {
+ KMessageBox::information(this, i18n("No KMyMoneyFile open"));
+ return;
+ }
+
+ KMSTATUS(i18n("Viewing personal data..."));
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyPayee user = file->user();
+
+ KNewFileDlg newFileDlg(user.name(), user.address(),
+ user.city(), user.state(), user.postcode(), user.telephone(),
+ user.email(), this, "NewFileDlg", i18n("Edit Personal Data"));
+
+ if (newFileDlg.exec() == QDialog::Accepted)
+ {
+ user.setName(newFileDlg.userNameText);
+ user.setAddress(newFileDlg.userStreetText);
+ user.setCity(newFileDlg.userTownText);
+ user.setState(newFileDlg.userCountyText);
+ user.setPostcode(newFileDlg.userPostcodeText);
+ user.setTelephone(newFileDlg.userTelephoneText);
+ user.setEmail(newFileDlg.userEmailText);
+ MyMoneyFileTransaction ft;
+ try {
+ file->setUser(user);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to store user information: %1").arg(e->what()));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotFileFileInfo(void)
+{
+ if ( !myMoneyView->fileOpen() ) {
+ KMessageBox::information(this, i18n("No KMyMoneyFile open"));
+ return;
+ }
+
+ QFile g( "kmymoney2.dump" );
+ g.open( IO_WriteOnly );
+ QDataStream st(&g);
+ MyMoneyStorageDump dumper;
+ dumper.writeStream(st, dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()));
+ g.close();
+}
+
+void KMyMoney2App::slotLoadAccountTemplates(void)
+{
+ KMSTATUS(i18n("Importing account templates."));
+
+ int rc;
+ KLoadTemplateDlg* dlg = new KLoadTemplateDlg();
+ if((rc = dlg->exec()) == QDialog::Accepted) {
+ MyMoneyFileTransaction ft;
+ try {
+ // import the account templates
+ QValueList<MyMoneyTemplate> templates = dlg->templates();
+ QValueList<MyMoneyTemplate>::iterator it_t;
+ for(it_t = templates.begin(); it_t != templates.end(); ++it_t) {
+ (*it_t).importTemplate(&progressCallback);
+ }
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to import template(s): %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+ delete dlg;
+}
+
+void KMyMoney2App::slotSaveAccountTemplates(void)
+{
+ KMSTATUS(i18n("Exporting account templates."));
+
+ QString newName = KFileDialog::getSaveFileName(KGlobalSettings::documentPath(),
+ i18n("*.kmt|KMyMoney template files\n"
+ "*.*|All files"), this, i18n("Save as..."));
+ //
+ // If there is no file extension, then append a .kmt at the end of the file name.
+ // If there is a file extension, make sure it is .kmt, delete any others.
+ //
+ if(!newName.isEmpty())
+ {
+ // find last . delimiter
+ int nLoc = newName.findRev('.');
+ if(nLoc != -1)
+ {
+ QString strExt, strTemp;
+ strTemp = newName.left(nLoc + 1);
+ strExt = newName.right(newName.length() - (nLoc + 1));
+ if((strExt.find("kmt", 0, FALSE) == -1))
+ {
+ strTemp.append("kmt");
+ //append to make complete file name
+ newName = strTemp;
+ }
+ }
+ else
+ {
+ newName.append(".kmt");
+ }
+
+ if(okToWriteFile(newName)) {
+ MyMoneyTemplate templ;
+ templ.exportTemplate(&progressCallback);
+ templ.saveTemplate(newName);
+ }
+ }
+}
+
+void KMyMoney2App::slotQifImport(void)
+{
+ if(m_qifReader == 0) {
+ // FIXME: the menu entry for qif import should be disabled here
+
+ KImportDlg* dlg = new KImportDlg(0);
+
+ if(dlg->exec()) {
+ KMSTATUS(i18n("Importing file..."));
+ m_qifReader = new MyMoneyQifReader;
+
+ // remove all kmm-statement-#.txt files
+ d->unlinkStatementXML();
+
+ connect(m_qifReader, SIGNAL(importFinished()), this, SLOT(slotQifImportFinished()));
+
+ m_qifReader->setURL(dlg->filename());
+
+ m_qifReader->setProfile(dlg->profile());
+ m_qifReader->setCategoryMapping(dlg->m_typeComboBox->currentItem() == 0);
+ m_qifReader->setProgressCallback(&progressCallback);
+
+ // disable all standard widgets during the import
+ setEnabled(false);
+
+ d->m_ft = new MyMoneyFileTransaction();
+ d->m_collectingStatements = true;
+ d->m_statementResults.clear();
+ m_qifReader->startImport();
+ }
+ delete dlg;
+
+ slotUpdateActions();
+ }
+}
+
+void KMyMoney2App::slotQifImportFinished(void)
+{
+ if(m_qifReader != 0) {
+ m_qifReader->finishImport();
+ d->m_ft->commit();
+ d->m_collectingStatements = false;
+
+ KMessageBox::informationList(this, i18n("The statements have been processed with the following results:"), d->m_statementResults, i18n("Statement stats"));
+
+#if 0
+ // fixme: re-enable the QIF import menu options
+ if(m_qifReader->finishImport()) {
+ if(verifyImportedData(m_qifReader->account())) {
+ // keep the new data set, destroy the backup copy
+ delete m_engineBackup;
+ m_engineBackup = 0;
+ }
+ }
+
+ if(m_engineBackup != 0) {
+ // user cancelled, destroy the updated set and keep the backup copy
+ IMyMoneyStorage* data = file->storage();
+
+
+ if(data != 0) {
+ file->detachStorage(data);
+ delete data;
+ }
+ file->attachStorage(m_engineBackup);
+ m_engineBackup = 0;
+
+ }
+#endif
+
+ // update the views as they might still contain invalid data
+ // from the import session. The same applies for the window caption
+ myMoneyView->slotRefreshViews();
+ updateCaption();
+
+ delete m_qifReader;
+ m_qifReader = 0;
+ }
+ delete d->m_ft;
+ d->m_ft = 0;
+
+ slotStatusProgressBar(-1, -1);
+ ready();
+
+ // re-enable all standard widgets
+ setEnabled(true);
+ slotUpdateActions();
+}
+
+void KMyMoney2App::slotGncImport(void)
+{
+ if (myMoneyView->fileOpen()) {
+ switch (KMessageBox::questionYesNoCancel (0,
+ i18n("You cannot import GnuCash data into an existing file. Do you wish to save this file?"), PACKAGE)) {
+ case KMessageBox::Yes:
+ slotFileSave();
+ break;
+ case KMessageBox::No:
+ myMoneyView->closeFile();
+ m_fileName = KURL();
+ break;
+ default:
+ return;
+ }
+ }
+
+ KMSTATUS(i18n("Importing a Gnucash file."));
+
+ KFileDialog* dialog = new KFileDialog(KGlobalSettings::documentPath(),
+ i18n("%1|Gnucash files\n%2|All files (*.*)").arg("*").arg("*"),
+ this, i18n("Import Gnucash file..."), true);
+ dialog->setMode(KFile::File | KFile::ExistingOnly);
+
+ if(dialog->exec() == QDialog::Accepted) {
+// slotFileClose();
+// if(myMoneyView->fileOpen())
+// return;
+
+ // call the importer
+ myMoneyView->readFile(dialog->selectedURL());
+ // imported files don't have a name
+ m_fileName = KURL();
+
+ updateCaption();
+ emit fileLoaded(m_fileName);
+ }
+ delete dialog;
+
+}
+
+void KMyMoney2App::slotAccountChart(void)
+{
+#ifdef HAVE_KDCHART
+ if(!m_selectedAccount.id().isEmpty()) {
+ KBalanceChartDlg dlg(m_selectedAccount, this);
+ dlg.exec();
+ }
+#endif
+}
+
+
+//
+// KMyMoney2App::slotStatementImport() is for testing only. The MyMoneyStatement
+// is not intended to be exposed to users in XML form.
+//
+
+void KMyMoney2App::slotStatementImport(void)
+{
+ bool result = false;
+ KMSTATUS(i18n("Importing an XML Statement."));
+
+ KFileDialog* dialog = new KFileDialog(KGlobalSettings::documentPath(),
+ i18n("%1|XML files\n%2|All files (*.*)").arg("*.xml").arg("*.*"),
+ this, i18n("Import XML Statement..."), true);
+ dialog->setMode(KFile::File | KFile::ExistingOnly);
+
+ if(dialog->exec() == QDialog::Accepted)
+ {
+ result = slotStatementImport(dialog->selectedURL().path());
+
+/* QFile f( dialog->selectedURL().path() );
+ f.open( IO_ReadOnly );
+ QString error = "Unable to parse file";
+ QDomDocument* doc = new QDomDocument;
+ if(doc->setContent(&f, FALSE))
+ {
+ if ( doc->doctype().name() == "KMYMONEY-STATEMENT" )
+ {
+ QDomElement rootElement = doc->documentElement();
+ if(!rootElement.isNull())
+ {
+ QDomNode child = rootElement.firstChild();
+ if(!child.isNull() && child.isElement())
+ {
+ MyMoneyStatement s;
+ if ( s.read(child.toElement()) )
+ result = slotStatementImport(s);
+ else
+ error = "File does not contain any statements";
+ }
+ }
+ }
+ else
+ error = "File is not a KMyMoney Statement";
+ }
+ delete doc;
+
+ if ( !result )
+ {
+ QMessageBox::critical( this, i18n("Critical Error"), i18n("Unable to read file %1: %2").arg( dialog->selectedURL().path()).arg(error), QMessageBox::Ok, 0 );
+
+ }*/
+ }
+ delete dialog;
+
+ if ( !result )
+ {
+ // re-enable all standard widgets
+ setEnabled(true);
+ }
+}
+
+bool KMyMoney2App::slotStatementImport(const QString& url)
+{
+ bool result = false;
+ MyMoneyStatement s;
+ if ( MyMoneyStatement::readXMLFile( s, url ) )
+ result = slotStatementImport(s);
+ else
+ KMessageBox::error(this, i18n("Error importing %1: This file is not a valid KMM statement file.").arg(url), i18n("Invalid Statement"));
+
+ return result;
+}
+
+bool KMyMoney2App::slotStatementImport(const MyMoneyStatement& s)
+{
+ bool result = false;
+
+ // keep a copy of the statement
+ MyMoneyStatement::writeXMLFile(s, QString("/home/thb/kmm-statement-%1.txt").arg(d->statementXMLindex++));
+
+ // we use an object on the heap here, so that we can check the presence
+ // of it during slotUpdateActions() by looking at the pointer.
+ m_smtReader = new MyMoneyStatementReader;
+ m_smtReader->setAutoCreatePayee(true);
+ m_smtReader->setProgressCallback(&progressCallback);
+
+ // disable all standard widgets during the import
+ setEnabled(false);
+
+ QStringList messages;
+ result = m_smtReader->import(s, messages);
+
+ bool transactionAdded = m_smtReader->anyTransactionAdded();
+
+ // get rid of the statement reader and tell everyone else
+ // about the destruction by setting the pointer to zero
+ delete m_smtReader;
+ m_smtReader = 0;
+
+ slotStatusProgressBar(-1, -1);
+ ready();
+
+ // re-enable all standard widgets
+ setEnabled(true);
+
+ if(!d->m_collectingStatements)
+ KMessageBox::informationList(this, i18n("The statement has been processed with the following results:"), messages, i18n("Statement stats"));
+ else if(transactionAdded)
+ d->m_statementResults += messages;
+
+ return result;
+}
+
+void KMyMoney2App::slotQifExport(void)
+{
+ KMSTATUS(i18n("Exporting file..."));
+
+ KExportDlg* dlg = new KExportDlg(0);
+
+ if(dlg->exec()) {
+ if(okToWriteFile(dlg->filename())) {
+ MyMoneyQifWriter writer;
+ connect(&writer, SIGNAL(signalProgress(int, int)), this, SLOT(slotStatusProgressBar(int, int)));
+
+ writer.write(dlg->filename(), dlg->profile(), dlg->accountId(),
+ dlg->accountSelected(), dlg->categorySelected(),
+ dlg->startDate(), dlg->endDate());
+ }
+ }
+ delete dlg;
+}
+
+bool KMyMoney2App::okToWriteFile(const KURL& url)
+{
+ // check if the file exists and warn the user
+ bool reallySaveFile = true;
+
+ if(KIO::NetAccess::exists(url, true, this)) {
+ if(KMessageBox::warningYesNo(this, QString("<qt>")+i18n("The file <b>%1</b> already exists. Do you really want to override it?").arg(url.prettyURL(0, KURL::StripFileProtocol))+QString("</qt>"), i18n("File already exists")) != KMessageBox::Yes)
+ reallySaveFile = false;
+ }
+ return reallySaveFile;
+}
+
+void KMyMoney2App::slotSettings(void)
+{
+ // if we already have an instance of the settings dialog, then use it
+ if(KConfigDialog::showDialog("KMyMoney-Settings"))
+ return;
+
+ // otherwise, we have to create it
+ KConfigDialog* dlg = new KConfigDialog(this, "KMyMoney-Settings", KMyMoneyGlobalSettings::self(),
+ KDialogBase::IconList, KDialogBase::Default | KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help, KDialogBase::Ok, true);
+
+ // create the pages ...
+ KSettingsGeneral* generalPage = new KSettingsGeneral();
+ KSettingsRegister* registerPage = new KSettingsRegister();
+ KSettingsHome* homePage = new KSettingsHome();
+ KSettingsSchedules* schedulesPage = new KSettingsSchedules();
+ KSettingsGpg* encryptionPage = new KSettingsGpg();
+ KSettingsColors* colorsPage = new KSettingsColors();
+ KSettingsFonts* fontsPage = new KSettingsFonts();
+ KSettingsOnlineQuotes* onlineQuotesPage = new KSettingsOnlineQuotes();
+ KSettingsForecast* forecastPage = new KSettingsForecast();
+ KSettingsPlugins* pluginsPage = new KSettingsPlugins();
+
+ // ... and add them to the dialog
+ dlg->addPage(generalPage, i18n("General"), "misc");
+ dlg->addPage(registerPage, i18n("Register"), "ledger");
+ dlg->addPage(homePage, i18n("Home"), "home");
+ dlg->addPage(schedulesPage, i18n("Scheduled\ntransactions"), "schedule");
+ dlg->addPage(encryptionPage, i18n("Encryption"), "kgpg");
+ dlg->addPage(colorsPage, i18n("Colors"), "colorscm");
+ dlg->addPage(fontsPage, i18n("Fonts"), "font");
+ dlg->addPage(onlineQuotesPage, i18n("Online Quotes"), "network_local");
+ dlg->addPage(forecastPage, i18n("Forecast"), "forcast");
+ dlg->addPage(pluginsPage, i18n("Plugins"), "connect_no");
+
+ connect(dlg, SIGNAL(settingsChanged()), this, SLOT(slotUpdateConfiguration()));
+ connect(dlg, SIGNAL(okClicked()), pluginsPage, SLOT(slotSavePlugins()));
+ connect(dlg, SIGNAL(defaultClicked()), pluginsPage, SLOT(slotDefaultsPlugins()));
+
+ dlg->show();
+}
+
+void KMyMoney2App::slotUpdateConfiguration(void)
+{
+ MyMoneyTransactionFilter::setFiscalYearStart(KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay());
+
+ myMoneyView->slotRefreshViews();
+
+ // re-read autosave configuration
+ m_autoSaveEnabled = KMyMoneyGlobalSettings::autoSaveFile();
+ m_autoSavePeriod = KMyMoneyGlobalSettings::autoSavePeriod();
+
+ // stop timer if turned off but running
+ if(m_autoSaveTimer->isActive() && !m_autoSaveEnabled) {
+ m_autoSaveTimer->stop();
+ }
+ // start timer if turned on and needed but not running
+ if(!m_autoSaveTimer->isActive() && m_autoSaveEnabled && myMoneyView->dirty()) {
+ m_autoSaveTimer->start(m_autoSavePeriod * 60 * 1000, true);
+ }
+}
+
+/** Init wizard dialog */
+bool KMyMoney2App::initWizard(void)
+{
+ KStartDlg start;
+ if (start.exec()) {
+ slotFileClose();
+ if (start.isNewFile()) {
+ slotFileNew();
+ } else if (start.isOpenFile()) {
+ KURL url;
+ url = start.getURL();
+
+ m_fileName = url.url();
+ slotFileOpenRecent(url);
+ } else { // Wizard / Template
+ m_fileName = start.getURL();
+ }
+
+ //save off directory as the last one used.
+ if(m_fileName.isLocalFile() && m_fileName.hasPath())
+ {
+ writeLastUsedDir(m_fileName.path(0));
+ writeLastUsedFile(m_fileName.path(0));
+ }
+
+ return true;
+
+ } else {
+ // cancel clicked so post an exit call
+ return false;
+ }
+}
+
+/** No descriptions */
+void KMyMoney2App::slotFileBackup(void)
+{
+ // Save the file first so isLocalFile() works
+ if (myMoneyView && myMoneyView->dirty())
+
+ {
+ if (KMessageBox::questionYesNo(this, i18n("The file must be saved first "
+ "before it can be backed up. Do you want to continue?")) == KMessageBox::No)
+ {
+ return;
+
+ }
+
+ slotFileSave();
+ }
+
+
+
+ if ( m_fileName.isEmpty() )
+ return;
+
+ if(!m_fileName.isLocalFile()) {
+ KMessageBox::sorry(this,
+ i18n("The current implementation of the backup functionality only supports local files as source files! Your current source file is '%1'.")
+ .arg(m_fileName.url()),
+
+ i18n("Local files only"));
+ return;
+ }
+
+ KBackupDlg *backupDlg = new KBackupDlg(this,0/*,true*/);
+ int returncode = backupDlg->exec();
+ if(returncode)
+ {
+
+ m_backupMount = backupDlg->mountCheckBox->isChecked();
+ proc.clearArguments();
+ m_backupState = BACKUP_MOUNTING;
+ m_mountpoint = backupDlg->txtMountPoint->text();
+
+ if (m_backupMount) {
+ progressCallback(0, 300, i18n("Mounting %1").arg(m_mountpoint));
+ proc << "mount";
+ proc << m_mountpoint;
+ proc.start();
+
+ } else {
+ // If we don't have to mount a device, we just issue
+ // a dummy command to start the copy operation
+ progressCallback(0, 300, "");
+ proc << "echo";
+ proc.start();
+ }
+
+ }
+
+ delete backupDlg;
+}
+
+
+/** No descriptions */
+void KMyMoney2App::slotProcessExited(void)
+{
+ switch(m_backupState) {
+ case BACKUP_MOUNTING:
+
+ if(proc.normalExit() && proc.exitStatus() == 0) {
+ proc.clearArguments();
+ QString today;
+ today.sprintf("-%04d-%02d-%02d.kmy",
+ QDate::currentDate().year(),
+ QDate::currentDate().month(),
+ QDate::currentDate().day());
+ QString backupfile = m_mountpoint + "/" + m_fileName.fileName(false);
+ KMyMoneyUtils::appendCorrectFileExt(backupfile, today);
+
+ // check if file already exists and ask what to do
+ m_backupResult = 0;
+ QFile f(backupfile);
+ if (f.exists()) {
+ int answer = KMessageBox::warningContinueCancel(this, i18n("Backup file for today exists on that device. Replace ?"), i18n("Backup"), i18n("&Replace"));
+ if (answer == KMessageBox::Cancel) {
+ m_backupResult = 1;
+
+ if (m_backupMount) {
+ progressCallback(250, 0, i18n("Unmounting %1").arg(m_mountpoint));
+ proc.clearArguments();
+ proc << "umount";
+ proc << m_mountpoint;
+ m_backupState = BACKUP_UNMOUNTING;
+ proc.start();
+ } else {
+ m_backupState = BACKUP_IDLE;
+ progressCallback(-1, -1, QString());
+ ready();
+ }
+ }
+ }
+
+ if(m_backupResult == 0) {
+ progressCallback(50, 0, i18n("Writing %1").arg(backupfile));
+ proc << "cp" << "-f" << m_fileName.path(0) << backupfile;
+ m_backupState = BACKUP_COPYING;
+ proc.start();
+ }
+
+ } else {
+ KMessageBox::information(this, i18n("Error mounting device"), i18n("Backup"));
+ m_backupResult = 1;
+ if (m_backupMount) {
+ progressCallback(250, 0, i18n("Unmounting %1").arg(m_mountpoint));
+ proc.clearArguments();
+ proc << "umount";
+ proc << m_mountpoint;
+ m_backupState = BACKUP_UNMOUNTING;
+ proc.start();
+
+ } else {
+ m_backupState = BACKUP_IDLE;
+ progressCallback(-1, -1, QString());
+ ready();
+ }
+ }
+ break;
+
+ case BACKUP_COPYING:
+ if(proc.normalExit() && proc.exitStatus() == 0) {
+
+ if (m_backupMount) {
+ progressCallback(250, 0, i18n("Unmounting %1").arg(m_mountpoint));
+ proc.clearArguments();
+ proc << "umount";
+ proc << m_mountpoint;
+ m_backupState = BACKUP_UNMOUNTING;
+ proc.start();
+ } else {
+ progressCallback(300, 0, i18n("Done"));
+ KMessageBox::information(this, i18n("File successfully backed up"), i18n("Backup"));
+ m_backupState = BACKUP_IDLE;
+ progressCallback(-1, -1, QString());
+ ready();
+ }
+ } else {
+ qDebug("cp exit status is %d", proc.exitStatus());
+ m_backupResult = 1;
+ KMessageBox::information(this, i18n("Error copying file to device"), i18n("Backup"));
+
+ if (m_backupMount) {
+ progressCallback(250, 0, i18n("Unmounting %1").arg(m_mountpoint));
+ proc.clearArguments();
+ proc << "umount";
+ proc << m_mountpoint;
+ m_backupState = BACKUP_UNMOUNTING;
+ proc.start();
+
+
+ } else {
+ m_backupState = BACKUP_IDLE;
+ progressCallback(-1, -1, QString());
+ ready();
+ }
+ }
+ break;
+
+
+ case BACKUP_UNMOUNTING:
+ if(proc.normalExit() && proc.exitStatus() == 0) {
+
+ progressCallback(300, 0, i18n("Done"));
+ if(m_backupResult == 0)
+ KMessageBox::information(this, i18n("File successfully backed up"), i18n("Backup"));
+ } else {
+ KMessageBox::information(this, i18n("Error unmounting device"), i18n("Backup"));
+ }
+ m_backupState = BACKUP_IDLE;
+ progressCallback(-1, -1, QString());
+ ready();
+ break;
+
+ default:
+ qWarning("Unknown state for backup operation!");
+ progressCallback(-1, -1, QString());
+ ready();
+ break;
+ }
+}
+
+void KMyMoney2App::slotFileNewWindow(void)
+{
+ KMyMoney2App *newWin = new KMyMoney2App;
+
+ newWin->show();
+}
+
+void KMyMoney2App::slotShowTipOfTheDay(void)
+{
+ KTipDialog::showTip(myMoneyView, "", true);
+}
+
+void KMyMoney2App::slotShowPreviousView(void)
+{
+
+}
+
+void KMyMoney2App::slotShowNextView(void)
+{
+
+}
+
+void KMyMoney2App::slotQifProfileEditor(void)
+{
+ MyMoneyQifProfileEditor* editor = new MyMoneyQifProfileEditor(true, this, "QIF Profile Editor");
+
+
+ editor->exec();
+
+ delete editor;
+
+}
+
+void KMyMoney2App::slotToolsStartKCalc(void)
+{
+ QString cmd = KMyMoneyGlobalSettings::externalCalculator();
+ // if none is present, we fall back to the default
+ if(cmd.isEmpty())
+ cmd = "kcalc";
+ KRun::runCommand(cmd);
+}
+
+void KMyMoney2App::slotFindTransaction(void)
+{
+ if(m_searchDlg == 0) {
+ m_searchDlg = new KFindTransactionDlg();
+ connect(m_searchDlg, SIGNAL(destroyed()), this, SLOT(slotCloseSearchDialog()));
+ connect(m_searchDlg, SIGNAL(transactionSelected(const QString&, const QString&)),
+ myMoneyView, SLOT(slotLedgerSelected(const QString&, const QString&)));
+ }
+ m_searchDlg->show();
+ m_searchDlg->raise();
+ m_searchDlg->setActiveWindow();
+}
+
+void KMyMoney2App::slotCloseSearchDialog(void)
+{
+ if(m_searchDlg)
+ m_searchDlg->deleteLater();
+ m_searchDlg = 0;
+}
+
+void KMyMoney2App::createInstitution(MyMoneyInstitution& institution)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MyMoneyFileTransaction ft;
+
+ try {
+ file->addInstitution(institution);
+ ft.commit();
+
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Cannot add institution: %1").arg(e->what()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotInstitutionNew(void)
+{
+ MyMoneyInstitution institution;
+ slotInstitutionNew(institution);
+}
+
+void KMyMoney2App::slotInstitutionNew(MyMoneyInstitution& institution)
+{
+ institution.clearId();
+ KNewBankDlg dlg(institution);
+ if (dlg.exec()) {
+ institution = dlg.institution();
+ createInstitution(institution);
+ }
+}
+
+void KMyMoney2App::slotInstitutionEdit(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyInstitution))
+ return;
+
+ try {
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //grab a pointer to the view, regardless of it being a account or institution view.
+ MyMoneyInstitution institution = file->institution(m_selectedInstitution.id());
+
+ // bankSuccess is not checked anymore because m_file->institution will throw anyway
+ KNewBankDlg dlg(institution);
+ if (dlg.exec()) {
+ MyMoneyFileTransaction ft;
+ try {
+ file->modifyInstitution(dlg.institution());
+ ft.commit();
+ slotSelectInstitution(file->institution(dlg.institution().id()));
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to store institution: %1").arg(e->what()));
+ delete e;
+ }
+ }
+
+ } catch(MyMoneyException *e) {
+ if(!obj.id().isEmpty())
+ KMessageBox::information(this, i18n("Unable to edit institution: %1").arg(e->what()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotInstitutionDelete(void)
+{
+ MyMoneyFile *file = MyMoneyFile::instance();
+ try {
+
+ MyMoneyInstitution institution = file->institution(m_selectedInstitution.id());
+ if ((KMessageBox::questionYesNo(this, QString("<p>")+i18n("Do you really want to delete institution <b>%1</b> ?").arg(institution.name()))) == KMessageBox::No)
+ return;
+ MyMoneyFileTransaction ft;
+
+ try {
+ file->removeInstitution(institution);
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to delete institution: %1").arg(e->what()));
+ delete e;
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to delete institution: %1").arg(e->what()));
+ delete e;
+ }
+}
+
+const MyMoneyAccount& KMyMoney2App::findAccount(const MyMoneyAccount& acc, const MyMoneyAccount& parent) const
+{
+ static MyMoneyAccount nullAccount;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyAccount> parents;
+ try {
+ // search by id
+ if(!acc.id().isEmpty()) {
+ return file->account(acc.id());
+ }
+ // collect the parents. in case parent does not have an id, we scan the all top-level accounts
+ if(parent.id().isEmpty()) {
+ parents << file->asset();
+ parents << file->liability();
+ parents << file->income();
+ parents << file->expense();
+ parents << file->equity();
+ } else {
+ parents << parent;
+ }
+ QValueList<MyMoneyAccount>::const_iterator it_p;
+ for(it_p = parents.begin(); it_p != parents.end(); ++it_p) {
+ MyMoneyAccount parentAccount = *it_p;
+ // search by name (allow hierarchy)
+ int pos;
+ // check for ':' in the name and use it as separator for a hierarchy
+ QString name = acc.name();
+ while((pos = name.find(MyMoneyFile::AccountSeperator)) != -1) {
+ QString part = name.left(pos);
+ QString remainder = name.mid(pos+1);
+ const MyMoneyAccount& existingAccount = file->subAccountByName(parentAccount, part);
+ if(existingAccount.id().isEmpty()) {
+ return existingAccount;
+ }
+ parentAccount = existingAccount;
+ name = remainder;
+ }
+ const MyMoneyAccount& existingAccount = file->subAccountByName(parentAccount, name);
+ if(!existingAccount.id().isEmpty()) {
+ if(acc.accountType() != MyMoneyAccount::UnknownAccountType) {
+ if(acc.accountType() != existingAccount.accountType())
+ continue;
+ }
+ return existingAccount;
+ }
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::error(0, i18n("Unable to find account: %1").arg(e->what()));
+ delete e;
+ }
+ return nullAccount;
+}
+
+void KMyMoney2App::createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // make sure we have a currency. If none is assigned, we assume base currency
+ if(newAccount.currencyId().isEmpty())
+ newAccount.setCurrencyId(file->baseCurrency().id());
+
+ MyMoneyFileTransaction ft;
+ try
+ {
+ int pos;
+ // check for ':' in the name and use it as separator for a hierarchy
+ while((pos = newAccount.name().find(MyMoneyFile::AccountSeperator)) != -1) {
+ QString part = newAccount.name().left(pos);
+ QString remainder = newAccount.name().mid(pos+1);
+ const MyMoneyAccount& existingAccount = file->subAccountByName(parentAccount, part);
+ if(existingAccount.id().isEmpty()) {
+ newAccount.setName(part);
+
+ file->addAccount(newAccount, parentAccount);
+ parentAccount = newAccount;
+ } else {
+ parentAccount = existingAccount;
+ }
+ newAccount.setParentAccountId(QString()); // make sure, there's no parent
+ newAccount.clearId(); // and no id set for adding
+ newAccount.removeAccountIds(); // and no sub-account ids
+ newAccount.setName(remainder);
+ }
+
+ const MyMoneySecurity& sec = file->security(newAccount.currencyId());
+ // Check the opening balance
+ if (openingBal.isPositive() && newAccount.accountGroup() == MyMoneyAccount::Liability)
+ {
+ QString message = i18n("This account is a liability and if the "
+ "opening balance represents money owed, then it should be negative. "
+ "Negate the amount?\n\n"
+ "Please click Yes to change the opening balance to %1,\n"
+ "Please click No to leave the amount as %2,\n"
+ "Please click Cancel to abort the account creation.")
+ .arg((-openingBal).formatMoney(newAccount, sec))
+ .arg(openingBal.formatMoney(newAccount, sec));
+
+ int ans = KMessageBox::questionYesNoCancel(this, message);
+ if (ans == KMessageBox::Yes) {
+ openingBal = -openingBal;
+
+ } else if (ans == KMessageBox::Cancel)
+ return;
+ }
+
+ file->addAccount(newAccount, parentAccount);
+
+ // in case of a loan account, we add the initial payment
+ if((newAccount.accountType() == MyMoneyAccount::Loan
+ || newAccount.accountType() == MyMoneyAccount::AssetLoan)
+ && !newAccount.value("kmm-loan-payment-acc").isEmpty()
+ && !newAccount.value("kmm-loan-payment-date").isEmpty()) {
+ MyMoneyAccountLoan acc(newAccount);
+ MyMoneyTransaction t;
+ MyMoneySplit a, b;
+ a.setAccountId(acc.id());
+ b.setAccountId(acc.value("kmm-loan-payment-acc").latin1());
+ a.setValue(acc.loanAmount());
+ if(acc.accountType() == MyMoneyAccount::Loan)
+ a.setValue(-a.value());
+
+ a.setShares(a.value());
+ b.setValue(-a.value());
+ b.setShares(b.value());
+ a.setMemo(i18n("Loan payout"));
+ b.setMemo(i18n("Loan payout"));
+ t.setPostDate(QDate::fromString(acc.value("kmm-loan-payment-date"), Qt::ISODate));
+ newAccount.deletePair("kmm-loan-payment-acc");
+ newAccount.deletePair("kmm-loan-payment-date");
+ MyMoneyFile::instance()->modifyAccount(newAccount);
+
+ t.addSplit(a);
+ t.addSplit(b);
+ file->addTransaction(t);
+ file->createOpeningBalanceTransaction(newAccount, openingBal);
+
+ // in case of an investment account we check if we should create
+ // a brokerage account
+ } else if(newAccount.accountType() == MyMoneyAccount::Investment
+ && !brokerageAccount.name().isEmpty()) {
+ file->addAccount(brokerageAccount, parentAccount);
+
+ // set a link from the investment account to the brokerage account
+ file->modifyAccount(newAccount);
+ file->createOpeningBalanceTransaction(brokerageAccount, openingBal);
+
+ } else
+ file->createOpeningBalanceTransaction(newAccount, openingBal);
+
+ ft.commit();
+ }
+ catch (MyMoneyException *e)
+ {
+ KMessageBox::information(this, i18n("Unable to add account: %1").arg(e->what()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotCategoryNew(const QString& name, QString& id)
+{
+ MyMoneyAccount account;
+ account.setName(name);
+
+ slotCategoryNew(account, MyMoneyFile::instance()->expense());
+
+ id = account.id();
+}
+
+void KMyMoney2App::slotCategoryNew(MyMoneyAccount& account, const MyMoneyAccount& parent)
+{
+ if(KMessageBox::questionYesNo(this,
+ QString("<qt>%1</qt>").arg(i18n("The category <b>%1</b> currently does not exist. Do you want to create it?<p><i>The parent account will default to <b>%2</b> but can be changed in the following dialog</i>.").arg(account.name()).arg(parent.name())), i18n("Create category"),
+ KStdGuiItem::yes(), KStdGuiItem::no(), "CreateNewCategories") == KMessageBox::Yes) {
+ createCategory(account, parent);
+ } else {
+ // we should not keep the 'no' setting because that can confuse people like
+ // I have seen in some usability tests. So we just delete it right away.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig) {
+ kconfig->setGroup(QString::fromLatin1("Notification Messages"));
+ kconfig->deleteEntry(QString::fromLatin1("CreateNewCategories"));
+ }
+ }
+}
+
+void KMyMoney2App::slotCategoryNew(void)
+{
+ MyMoneyAccount parent;
+ MyMoneyAccount account;
+
+ // Preselect the parent account by looking at the current selected account/category
+ if(!m_selectedAccount.id().isEmpty() && m_selectedAccount.isIncomeExpense()) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ try {
+ parent = file->account(m_selectedAccount.id());
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+
+ createCategory(account, parent);
+}
+
+void KMyMoney2App::createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent)
+{
+ if(!parent.id().isEmpty()) {
+ try {
+ // make sure parent account exists
+ MyMoneyFile::instance()->account(parent.id());
+ account.setParentAccountId(parent.id());
+ account.setAccountType( parent.accountType() );
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+
+ KNewAccountDlg dialog(account, false, true, 0, 0, i18n("Create a new Category"));
+
+ if(dialog.exec() == QDialog::Accepted) {
+ MyMoneyAccount parentAccount, brokerageAccount;
+ account = dialog.account();
+ parentAccount = dialog.parentAccount();
+
+ createAccount(account, parentAccount, brokerageAccount, MyMoneyMoney(0,1));
+ }
+}
+
+void KMyMoney2App::slotAccountNew(void)
+{
+ MyMoneyAccount acc;
+ acc.setOpeningDate(QDate::currentDate());
+
+ slotAccountNew(acc);
+}
+
+void KMyMoney2App::slotAccountNew(MyMoneyAccount& account)
+{
+ NewAccountWizard::Wizard* wizard = new NewAccountWizard::Wizard();
+ connect(wizard, SIGNAL(createInstitution(MyMoneyInstitution&)), this, SLOT(slotInstitutionNew(MyMoneyInstitution&)));
+ connect(wizard, SIGNAL(createAccount(MyMoneyAccount&)), this, SLOT(slotAccountNew(MyMoneyAccount&)));
+ connect(wizard, SIGNAL(createPayee(const QString&, QString&)), this, SLOT(slotPayeeNew(const QString&, QString&)));
+ connect(wizard, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)), this, SLOT(slotCategoryNew(MyMoneyAccount&, const MyMoneyAccount&)));
+
+ wizard->setAccount(account);
+
+ if(wizard->exec() == QDialog::Accepted) {
+ MyMoneyAccount acc = wizard->account();
+ if(!(acc == MyMoneyAccount())) {
+ MyMoneyFileTransaction ft;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ try {
+ // create the account
+ MyMoneyAccount parent = wizard->parentAccount();
+ file->addAccount(acc, parent);
+
+ // tell the wizard about the account id which it
+ // needs to create a possible schedule and transactions
+ wizard->setAccount(acc);
+
+ // store a possible conversion rate for the currency
+ if(acc.currencyId() != file->baseCurrency().id()) {
+ file->addPrice(wizard->conversionRate());
+ }
+
+ // create the opening balance transaction if any
+ file->createOpeningBalanceTransaction(acc, wizard->openingBalance());
+ // create the payout transaction for loans if any
+ MyMoneyTransaction payoutTransaction = wizard->payoutTransaction();
+ if(payoutTransaction.splits().count() > 0) {
+ file->addTransaction(payoutTransaction);
+ }
+
+ // create a brokerage account if selected
+ MyMoneyAccount brokerageAccount = wizard->brokerageAccount();
+ if(!(brokerageAccount == MyMoneyAccount())) {
+ file->addAccount(brokerageAccount, parent);
+ }
+
+ // create a possible schedule
+ MyMoneySchedule sch = wizard->schedule();
+ if(!(sch == MyMoneySchedule())) {
+ MyMoneyFile::instance()->addSchedule(sch);
+ if(acc.isLoan()) {
+ MyMoneyAccountLoan accLoan = MyMoneyFile::instance()->account(acc.id());
+ accLoan.setSchedule(sch.id());
+ acc = accLoan;
+ MyMoneyFile::instance()->modifyAccount(acc);
+ }
+ }
+ ft.commit();
+ account = acc;
+ } catch (MyMoneyException *e) {
+ KMessageBox::error(this, i18n("Unable to create account: %1").arg(e->what()));
+ }
+ }
+ }
+ delete wizard;
+}
+
+void KMyMoney2App::slotInvestmentNew(MyMoneyAccount& account, const MyMoneyAccount& parent)
+{
+ QString dontShowAgain = "CreateNewInvestments";
+ if(KMessageBox::questionYesNo(this,
+ QString("<qt>")+i18n("The security <b>%1</b> currently does not exist as sub-account of <b>%2</b>. "
+ "Do you want to create it?").arg(account.name()).arg(parent.name())+QString("</qt>"), i18n("Create security"),
+ KStdGuiItem::yes(), KStdGuiItem::no(), dontShowAgain) == KMessageBox::Yes) {
+ KNewInvestmentWizard dlg;
+ dlg.setName(account.name());
+ if(dlg.exec() == QDialog::Accepted) {
+ dlg.createObjects(parent.id());
+ account = dlg.account();
+ }
+ } else {
+ // in case the user said no but turned on the don't show again selection, we will enable
+ // the message no matter what. Otherwise, the user is not able to use this feature
+ // in the future anymore.
+ KMessageBox::enableMessage(dontShowAgain);
+ }
+}
+
+void KMyMoney2App::slotInvestmentNew(void)
+{
+ KNewInvestmentWizard dlg;
+ if(dlg.exec() == QDialog::Accepted) {
+ dlg.createObjects(m_selectedAccount.id());
+ }
+}
+
+void KMyMoney2App::slotInvestmentEdit(void)
+{
+ KNewInvestmentWizard dlg(m_selectedInvestment);
+ if(dlg.exec() == QDialog::Accepted) {
+ dlg.createObjects(m_selectedAccount.id());
+ }
+}
+
+void KMyMoney2App::slotInvestmentDelete(void)
+{
+ if(KMessageBox::questionYesNo(this, QString("<p>")+i18n("Do you really want to delete the investment <b>%1</b>?").arg(m_selectedInvestment.name()), i18n("Delete investment"), KStdGuiItem::yes(), KStdGuiItem::no(), "DeleteInvestment") == KMessageBox::Yes) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyFileTransaction ft;
+ try {
+ file->removeAccount(m_selectedInvestment);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to delete investment: %1").arg(e->what()));
+ delete e;
+ }
+ } else {
+ // we should not keep the 'no' setting because that can confuse people like
+ // I have seen in some usability tests. So we just delete it right away.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig) {
+ kconfig->setGroup(QString::fromLatin1("Notification Messages"));
+ kconfig->deleteEntry(QString::fromLatin1("DeleteInvestment"));
+ }
+ }
+}
+
+void KMyMoney2App::slotOnlinePriceUpdate(void)
+{
+ if(!m_selectedInvestment.id().isEmpty()) {
+ KEquityPriceUpdateDlg dlg(0, m_selectedInvestment.currencyId());
+ if(dlg.exec() == QDialog::Accepted)
+ dlg.storePrices();
+ }
+}
+
+void KMyMoney2App::slotManualPriceUpdate(void)
+{
+ if(!m_selectedInvestment.id().isEmpty()) {
+ try {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(m_selectedInvestment.currencyId());
+ MyMoneySecurity currency = MyMoneyFile::instance()->security(security.tradingCurrency());
+ MyMoneyPrice price = MyMoneyFile::instance()->price(security.id(), currency.id());
+ signed64 fract = MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision());
+
+ KCurrencyCalculator calc(security, currency, MyMoneyMoney(1,1), price.rate(currency.id()), price.date(), fract);
+ calc.setupPriceEditor();
+
+ // The dialog takes care of adding the price if necessary
+ calc.exec();
+ } catch(MyMoneyException* e) {
+ qDebug("Error in price update: %s", e->what().data());
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ // Add the schedule only if one exists
+ //
+ // Remember to modify the first split to reference the newly created account
+ if (!newSchedule.name().isEmpty())
+ {
+ try
+ {
+ // We assume at least 2 splits in the transaction
+ MyMoneyTransaction t = newSchedule.transaction();
+ if(t.splitCount() < 2) {
+ throw new MYMONEYEXCEPTION("Transaction for schedule has less than 2 splits!");
+ }
+#if 0
+ // now search the split that does not have an account reference
+ // and set it up to be the one of the account we just added
+ // to the account pool. Note: the schedule code used to leave
+ // this always the first split, but the loan code leaves it as
+ // the second one. So I thought, searching is a good alternative ....
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).accountId().isEmpty()) {
+ MyMoneySplit s = (*it_s);
+ s.setAccountId(newAccount.id());
+ t.modifySplit(s);
+ break;
+ }
+ }
+ newSchedule.setTransaction(t);
+#endif
+
+ MyMoneyFileTransaction ft;
+ try {
+ file->addSchedule(newSchedule);
+
+ // in case of a loan account, we keep a reference to this
+ // schedule in the account
+ if(newAccount.accountType() == MyMoneyAccount::Loan
+ || newAccount.accountType() == MyMoneyAccount::AssetLoan) {
+ newAccount.setValue("schedule", newSchedule.id());
+ file->modifyAccount(newAccount);
+ }
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(this, i18n("Unable to add scheduled transaction: "), e->what());
+ delete e;
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ KMessageBox::information(this, i18n("Unable to add scheduled transaction: "), e->what());
+ delete e;
+ }
+ }
+}
+
+bool KMyMoney2App::exchangeAccountInTransaction(MyMoneyTransaction& _t, const QString& fromId, const QString& toId)
+{
+ bool rc = false;
+ MyMoneyTransaction t(_t);
+ QValueList<MyMoneySplit>::iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).accountId() == fromId) {
+ (*it_s).setAccountId(toId);
+ _t.modifySplit(*it_s);
+ rc = true;
+ }
+ }
+ return rc;
+}
+
+void KMyMoney2App::slotAccountDelete(void)
+{
+ if (m_selectedAccount.id().isEmpty())
+ return; // need an account ID
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ // can't delete standard accounts or account which still have transactions assigned
+ if (file->isStandardAccount(m_selectedAccount.id()))
+ return;
+
+ // check if the account is referenced by a transaction or schedule
+ MyMoneyFileBitArray skip(IMyMoneyStorage::MaxRefCheckBits);
+ skip.fill(false);
+ skip.setBit(IMyMoneyStorage::RefCheckAccount);
+ skip.setBit(IMyMoneyStorage::RefCheckInstitution);
+ skip.setBit(IMyMoneyStorage::RefCheckPayee);
+ skip.setBit(IMyMoneyStorage::RefCheckSecurity);
+ skip.setBit(IMyMoneyStorage::RefCheckCurrency);
+ skip.setBit(IMyMoneyStorage::RefCheckPrice);
+ bool hasReference = file->isReferenced(m_selectedAccount, skip);
+
+ // make sure we only allow transactions in a 'category' (income/expense account)
+ switch(m_selectedAccount.accountType()) {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ break;
+
+ default:
+ // if the account is still referenced
+ if(hasReference) {
+ return;
+ }
+ break;
+ }
+
+ // if we get here and still have transactions referencing the account, we
+ // need to check with the user to possibly re-assign them to a different account
+ bool needAskUser = true;
+ bool exit = false;
+
+ MyMoneyFileTransaction ft;
+
+ if(hasReference) {
+ // show transaction reassignment dialog
+
+ needAskUser = false;
+ KCategoryReassignDlg* dlg = new KCategoryReassignDlg(this);
+ QString categoryId = dlg->show(m_selectedAccount);
+ delete dlg; // and kill the dialog
+ if (categoryId.isEmpty())
+ return; // the user aborted the dialog, so let's abort as well
+
+ MyMoneyAccount newCategory = file->account(categoryId);
+ try {
+ {
+ KMSTATUS(i18n("Adjusting transactions..."));
+ /*
+ m_selectedAccount.id() is the old id, categoryId the new one
+ Now search all transactions and schedules that reference m_selectedAccount.id()
+ and replace that with categoryId.
+ */
+ // get the list of all transactions that reference the old account
+ MyMoneyTransactionFilter filter(m_selectedAccount.id());
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> tlist;
+ QValueList<MyMoneyTransaction>::iterator it_t;
+ file->transactionList(tlist, filter);
+
+ slotStatusProgressBar(0, tlist.count());
+ int cnt = 0;
+ for(it_t = tlist.begin(); it_t != tlist.end(); ++it_t) {
+ slotStatusProgressBar(++cnt, 0);
+ MyMoneyTransaction t = (*it_t);
+ if(exchangeAccountInTransaction(t, m_selectedAccount.id(), categoryId))
+ file->modifyTransaction(t);
+ }
+ slotStatusProgressBar(tlist.count(), 0);
+ }
+ // now fix all schedules
+ {
+ KMSTATUS(i18n("Adjusting scheduled transactions..."));
+ QValueList<MyMoneySchedule> slist = file->scheduleList(m_selectedAccount.id());
+ QValueList<MyMoneySchedule>::iterator it_s;
+
+ int cnt = 0;
+ slotStatusProgressBar(0, slist.count());
+ for(it_s = slist.begin(); it_s != slist.end(); ++it_s) {
+ slotStatusProgressBar(++cnt, 0);
+ MyMoneyTransaction t = (*it_s).transaction();
+ if(exchangeAccountInTransaction(t, m_selectedAccount.id(), categoryId)) {
+ (*it_s).setTransaction(t);
+ file->modifySchedule(*it_s);
+ }
+ }
+ slotStatusProgressBar(slist.count(), 0);
+ }
+ // now fix all budgets
+ {
+ KMSTATUS(i18n("Adjusting budgets..."));
+ QValueList<MyMoneyBudget> blist = file->budgetList();
+ QValueList<MyMoneyBudget>::const_iterator it_b;
+ for(it_b = blist.begin(); it_b != blist.end(); ++it_b) {
+ if((*it_b).hasReferenceTo(m_selectedAccount.id())) {
+ MyMoneyBudget b = (*it_b);
+ MyMoneyBudget::AccountGroup fromBudget = b.account(m_selectedAccount.id());
+ MyMoneyBudget::AccountGroup toBudget = b.account(categoryId);
+ toBudget += fromBudget;
+ b.setAccount(toBudget, toBudget.id());
+ b.removeReference(m_selectedAccount.id());
+ file->modifyBudget(b);
+
+ }
+ }
+ slotStatusProgressBar(blist.count(), 0);
+ }
+ } catch(MyMoneyException *e) {
+ KMessageBox::error( this, i18n("Unable to exchange category <b>%1</b> with category <b>%2</b>. Reason: %3").arg(m_selectedAccount.name()).arg(newCategory.name()).arg(e->what()));
+ delete e;
+ exit = true;
+ }
+ slotStatusProgressBar(-1, -1);
+ }
+
+ if(exit)
+ return;
+
+ // at this point, we must not have a reference to the account
+ // to be deleted anymore
+ switch(m_selectedAccount.accountGroup()) {
+ // special handling for categories to allow deleting of empty subcategories
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ { // open a compound statement here to be able to declare variables
+ // which would otherwise not work within a case label.
+
+ // case A - only a single, unused category without subcats selected
+ if (m_selectedAccount.accountList().isEmpty()) {
+ if (!needAskUser || (KMessageBox::questionYesNo(this, QString("<qt>")+i18n("Do you really want to delete category <b>%1</b>?").arg(m_selectedAccount.name())+QString("</qt>")) == KMessageBox::Yes)) {
+ try {
+ file->removeAccount(m_selectedAccount);
+ m_selectedAccount.clearId();
+ slotUpdateActions();
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::error( this, QString("<qt>")+i18n("Unable to delete category <b>%1</b>. Cause: %2").arg(m_selectedAccount.name()).arg(e->what())+QString("</qt>"));
+ delete e;
+ }
+ }
+ return;
+ }
+ // case B - we have some subcategories, maybe the user does not want to
+ // delete them all, but just the category itself?
+ MyMoneyAccount parentAccount = file->account(m_selectedAccount.parentAccountId());
+
+ QStringList accountsToReparent;
+ int result = KMessageBox::questionYesNoCancel(this, QString("<qt>")+
+ i18n("Do you want to delete category <b>%1</b> with all its sub-categories or only "
+ "the category itself? If you only delete the category itself, all its sub-categories "
+ "will be made sub-categories of <b>%2</b>.").arg(m_selectedAccount.name()).arg(parentAccount.name())+QString("</qt>"),
+ QString::null,
+ KGuiItem(i18n("Delete all")),
+ KGuiItem(i18n("Just the category")));
+ if (result == KMessageBox::Cancel)
+ return; // cancel pressed? ok, no delete then...
+ // "No" means "Just the category" and that means we need to reparent all subaccounts
+ bool need_confirmation = false;
+ // case C - User only wants to delete the category itself
+ if (result == KMessageBox::No)
+ accountsToReparent = m_selectedAccount.accountList();
+ else {
+ // case D - User wants to delete all subcategories, now check all subcats of
+ // m_selectedAccount and remember all that cannot be deleted and
+ // must be "reparented"
+ for (QStringList::const_iterator it = m_selectedAccount.accountList().begin();
+ it != m_selectedAccount.accountList().end(); ++it)
+ {
+ // reparent account if a transaction is assigned
+ if (file->transactionCount(*it)!=0)
+ accountsToReparent.push_back(*it);
+ else if (!file->account(*it).accountList().isEmpty()) {
+ // or if we have at least one sub-account that is used for transactions
+ if (!file->hasOnlyUnusedAccounts(file->account(*it).accountList())) {
+ accountsToReparent.push_back(*it);
+ //kdDebug() << "subaccount not empty" << endl;
+ }
+ }
+ }
+ if (!accountsToReparent.isEmpty())
+ need_confirmation = true;
+ }
+ if (!accountsToReparent.isEmpty() && need_confirmation) {
+ if (KMessageBox::questionYesNo(this, QString("<p>")+i18n("Some sub-categories of category <b>%1</b> cannot "
+ "be deleted, because they are still used. They will be made sub-categories of <b>%2</b>. Proceed?").arg(m_selectedAccount.name()).arg(parentAccount.name())) != KMessageBox::Yes) {
+ return; // user gets wet feet...
+ }
+ }
+ // all good, now first reparent selected sub-categories
+ try {
+ MyMoneyAccount parent = file->account(m_selectedAccount.parentAccountId());
+ for (QStringList::const_iterator it = accountsToReparent.begin(); it != accountsToReparent.end(); ++it) {
+ MyMoneyAccount child = file->account(*it);
+ file->reparentAccount(child, parent);
+ }
+ // reload the account because the sub-account list might have changed
+ m_selectedAccount = file->account(m_selectedAccount.id());
+ // now recursively delete remaining sub-categories
+ file->removeAccountList(m_selectedAccount.accountList());
+ // don't forget to update m_selectedAccount, because we still have a copy of
+ // the old account list, which is no longer valid
+ m_selectedAccount = file->account(m_selectedAccount.id());
+ } catch(MyMoneyException* e) {
+ KMessageBox::error( this, QString("<qt>")+i18n("Unable to delete a sub-category of category <b>%1</b>. Reason: %2").arg(m_selectedAccount.name()).arg(e->what())+QString("</qt>"));
+ delete e;
+ return;
+ }
+ }
+ break; // the category/account is deleted after the switch
+
+ default:
+ if (!m_selectedAccount.accountList().isEmpty())
+ return; // can't delete accounts which still have subaccounts
+
+ if (KMessageBox::questionYesNo(this, QString("<p>")+i18n("Do you really want to "
+ "delete account <b>%1</b>?").arg(m_selectedAccount.name())) != KMessageBox::Yes) {
+ return; // ok, you don't want to? why did you click then, hmm?
+ }
+ } // switch;
+
+ try {
+ file->removeAccount(m_selectedAccount);
+ m_selectedAccount.clearId();
+ slotUpdateActions();
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::error( this, i18n("Unable to delete account '%1'. Cause: %2").arg(m_selectedAccount.name()).arg(e->what()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotAccountEdit(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ if(!m_selectedAccount.id().isEmpty()) {
+ if(!file->isStandardAccount(m_selectedAccount.id())) {
+ if(m_selectedAccount.accountType() != MyMoneyAccount::Loan
+ && m_selectedAccount.accountType() != MyMoneyAccount::AssetLoan) {
+ QString caption;
+ bool category = false;
+ switch(MyMoneyAccount::accountGroup(m_selectedAccount.accountType())) {
+ default:
+ caption = i18n("Edit account '%1'").arg(m_selectedAccount.name());
+ break;
+
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::Income:
+ caption = i18n("Edit category '%1'").arg(m_selectedAccount.name());
+ category = true;
+ break;
+ }
+ QString tid = file->openingBalanceTransaction(m_selectedAccount);
+ MyMoneyTransaction t;
+ MyMoneySplit s0, s1;
+ KNewAccountDlg dlg(m_selectedAccount, true, category, 0, 0, caption);
+
+ if(category || m_selectedAccount.accountType() == MyMoneyAccount::Investment) {
+ dlg.setOpeningBalanceShown(false);
+ } else {
+ if(!tid.isEmpty()) {
+ try {
+ t = file->transaction(tid);
+ s0 = t.splitByAccount(m_selectedAccount.id());
+ s1 = t.splitByAccount(m_selectedAccount.id(), false);
+ dlg.setOpeningBalance(s0.shares());
+ if(m_selectedAccount.accountGroup() == MyMoneyAccount::Liability) {
+ dlg.setOpeningBalance(-s0.shares());
+ }
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << "Error retrieving opening balance transaction " << tid << ": " << e->what() << "\n";
+ tid = QString();
+ delete e;
+ }
+ }
+ }
+
+ // check for online modules
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin *>::const_iterator it_plugin = m_onlinePlugins.end();
+ const MyMoneyKeyValueContainer& kvp = m_selectedAccount.onlineBankingSettings();
+ if(!kvp["provider"].isEmpty()) {
+ // if we have an online provider for this account, we need to check
+ // that we have the corresponding plugin. If that exists, we ask it
+ // to provide an additional tab for the account editor.
+ it_plugin = m_onlinePlugins.find(kvp["provider"]);
+ if(it_plugin != m_onlinePlugins.end()) {
+ QString name;
+ QWidget *w = 0;
+ w = (*it_plugin)->accountConfigTab(m_selectedAccount, name);
+ dlg.addTab(w, name);
+ }
+ }
+
+ if (dlg.exec() == QDialog::Accepted) {
+ try {
+ MyMoneyFileTransaction ft;
+
+ MyMoneyAccount account = dlg.account();
+ MyMoneyAccount parent = dlg.parentAccount();
+ if(it_plugin != m_onlinePlugins.end()) {
+ account.setOnlineBankingSettings((*it_plugin)->onlineBankingSettings(account.onlineBankingSettings()));
+ }
+ MyMoneyMoney bal = dlg.openingBalance();
+ if(m_selectedAccount.accountGroup() == MyMoneyAccount::Liability) {
+ bal = -bal;
+ }
+
+ // we need to modify first, as reparent would override all other changes
+ file->modifyAccount(account);
+ if(account.parentAccountId() != parent.id()) {
+ file->reparentAccount(account, parent);
+ }
+ if(!tid.isEmpty() && dlg.openingBalance().isZero()) {
+ file->removeTransaction(t);
+
+ } else if(!tid.isEmpty() && !dlg.openingBalance().isZero()) {
+ s0.setShares(bal);
+ s0.setValue(bal);
+ t.modifySplit(s0);
+ s1.setShares(-bal);
+ s1.setValue(-bal);
+ t.modifySplit(s1);
+ file->modifyTransaction(t);
+
+ } else if(tid.isEmpty() && !dlg.openingBalance().isZero()){
+ file->createOpeningBalanceTransaction(m_selectedAccount, bal);
+ }
+
+ ft.commit();
+
+ // reload the account object as it might have changed in the meantime
+ slotSelectAccount(file->account(account.id()));
+
+ } catch(MyMoneyException* e) {
+ KMessageBox::error( this, i18n("Unable to modify account '%1'. Cause: %2").arg(m_selectedAccount.name()).arg(e->what()));
+ delete e;
+ }
+ }
+ } else {
+ KEditLoanWizard* wizard = new KEditLoanWizard(m_selectedAccount);
+ connect(wizard, SIGNAL(newCategory(MyMoneyAccount&)), this, SLOT(slotCategoryNew(MyMoneyAccount&)));
+ connect(wizard, SIGNAL(createPayee(const QString&, QString&)), this, SLOT(slotPayeeNew(const QString&, QString&)));
+ if(wizard->exec() == QDialog::Accepted) {
+ MyMoneySchedule sch = file->schedule(m_selectedAccount.value("schedule").latin1());
+ if(!(m_selectedAccount == wizard->account())
+ || !(sch == wizard->schedule())) {
+ MyMoneyFileTransaction ft;
+ try {
+ file->modifyAccount(wizard->account());
+ sch = wizard->schedule();
+ try {
+ file->schedule(sch.id());
+ file->modifySchedule(sch);
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ try {
+ file->addSchedule(sch);
+ ft.commit();
+ } catch (MyMoneyException *f) {
+ qDebug("Cannot add schedule: '%s'", f->what().data());
+ delete f;
+ }
+ delete e;
+ }
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to modify account %s: '%s'", m_selectedAccount.name().data(),
+ e->what().data());
+ delete e;
+ }
+ }
+ }
+ delete wizard;
+ }
+ }
+ }
+}
+
+void KMyMoney2App::slotAccountReconcileStart(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount account;
+
+ // we cannot reconcile standard accounts
+ if(!file->isStandardAccount(m_selectedAccount.id())) {
+ // check if we can reconcile this account
+ // it make's sense for asset and liability accounts
+ try {
+#if 0
+ // check if we have overdue schedules for this account
+ QValueList<MyMoneySchedule> schedules = file->scheduleList(m_selectedAccount.id(), MyMoneySchedule::TYPE_ANY, MyMoneySchedule::OCCUR_ANY, MyMoneySchedule::STYPE_ANY, QDate(), QDate(), true);
+ if(schedules.count() > 0) {
+ if(KMessageBox::questionYesNo(this, i18n("KMyMoney has detected some overdue scheduled transactions for this account. Do you want to enter those scheduled transactions now?"), i18n("Scheduled transactions found")) == KMessageBox::Yes) {
+
+ QMap<QString, bool> skipMap;
+ bool processedOne;
+ KMyMoneyUtils::EnterScheduleResultCodeE rc = KMyMoneyUtils::Enter;
+ do {
+ processedOne = false;
+ QValueList<MyMoneySchedule>::const_iterator it_sch;
+ for(it_sch = schedules.begin(); (rc != KMyMoneyUtils::Cancel) && (it_sch != schedules.end()); ++it_sch) {
+ MyMoneySchedule sch(*(it_sch));
+
+ // and enter it if it is not on the skip list
+ if(skipMap.find((*it_sch).id()) == skipMap.end()) {
+ rc = enterSchedule(sch, false, true);
+ if(rc == KMyMoneyUtils::Ignore) {
+ skipMap[(*it_sch).id()] = true;
+ }
+ }
+ }
+
+ // reload list (maybe this schedule needs to be added again)
+ schedules = file->scheduleList(m_selectedAccount.id(), MyMoneySchedule::TYPE_ANY, MyMoneySchedule::OCCUR_ANY, MyMoneySchedule::STYPE_ANY, QDate(), QDate(), true);
+ } while(processedOne);
+ }
+ }
+#endif
+
+ account = file->account(m_selectedAccount.id());
+ // get rid of previous run.
+ if(m_endingBalanceDlg)
+ delete m_endingBalanceDlg;
+ m_endingBalanceDlg = new KEndingBalanceDlg(account, this);
+ if(account.isAssetLiability()) {
+ connect(m_endingBalanceDlg, SIGNAL(createPayee(const QString&, QString&)), this, SLOT(slotPayeeNew(const QString&, QString&)));
+ connect(m_endingBalanceDlg, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)), this, SLOT(slotCategoryNew(MyMoneyAccount&, const MyMoneyAccount&)));
+
+ if(m_endingBalanceDlg->exec() == QDialog::Accepted) {
+ if(myMoneyView->startReconciliation(account, m_endingBalanceDlg->statementDate(), m_endingBalanceDlg->endingBalance())) {
+
+ // check if the user requests us to create interest
+ // or charge transactions.
+ MyMoneyTransaction ti = m_endingBalanceDlg->interestTransaction();
+ MyMoneyTransaction tc = m_endingBalanceDlg->chargeTransaction();
+ MyMoneyFileTransaction ft;
+ try {
+ if(ti != MyMoneyTransaction()) {
+ MyMoneyFile::instance()->addTransaction(ti);
+ }
+ if(tc != MyMoneyTransaction()) {
+ MyMoneyFile::instance()->addTransaction(tc);
+ }
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ qWarning("interest transaction not stored: '%s'", e->what().data());
+ delete e;
+ }
+
+ // reload the account object as it might have changed in the meantime
+ m_reconciliationAccount = file->account(account.id());
+ slotUpdateActions();
+ }
+ }
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotAccountReconcileFinish(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if(!m_reconciliationAccount.id().isEmpty()) {
+ // retrieve list of all transactions that are not reconciled or cleared
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> > transactionList;
+ MyMoneyTransactionFilter filter(m_reconciliationAccount.id());
+ filter.addState(MyMoneyTransactionFilter::cleared);
+ filter.addState(MyMoneyTransactionFilter::notReconciled);
+ filter.setDateFilter(QDate(), m_endingBalanceDlg->statementDate());
+ filter.setConsiderCategory(false);
+ filter.setReportAllSplits(true);
+ file->transactionList(transactionList, filter);
+
+ MyMoneyMoney balance = MyMoneyFile::instance()->balance(m_reconciliationAccount.id(), m_endingBalanceDlg->statementDate());
+ MyMoneyMoney actBalance, clearedBalance;
+ actBalance = clearedBalance = balance;
+
+ // walk the list of transactions to figure out the balance(s)
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::const_iterator it;
+ for(it = transactionList.begin(); it != transactionList.end(); ++it) {
+ if((*it).second.reconcileFlag() == MyMoneySplit::NotReconciled) {
+ clearedBalance -= (*it).second.shares();
+ }
+ }
+
+ if(m_endingBalanceDlg->endingBalance() != clearedBalance) {
+ QString message = i18n("You are about to finish the reconciliation of this account with a difference between your bank statement and the transactions marked as cleared.\n"
+ "Are you sure you want to finish the reconciliation ?");
+ if (KMessageBox::questionYesNo(this, message, i18n("Confirm end of reconciliation"), KStdGuiItem::yes(), KStdGuiItem::no()) == KMessageBox::No)
+ return;
+ }
+
+ MyMoneyFileTransaction ft;
+
+ // refresh object
+ m_reconciliationAccount = file->account(m_reconciliationAccount.id());
+
+ // Turn off reconciliation mode
+ myMoneyView->finishReconciliation(m_reconciliationAccount);
+
+ m_reconciliationAccount.setValue("lastStatementBalance", m_endingBalanceDlg->endingBalance().toString());
+ m_reconciliationAccount.setLastReconciliationDate(m_endingBalanceDlg->statementDate());
+
+ m_reconciliationAccount.deletePair("lastReconciledBalance");
+ m_reconciliationAccount.deletePair("statementBalance");
+ m_reconciliationAccount.deletePair("statementDate");
+
+ try {
+ // update the account data
+ file->modifyAccount(m_reconciliationAccount);
+
+ /*
+ // collect the list of cleared splits for this account
+ filter.clear();
+ filter.addAccount(m_reconciliationAccount.id());
+ filter.addState(MyMoneyTransactionFilter::cleared);
+ filter.setConsiderCategory(false);
+ filter.setReportAllSplits(true);
+ file->transactionList(transactionList, filter);
+ */
+
+ // walk the list of transactions/splits and mark the cleared ones as reconciled
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::iterator it;
+
+ for(it = transactionList.begin(); it != transactionList.end(); ++it) {
+ MyMoneySplit sp = (*it).second;
+ // skip the ones that are not marked cleared
+ if(sp.reconcileFlag() != MyMoneySplit::Cleared)
+ continue;
+
+ // always retrieve a fresh copy of the transaction because we
+ // might have changed it already with another split
+ MyMoneyTransaction t = file->transaction((*it).first.id());
+ sp.setReconcileFlag(MyMoneySplit::Reconciled);
+ sp.setReconcileDate(m_endingBalanceDlg->statementDate());
+ t.modifySplit(sp);
+
+ // update the engine ...
+ file->modifyTransaction(t);
+
+ // ... and the list
+ (*it) = qMakePair(t, sp);
+ }
+ ft.commit();
+
+ // reload account data from engine as the data might have changed in the meantime
+ m_reconciliationAccount = file->account(m_reconciliationAccount.id());
+ emit accountReconciled(m_reconciliationAccount,
+ m_endingBalanceDlg->statementDate(),
+ m_endingBalanceDlg->previousBalance(),
+ m_endingBalanceDlg->endingBalance(),
+ transactionList);
+
+ } catch(MyMoneyException *e) {
+ qDebug("Unexpected exception when setting cleared to reconcile");
+ delete e;
+ }
+ }
+ // Turn off reconciliation mode
+ m_reconciliationAccount = MyMoneyAccount();
+ slotUpdateActions();
+}
+
+void KMyMoney2App::slotAccountReconcilePostpone(void)
+{
+ MyMoneyFileTransaction ft;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if(!m_reconciliationAccount.id().isEmpty()) {
+ // refresh object
+ m_reconciliationAccount = file->account(m_reconciliationAccount.id());
+
+ // Turn off reconciliation mode
+ myMoneyView->finishReconciliation(m_reconciliationAccount);
+
+ m_reconciliationAccount.setValue("lastReconciledBalance", m_endingBalanceDlg->previousBalance().toString());
+ m_reconciliationAccount.setValue("statementBalance", m_endingBalanceDlg->endingBalance().toString());
+ m_reconciliationAccount.setValue("statementDate", m_endingBalanceDlg->statementDate().toString(Qt::ISODate));
+
+ try {
+ file->modifyAccount(m_reconciliationAccount);
+ ft.commit();
+ m_reconciliationAccount = MyMoneyAccount();
+ slotUpdateActions();
+ } catch(MyMoneyException *e) {
+ qDebug("Unexpected exception when setting last reconcile info into account");
+ delete e;
+ ft.rollback();
+ m_reconciliationAccount = file->account(m_reconciliationAccount.id());
+ }
+ }
+}
+
+void KMyMoney2App::slotAccountOpen(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyAccount))
+ return;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString id = m_selectedAccount.id();
+
+ // if the caller passed a non-empty object, we need to select that
+ if(!obj.id().isEmpty()) {
+ id = obj.id();
+ }
+
+ // we cannot reconcile standard accounts
+ if(!file->isStandardAccount(id)) {
+ // check if we can open this account
+ // currently it make's sense for asset and liability accounts
+ try {
+ MyMoneyAccount account = file->account(id);
+ myMoneyView->slotLedgerSelected(account.id());
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+}
+
+bool KMyMoney2App::canCloseAccount(const MyMoneyAccount& acc) const
+{
+ // balance must be zero
+ if(!acc.balance().isZero())
+ return false;
+
+ // all children must be already closed
+ QStringList::const_iterator it_a;
+ for(it_a = acc.accountList().begin(); it_a != acc.accountList().end(); ++it_a) {
+ MyMoneyAccount a = MyMoneyFile::instance()->account(*it_a);
+ if(!a.isClosed()) {
+ return false;
+ }
+ }
+
+ // there must be no unfinished schedule referencing the account
+ QValueList<MyMoneySchedule> list = MyMoneyFile::instance()->scheduleList();
+ QValueList<MyMoneySchedule>::const_iterator it_l;
+ for(it_l = list.begin(); it_l != list.end(); ++it_l) {
+ if((*it_l).isFinished())
+ continue;
+ if((*it_l).hasReferenceTo(acc.id()))
+ return false;
+ }
+ return true;
+}
+
+void KMyMoney2App::slotAccountClose(void)
+{
+ MyMoneyAccount a;
+ if(!m_selectedInvestment.id().isEmpty())
+ a = m_selectedInvestment;
+ else if(!m_selectedAccount.id().isEmpty())
+ a = m_selectedAccount;
+ if(a.id().isEmpty())
+ return; // need an account ID
+
+ MyMoneyFileTransaction ft;
+ try {
+ a.setClosed(true);
+ MyMoneyFile::instance()->modifyAccount(a);
+ ft.commit();
+ if(KMyMoneyGlobalSettings::hideClosedAccounts()) {
+ KMessageBox::information(this, QString("<qt>")+i18n("You have closed this account. It remains in the system because you have transactions which still refer to it, but is not shown in the views. You can make it visible again by going to the View menu and selecting <b>Show all accounts</b> or by unselecting the <b>Don't show closed accounts</b> setting.")+QString("</qt>"), i18n("Information"), "CloseAccountInfo");
+ }
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotAccountReopen(void)
+{
+ MyMoneyAccount a;
+ if(!m_selectedInvestment.id().isEmpty())
+ a = m_selectedInvestment;
+ else if(!m_selectedAccount.id().isEmpty())
+ a = m_selectedAccount;
+ if(a.id().isEmpty())
+ return; // need an account ID
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyFileTransaction ft;
+ try {
+ while(a.isClosed()) {
+ a.setClosed(false);
+ file->modifyAccount(a);
+ a = file->account(a.parentAccountId());
+ }
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotReparentAccount(const MyMoneyAccount& _src, const MyMoneyInstitution& _dst)
+{
+ MyMoneyAccount src(_src);
+ src.setInstitutionId(_dst.id());
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifyAccount(src);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::sorry(this, QString("<p>")+i18n("<b>%1</b> cannot be moved to institution <b>%2</b>. Reason: %3").arg(src.name()).arg(_dst.name()).arg(e->what()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotReparentAccount(const MyMoneyAccount& _src, const MyMoneyAccount& _dst)
+{
+ MyMoneyAccount src(_src);
+ MyMoneyAccount dst(_dst);
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->reparentAccount(src, dst);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::sorry(this, QString("<p>")+i18n("<b>%1</b> cannot be moved to <b>%2</b>. Reason: %3").arg(src.name()).arg(dst.name()).arg(e->what()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotAccountTransactionReport(void)
+{
+ // Generate a transaction report that contains transactions for only the
+ // currently selected account.
+ if(!m_selectedAccount.id().isEmpty()) {
+ MyMoneyReport report(
+ MyMoneyReport::eAccount,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCcategory,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("%1 YTD Account Transactions").arg(m_selectedAccount.name()),
+ i18n("Generated Report")
+ );
+ report.setGroup(i18n("Transactions"));
+ report.addAccount(m_selectedAccount.id());
+
+ myMoneyView->slotShowReport(report);
+ }
+}
+
+void KMyMoney2App::slotScheduleNew(void)
+{
+ slotScheduleNew(MyMoneyTransaction());
+}
+
+void KMyMoney2App::slotScheduleNew(const MyMoneyTransaction& _t, MyMoneySchedule::occurenceE occurence)
+{
+ MyMoneySchedule schedule;
+ schedule.setOccurence(occurence);
+
+ // if the schedule is based on an existing transaction,
+ // we take the post date and project it to the next
+ // schedule in a month.
+ if(_t != MyMoneyTransaction()) {
+ MyMoneyTransaction t(_t);
+ if(occurence != MyMoneySchedule::OCCUR_ONCE)
+ t.setPostDate(schedule.nextPayment(t.postDate()));
+ schedule.setTransaction(t);
+ }
+
+ KEditScheduleDlg dlg(schedule, this);
+ TransactionEditor* transactionEditor = dlg.startEdit();
+ if(transactionEditor) {
+ if(dlg.exec() == QDialog::Accepted) {
+ MyMoneyFileTransaction ft;
+ try {
+ schedule = dlg.schedule();
+ MyMoneyFile::instance()->addSchedule(schedule);
+ ft.commit();
+
+ } catch (MyMoneyException *e) {
+ KMessageBox::error(this, i18n("Unable to add scheduled transaction: %1").arg(e->what()), i18n("Add scheduled transaction"));
+ delete e;
+ }
+ }
+ }
+ delete transactionEditor;
+}
+
+void KMyMoney2App::slotScheduleEdit(void)
+{
+ if (!m_selectedSchedule.id().isEmpty()) {
+ try {
+ MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(m_selectedSchedule.id());
+
+ KEditScheduleDlg* sched_dlg = 0;
+ KEditLoanWizard* loan_wiz = 0;
+
+
+ switch (schedule.type()) {
+ case MyMoneySchedule::TYPE_BILL:
+ case MyMoneySchedule::TYPE_DEPOSIT:
+ case MyMoneySchedule::TYPE_TRANSFER:
+ sched_dlg = new KEditScheduleDlg(schedule, this);
+ m_transactionEditor = sched_dlg->startEdit();
+ if(m_transactionEditor) {
+ if(sched_dlg->exec() == QDialog::Accepted) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneySchedule sched = sched_dlg->schedule();
+ // Check whether the new Schedule Date
+ // is at or before the lastPaymentDate
+ // If it is, ask the user whether to clear the
+ // lastPaymentDate
+ const QDate& next = sched.nextDueDate();
+ const QDate& last = sched.lastPayment();
+ if ( next.isValid() && last.isValid() && next <= last ) {
+ // Entered a date effectively no later
+ // than previous payment. Date would be
+ // updated automatically so we probably
+ // want to clear it. Let's ask the user.
+ if(KMessageBox::questionYesNo(this, QString("<qt>")+i18n("You have entered a scheduled transaction date of <b>%1</b>. Because the scheduled transaction was last paid on <b>%2</b>, KMyMoney will automatically adjust the scheduled transaction date to the next date unless the last payment date is reset. Do you want to reset the last payment date?").arg(KGlobal::locale()->formatDate(next, true)).arg(KGlobal::locale()->formatDate(last, true))+QString("</qt>"),i18n("Reset Last Payment Date" ), KStdGuiItem::yes(), KStdGuiItem::no()) == KMessageBox::Yes) {
+ sched.setLastPayment( QDate() );
+ }
+ }
+ MyMoneyFile::instance()->modifySchedule(sched);
+ // delete the editor before we emit the dataChanged() signal from the
+ // engine. Calling this twice in a row does not hurt.
+ deleteTransactionEditor();
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to modify scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ }
+ deleteTransactionEditor();
+ }
+ delete sched_dlg;
+ break;
+
+ case MyMoneySchedule::TYPE_LOANPAYMENT:
+ loan_wiz = new KEditLoanWizard(schedule.account(2));
+ connect(loan_wiz, SIGNAL(newCategory(MyMoneyAccount&)), this, SLOT(slotCategoryNew(MyMoneyAccount&)));
+ connect(loan_wiz, SIGNAL(createPayee(const QString&, QString&)), this, SLOT(slotPayeeNew(const QString&, QString&)));
+ if (loan_wiz->exec() == QDialog::Accepted) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifySchedule(loan_wiz->schedule());
+ MyMoneyFile::instance()->modifyAccount(loan_wiz->account());
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to modify scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ }
+ delete loan_wiz;
+ break;
+
+ case MyMoneySchedule::TYPE_ANY:
+ break;
+ }
+
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to modify scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotScheduleDelete(void)
+{
+ if (!m_selectedSchedule.id().isEmpty()) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneySchedule sched = MyMoneyFile::instance()->schedule(m_selectedSchedule.id());
+ QString msg = QString("<p>")+i18n("Are you sure you want to delete the scheduled transaction <b>%1</b>?").arg(m_selectedSchedule.name());
+ if(sched.type() == MyMoneySchedule::TYPE_LOANPAYMENT) {
+ msg += QString(" ");
+ msg += i18n("In case of loan payments it is currently not possible to recreate the scheduled transaction.");
+ }
+ if (KMessageBox::questionYesNo(this, msg) == KMessageBox::No)
+ return;
+
+ MyMoneyFile::instance()->removeSchedule(sched);
+ ft.commit();
+
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to remove scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotScheduleDuplicate(void)
+{
+ // since we may jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("schedule_duplicate")->isEnabled()) {
+ MyMoneySchedule sch = m_selectedSchedule;
+ sch.clearId();
+ sch.setLastPayment(QDate());
+ sch.setName(i18n("Copy of scheduled transaction name", "Copy of %1").arg(sch.name()));
+
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->addSchedule(sch);
+ ft.commit();
+
+ // select the new schedule in the view
+ if(!m_selectedSchedule.id().isEmpty())
+ myMoneyView->slotScheduleSelected(sch.id());
+
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to duplicate transaction(s): %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotScheduleSkip(void)
+{
+ if (!m_selectedSchedule.id().isEmpty()) {
+ try {
+ MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(m_selectedSchedule.id());
+ if(!schedule.isFinished()) {
+ if(schedule.occurence() != MyMoneySchedule::OCCUR_ONCE) {
+ QDate next = schedule.nextDueDate();
+ if(!schedule.isFinished() && (KMessageBox::questionYesNo(this, QString("<qt>")+i18n("Do you really want to skip the <b>%1</b> transaction scheduled for <b>%2</b>?").arg(schedule.name(), KGlobal::locale()->formatDate(next, true))+QString("</qt>"))) == KMessageBox::Yes) {
+ MyMoneyFileTransaction ft;
+ schedule.setLastPayment(next);
+ schedule.setNextDueDate(schedule.nextPayment(next));
+ MyMoneyFile::instance()->modifySchedule(schedule);
+ ft.commit();
+ }
+ }
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, QString("<qt>")+i18n("Unable to skip scheduled transaction <b>%1</b>.").arg(m_selectedSchedule.name())+QString("</qt>"), e->what());
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotScheduleEnter(void)
+{
+ if (!m_selectedSchedule.id().isEmpty()) {
+ try {
+ MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(m_selectedSchedule.id());
+ enterSchedule(schedule);
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unknown scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ }
+}
+
+KMyMoneyUtils::EnterScheduleResultCodeE KMyMoney2App::enterSchedule(MyMoneySchedule& schedule, bool autoEnter, bool extendedKeys)
+{
+ KMyMoneyUtils::EnterScheduleResultCodeE rc = KMyMoneyUtils::Cancel;
+ if (!schedule.id().isEmpty()) {
+ try {
+ schedule = MyMoneyFile::instance()->schedule(schedule.id());
+ QDate origDueDate = schedule.nextDueDate();
+
+ KEnterScheduleDlg dlg(this, schedule);
+ dlg.showExtendedKeys(extendedKeys);
+
+ m_transactionEditor = dlg.startEdit();
+ if(m_transactionEditor) {
+ MyMoneyTransaction torig, taccepted;
+ m_transactionEditor->createTransaction(torig, dlg.transaction(), schedule.transaction().splits()[0], true);
+ // force actions to be available no matter what (will be updated according to the state during
+ // slotTransactionsEnter or slotTransactionsCancel)
+ kmymoney2->action("transaction_cancel")->setEnabled(true);
+ kmymoney2->action("transaction_enter")->setEnabled(true);
+
+ KConfirmManualEnterDlg::Action action = KConfirmManualEnterDlg::ModifyOnce;
+ if(!autoEnter || !schedule.isFixed()) {
+ for(;;) {
+ rc = KMyMoneyUtils::Cancel;
+ if(dlg.exec() == QDialog::Accepted) {
+ rc = dlg.resultCode();
+ if(rc == KMyMoneyUtils::Enter) {
+ m_transactionEditor->createTransaction(taccepted, torig, torig.splits()[0], true);
+ // make sure to suppress comparison of some data: postDate
+ torig.setPostDate(taccepted.postDate());
+ if(torig != taccepted) {
+ KConfirmManualEnterDlg cdlg(schedule, this);
+ cdlg.loadTransactions(torig, taccepted);
+ if(cdlg.exec() == QDialog::Accepted) {
+ action = cdlg.action();
+ break;
+ }
+ // the user has choosen 'cancel' during confirmation,
+ // we go back to the editor
+ continue;
+ }
+ } else if(rc == KMyMoneyUtils::Skip) {
+ slotTransactionsCancel();
+ slotScheduleSkip();
+ } else {
+ slotTransactionsCancel();
+ }
+ } else {
+ if(autoEnter) {
+ if(KMessageBox::warningYesNo(this, i18n("Are you sure you wish to stop this scheduled transaction from being entered into the register?\n\nKMyMoney will prompt you again next time it starts unless you manually enter it later.")) == KMessageBox::No) {
+ // the user has choosen 'No' for the above question,
+ // we go back to the editor
+ continue;
+ }
+ }
+ slotTransactionsCancel();
+ }
+ break;
+ }
+ }
+
+ // if we still have the editor around here, the user did not cancel
+ if(m_transactionEditor) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyTransaction t;
+ // add the new transaction
+ switch(action) {
+ case KConfirmManualEnterDlg::UseOriginal:
+ // setup widgets with original transaction data
+ m_transactionEditor->setTransaction(dlg.transaction(), dlg.transaction().splits()[0]);
+ // and create a transaction based on that data
+ taccepted = MyMoneyTransaction();
+ m_transactionEditor->createTransaction(taccepted, dlg.transaction(), dlg.transaction().splits()[0], true);
+ break;
+
+ case KConfirmManualEnterDlg::ModifyAlways:
+ schedule.setTransaction(taccepted);
+ break;
+
+ case KConfirmManualEnterDlg::ModifyOnce:
+ break;
+ }
+
+ QString newId;
+ connect(m_transactionEditor, SIGNAL(balanceWarning(QWidget*, const MyMoneyAccount&, const QString&)), d->m_balanceWarning, SLOT(slotShowMessage(QWidget*, const MyMoneyAccount&, const QString&)));
+ if(m_transactionEditor->enterTransactions(newId, false)) {
+ if(!newId.isEmpty()) {
+ MyMoneyTransaction t = MyMoneyFile::instance()->transaction(newId);
+ schedule.setLastPayment(t.postDate());
+ }
+ schedule.setNextDueDate(schedule.nextPayment(origDueDate));
+ MyMoneyFile::instance()->modifySchedule(schedule);
+ rc = KMyMoneyUtils::Enter;
+
+ // delete the editor before we emit the dataChanged() signal from the
+ // engine. Calling this twice in a row does not hurt.
+ deleteTransactionEditor();
+ ft.commit();
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to enter scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ deleteTransactionEditor();
+ }
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to enter scheduled transaction '%1'").arg(m_selectedSchedule.name()), e->what());
+ delete e;
+ }
+ }
+ return rc;
+}
+
+void KMyMoney2App::slotPayeeNew(const QString& newnameBase, QString& id)
+{
+ bool doit = true;
+
+ if(newnameBase != i18n("New Payee")) {
+ // Ask the user if that is what he intended to do?
+ QString msg = QString("<qt>") + i18n("Do you want to add <b>%1</b> as payer/receiver ?").arg(newnameBase) + QString("</qt>");
+ const QString dontAskAgain = QString::fromLatin1("NewPayee");
+ if(KMessageBox::questionYesNo(this, msg, i18n("New payee/receiver"), KStdGuiItem::yes(), KStdGuiItem::no(), dontAskAgain) == KMessageBox::No) {
+ doit = false;
+ // we should not keep the 'no' setting because that can confuse people like
+ // I have seen in some usability tests. So we just delete it right away.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig) {
+ kconfig->setGroup(QString::fromLatin1("Notification Messages"));
+ kconfig->deleteEntry(dontAskAgain);
+ }
+ }
+ }
+
+ if(doit) {
+ MyMoneyFileTransaction ft;
+ try {
+ QString newname(newnameBase);
+ // adjust name until a unique name has been created
+ int count = 0;
+ for(;;) {
+ try {
+ MyMoneyFile::instance()->payeeByName(newname);
+ newname = QString("%1 [%2]").arg(newnameBase).arg(++count);
+ } catch(MyMoneyException* e) {
+ delete e;
+ break;
+ }
+ }
+
+ MyMoneyPayee p;
+ p.setName(newname);
+ MyMoneyFile::instance()->addPayee(p);
+ id = p.id();
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ KMessageBox::detailedSorry(this, i18n("Unable to add payee"),
+ QString("%1 thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotPayeeNew(void)
+{
+ QString id;
+ slotPayeeNew(i18n("New Payee"), id);
+
+ // the callbacks should have made sure, that the payees view has been
+ // updated already. So we search for the id in the list of items
+ // and select it.
+ emit payeeCreated(id);
+}
+
+bool KMyMoney2App::payeeInList(const QValueList<MyMoneyPayee>& list, const QString& id) const
+{
+ bool rc = false;
+ QValueList<MyMoneyPayee>::const_iterator it_p = list.begin();
+ while(it_p != list.end()) {
+ if((*it_p).id() == id) {
+ rc = true;
+ break;
+ }
+ ++it_p;
+ }
+ return rc;
+}
+
+void KMyMoney2App::slotPayeeDelete(void)
+{
+ if(m_selectedPayees.isEmpty())
+ return; // shouldn't happen
+
+ MyMoneyFile * file = MyMoneyFile::instance();
+
+ // first create list with all non-selected payees
+ QValueList<MyMoneyPayee> remainingPayees = file->payeeList();
+ QValueList<MyMoneyPayee>::iterator it_p;
+ for(it_p = remainingPayees.begin(); it_p != remainingPayees.end(); ) {
+ if(m_selectedPayees.find(*it_p) != m_selectedPayees.end()) {
+ it_p = remainingPayees.erase(it_p);
+ } else {
+ ++it_p;
+ }
+ }
+
+ // get confirmation from user
+ QString prompt;
+ if (m_selectedPayees.size() == 1)
+ prompt = QString("<p>")+i18n("Do you really want to remove the payee <b>%1</b>?").arg(m_selectedPayees.front().name());
+ else
+ prompt = i18n("Do you really want to remove all selected payees?");
+
+ if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Payee"))==KMessageBox::No)
+ return;
+
+ MyMoneyFileTransaction ft;
+ try {
+ // create a transaction filter that contains all payees selected for removal
+ MyMoneyTransactionFilter f = MyMoneyTransactionFilter();
+ for (QValueList<MyMoneyPayee>::const_iterator it = m_selectedPayees.begin();
+ it != m_selectedPayees.end(); ++it) {
+ f.addPayee( (*it).id() );
+ }
+ // request a list of all transactions that still use the payees in question
+ QValueList<MyMoneyTransaction> translist = file->transactionList(f);
+// kdDebug() << "[KPayeesView::slotDeletePayee] " << translist.count() << " transaction still assigned to payees" << endl;
+
+ // now get a list of all schedules that make use of one of the payees
+ QValueList<MyMoneySchedule> all_schedules = file->scheduleList();
+ QValueList<MyMoneySchedule> used_schedules;
+ for (QValueList<MyMoneySchedule>::ConstIterator it = all_schedules.begin();
+ it != all_schedules.end(); ++it)
+ {
+ // loop over all splits in the transaction of the schedule
+ for (QValueList<MyMoneySplit>::ConstIterator s_it = (*it).transaction().splits().begin();
+ s_it != (*it).transaction().splits().end(); ++s_it)
+ {
+ // is the payee in the split to be deleted?
+ if(payeeInList(m_selectedPayees, (*s_it).payeeId())) {
+ used_schedules.push_back(*it); // remember this schedule
+ break;
+ }
+ }
+ }
+// kdDebug() << "[KPayeesView::slotDeletePayee] " << used_schedules.count() << " schedules use one of the selected payees" << endl;
+
+ MyMoneyPayee newPayee;
+ bool addToMatchList = false;
+ // if at least one payee is still referenced, we need to reassign its transactions first
+ if (!translist.isEmpty() || !used_schedules.isEmpty()) {
+ // show error message if no payees remain
+ if (remainingPayees.isEmpty()) {
+ KMessageBox::sorry(this, i18n("At least one transaction/scheduled transaction is still referenced by a payee. "
+ "Currently you have all payees selected. However, at least one payee must remain so "
+ "that the transaction/scheduled transaction can be reassigned."));
+ return;
+ }
+
+ // show transaction reassignment dialog
+ KPayeeReassignDlg * dlg = new KPayeeReassignDlg(this);
+ QString payee_id = dlg->show(remainingPayees);
+ addToMatchList = dlg->addToMatchList();
+ delete dlg; // and kill the dialog
+ if (payee_id.isEmpty())
+ return; // the user aborted the dialog, so let's abort as well
+
+ newPayee = file->payee(payee_id);
+
+ // TODO : check if we have a report that explicitely uses one of our payees
+ // and issue an appropriate warning
+ try {
+ QValueList<MyMoneySplit>::iterator s_it;
+ // now loop over all transactions and reassign payee
+ for (QValueList<MyMoneyTransaction>::iterator it = translist.begin(); it != translist.end(); ++it) {
+ // create a copy of the splits list in the transaction
+ QValueList<MyMoneySplit> splits = (*it).splits();
+ // loop over all splits
+ for (s_it = splits.begin(); s_it != splits.end(); ++s_it) {
+ // if the split is assigned to one of the selected payees, we need to modify it
+ if(payeeInList(m_selectedPayees, (*s_it).payeeId())) {
+ (*s_it).setPayeeId(payee_id); // first modify payee in current split
+ // then modify the split in our local copy of the transaction list
+ (*it).modifySplit(*s_it); // this does not modify the list object 'splits'!
+ }
+ } // for - Splits
+ file->modifyTransaction(*it); // modify the transaction in the MyMoney object
+ } // for - Transactions
+
+ // now loop over all schedules and reassign payees
+ for (QValueList<MyMoneySchedule>::iterator it = used_schedules.begin();
+ it != used_schedules.end(); ++it)
+ {
+ // create copy of transaction in current schedule
+ MyMoneyTransaction trans = (*it).transaction();
+ // create copy of lists of splits
+ QValueList<MyMoneySplit> splits = trans.splits();
+ for (s_it = splits.begin(); s_it != splits.end(); ++s_it) {
+ if(payeeInList(m_selectedPayees, (*s_it).payeeId())) {
+ (*s_it).setPayeeId(payee_id);
+ trans.modifySplit(*s_it); // does not modify the list object 'splits'!
+ }
+ } // for - Splits
+ // store transaction in current schedule
+ (*it).setTransaction(trans);
+ file->modifySchedule(*it); // modify the schedule in the MyMoney engine
+ } // for - Schedules
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to reassign payee of transaction/split"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+ } // if !translist.isEmpty()
+
+ bool ignorecase;
+ QStringList payeeNames;
+ MyMoneyPayee::payeeMatchType matchType = newPayee.matchData(ignorecase, payeeNames);
+ QStringList deletedPayeeNames;
+
+ // now loop over all selected payees and remove them
+ for (QValueList<MyMoneyPayee>::iterator it = m_selectedPayees.begin();
+ it != m_selectedPayees.end(); ++it) {
+ if(addToMatchList) {
+ deletedPayeeNames << (*it).name();
+ }
+ file->removePayee(*it);
+ }
+
+ // if we initially have no matching turned on, we just ignore the case (default)
+ if(matchType == MyMoneyPayee::matchDisabled)
+ ignorecase = true;
+
+ // update the destination payee if this was requested by the user
+ if(addToMatchList && deletedPayeeNames.count() > 0) {
+ // add new names to the list
+ // TODO: it would be cool to somehow shrink the list to make better use
+ // of regular expressions at this point. For now, we leave this task
+ // to the user himeself.
+ QStringList::const_iterator it_n;
+ for(it_n = deletedPayeeNames.begin(); it_n != deletedPayeeNames.end(); ++it_n) {
+ if(matchType == MyMoneyPayee::matchKey) {
+ // make sure we really need it and it is not caught by an existing regexp
+ QStringList::const_iterator it_k;
+ for(it_k = payeeNames.begin(); it_k != payeeNames.end(); ++it_k) {
+ QRegExp exp(*it_k, ignorecase);
+ if(exp.search(*it_n) != -1)
+ break;
+ }
+ if(it_k == payeeNames.end())
+ payeeNames << QRegExp::escape(*it_n);
+ } else if(payeeNames.contains(*it_n) == 0)
+ payeeNames << QRegExp::escape(*it_n);
+ }
+
+ // and update the payee in the engine context
+ // make sure to turn on matching for this payee in the right mode
+ newPayee.setMatchData(MyMoneyPayee::matchKey, ignorecase, payeeNames);
+ file->modifyPayee(newPayee);
+ }
+ ft.commit();
+
+ // If we just deleted the payees, they sure don't exist anymore
+ slotSelectPayees(QValueList<MyMoneyPayee>());
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to remove payee(s)"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotCurrencyNew(void)
+{
+ QString sid = KInputDialog::getText(i18n("New currency"), i18n("Enter ISO 4217 code for the new currency"), QString::null, 0, 0, 0, 0, ">AAA");
+ if(!sid.isEmpty()) {
+ QString id(sid);
+ MyMoneySecurity currency(id, i18n("New currency"));
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->addCurrency(currency);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::sorry(this, i18n("Cannot create new currency. %1").arg(e->what()), i18n("New currency"));
+ delete e;
+ }
+ emit currencyCreated(id);
+ }
+}
+
+void KMyMoney2App::slotCurrencyRename(QListViewItem* item, int, const QString& txt)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ KMyMoneyListViewItem* p = static_cast<KMyMoneyListViewItem *>(item);
+
+ try {
+ if(txt != m_selectedCurrency.name()) {
+ MyMoneySecurity currency = file->currency(p->id());
+ currency.setName(txt);
+ MyMoneyFileTransaction ft;
+ try {
+ file->modifyCurrency(currency);
+ m_selectedCurrency = currency;
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::sorry(this, i18n("Cannot rename currency. %1").arg(e->what()), i18n("Rename currency"));
+ delete e;
+ }
+ }
+ } catch(MyMoneyException *e) {
+ KMessageBox::sorry(this, i18n("Cannot rename currency. %1").arg(e->what()), i18n("Rename currency"));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotCurrencyDelete(void)
+{
+ if(!m_selectedCurrency.id().isEmpty()) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->removeCurrency(m_selectedCurrency);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::sorry(this, i18n("Cannot delete currency %1. %2").arg(m_selectedCurrency.name()).arg(e->what()), i18n("Delete currency"));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotCurrencySetBase(void)
+{
+ if(!m_selectedCurrency.id().isEmpty()) {
+ if(m_selectedCurrency.id() != MyMoneyFile::instance()->baseCurrency().id()) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->setBaseCurrency(m_selectedCurrency);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::sorry(this, i18n("Cannot set %1 as base currency: %2").arg(m_selectedCurrency.name()).arg(e->what()), i18n("Set base currency"));
+ delete e;
+ }
+ }
+ }
+}
+
+void KMyMoney2App::slotBudgetNew(void)
+{
+ QDate date = QDate::currentDate(Qt::LocalTime);
+ date.setYMD(date.year(), 1, 1);
+ QString newname = i18n("Budget %1").arg(QString::number(date.year()));
+
+ MyMoneyBudget budget;
+
+ // make sure we have a unique name
+ try {
+ int i=1;
+ // Exception thrown when the name is not found
+ while (1) {
+ MyMoneyFile::instance()->budgetByName(newname);
+ newname = i18n("Budget %1 (%2)").arg(QString::number(date.year()), QString::number(i++));
+ }
+ } catch(MyMoneyException *e) {
+ // all ok, the name is unique
+ delete e;
+ }
+
+ MyMoneyFileTransaction ft;
+ try {
+ budget.setName(newname);
+ budget.setBudgetStart(date);
+
+ MyMoneyFile::instance()->addBudget(budget);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to add budget: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotBudgetDelete(void)
+{
+ if(m_selectedBudgets.isEmpty())
+ return; // shouldn't happen
+
+ MyMoneyFile * file = MyMoneyFile::instance();
+
+ // get confirmation from user
+ QString prompt;
+ if (m_selectedBudgets.size() == 1)
+ prompt = QString("<p>")+i18n("Do you really want to remove the budget <b>%1</b>?").arg(m_selectedBudgets.front().name());
+ else
+ prompt = i18n("Do you really want to remove all selected budgets?");
+
+ if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Budget"))==KMessageBox::No)
+ return;
+
+ MyMoneyFileTransaction ft;
+ try {
+ // now loop over all selected budgets and remove them
+ for (QValueList<MyMoneyBudget>::iterator it = m_selectedBudgets.begin();
+ it != m_selectedBudgets.end(); ++it) {
+ file->removeBudget(*it);
+ }
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to remove budget: %1, thrown in %2:%3"). arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotBudgetCopy(void)
+{
+ if(m_selectedBudgets.size() == 1) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyBudget budget = m_selectedBudgets[0];
+ budget.clearId();
+ budget.setName(i18n("Copy of %1").arg(budget.name()));
+
+ MyMoneyFile::instance()->addBudget(budget);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to add budget: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotBudgetChangeYear(void)
+{
+ if(m_selectedBudgets.size() == 1) {
+ QStringList years;
+ int current = 0;
+ bool haveCurrent = false;
+ MyMoneyBudget budget = *(m_selectedBudgets.begin());
+ for(int i = (QDate::currentDate().year()-3); i < (QDate::currentDate().year()+5); ++i) {
+ years << QString("%1").arg(i);
+ if(i == budget.budgetStart().year()) {
+ haveCurrent = true;
+ }
+ if(!haveCurrent)
+ ++current;
+ }
+ if(!haveCurrent)
+ current = 0;
+ bool ok = false;
+
+ QString yearString = KInputDialog::getItem(i18n("Select year"), i18n("Budget year"), years, current, false, &ok, this);
+
+ if(ok) {
+ int year = yearString.toInt(0, 0);
+ QDate newYear = QDate(year, 1, 1);
+ if(newYear != budget.budgetStart()) {
+ MyMoneyFileTransaction ft;
+ try {
+ budget.setBudgetStart(newYear);
+ MyMoneyFile::instance()->modifyBudget(budget);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify budget: %1, thrown in %2:%3"). arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+ }
+ }
+}
+
+void KMyMoney2App::slotBudgetForecast(void)
+{
+ if(m_selectedBudgets.size() == 1) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyBudget budget = m_selectedBudgets[0];
+ bool calcBudget = budget.getaccounts().count() == 0;
+ if(!calcBudget) {
+ if(KMessageBox::warningContinueCancel(0, i18n("The current budget already contains data. Continuing will replace all current values of this budget."), i18n("Warning")) == KMessageBox::Continue)
+ calcBudget = true;
+ }
+
+ if(calcBudget) {
+ QDate historyStart;
+ QDate historyEnd;
+ QDate budgetStart;
+ QDate budgetEnd;
+
+ budgetStart = budget.budgetStart();
+ budgetEnd = budgetStart.addYears(1).addDays(-1);
+ historyStart = budgetStart.addYears(-1);
+ historyEnd = budgetEnd.addYears(-1);
+
+ MyMoneyForecast forecast;
+ forecast.createBudget(budget, historyStart, historyEnd, budgetStart, budgetEnd, true);
+
+ MyMoneyFile::instance()->modifyBudget(budget);
+ ft.commit();
+ }
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify budget: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotKDELanguageSettings(void)
+{
+ KMessageBox::information(this, i18n("Please be aware that changes made in the following dialog affect all KDE applications not only KMyMoney."), i18n("Warning"), "LanguageSettingsWarning");
+
+ QStringList args;
+ args << "language";
+ QString error;
+ int pid;
+
+ KApplication::kdeinitExec("kcmshell", args, &error, &pid);
+}
+
+void KMyMoney2App::slotNewFeature(void)
+{
+ // accounts
+ // transactions
+ // budgets
+ // currency
+ // institutions
+ // payees
+ // schedules
+
+ // slotStatementImport();
+#if 0
+ if(m_selectedBudgets.size() == 1) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyBudget budget = m_selectedBudgets[0];
+ bool calcBudget = budget.getaccounts().count() == 0;
+ if(!calcBudget) {
+ if(KMessageBox::warningContinueCancel(0, i18n("The current budget already contains data. Continuing will replace all current values of this budget."), i18n("Warning")) == KMessageBox::Continue)
+ calcBudget = true;
+ }
+
+ if(calcBudget) {
+ QDate historyStart;
+ QDate historyEnd;
+ QDate budgetStart;
+ QDate budgetEnd;
+
+ budgetStart = budget.budgetStart();
+ budgetEnd = budgetStart.addYears(1).addDays(-1);
+ historyStart = budgetStart.addYears(-1);
+ historyEnd = budgetEnd.addYears(-1);
+
+ MyMoneyForecast forecast;
+ budget = forecast.createBudget (historyStart, historyEnd, budgetStart, budgetEnd, true);
+
+ budget.setName(m_selectedBudgets[0].name());
+ MyMoneyFile::instance()->removeBudget(m_selectedBudgets[0]);
+ MyMoneyFile::instance()->addBudget(budget);
+ ft.commit();
+ }
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify budget: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+#endif
+}
+
+void KMyMoney2App::slotTransactionsDelete(void)
+{
+ // since we may jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(!kmymoney2->action("transaction_delete")->isEnabled())
+ return;
+ if(m_selectedTransactions.count() == 0)
+ return;
+ if(m_selectedTransactions.warnLevel() == 1) {
+ if(KMessageBox::warningContinueCancel(0,
+ i18n(
+ "At least one split of the selected transactions has been reconciled. "
+ "Do you wish to delete the transactions anyway?"
+ ),
+ i18n("Transaction already reconciled"), KStdGuiItem::cont(),
+ "DeleteReconciledTransaction") == KMessageBox::Cancel)
+ return;
+ }
+ QString msg;
+ if(m_selectedTransactions.count() == 1) {
+ msg = i18n("Do you really want to delete the selected transaction?");
+ } else {
+ msg = i18n("Do you really want to delete all %1 selected transactions?").arg(m_selectedTransactions.count());
+ }
+ if(KMessageBox::questionYesNo(this, msg, i18n("Delete transaction")) == KMessageBox::Yes) {
+ KMSTATUS(i18n("Deleting transactions"));
+ doDeleteTransactions();
+ }
+}
+
+void KMyMoney2App::slotTransactionDuplicate(void)
+{
+ // since we may jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("transaction_duplicate")->isEnabled()) {
+ KMyMoneyRegister::SelectedTransactions list = m_selectedTransactions;
+ KMyMoneyRegister::SelectedTransactions::iterator it_t;
+
+ int i = 0;
+ int cnt = m_selectedTransactions.count();
+ KMSTATUS(i18n("Duplicating transactions"));
+ slotStatusProgressBar(0, cnt);
+ MyMoneyFileTransaction ft;
+ MyMoneyTransaction lt;
+ try {
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ MyMoneyTransaction t = (*it_t).transaction();
+ QValueList<MyMoneySplit>::iterator it_s;
+ // wipe out any reconciliation information
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ (*it_s).setReconcileFlag(MyMoneySplit::NotReconciled);
+ (*it_s).setReconcileDate(QDate());
+ (*it_s).setBankID(QString());
+ }
+ // clear invalid data
+ t.setEntryDate(QDate());
+ t.clearId();
+ // and set the post date to today
+ t.setPostDate(QDate::currentDate());
+
+ MyMoneyFile::instance()->addTransaction(t);
+ lt = t;
+ slotStatusProgressBar(i++, 0);
+ }
+ ft.commit();
+
+ // select the new transaction in the ledger
+ if(!m_selectedAccount.id().isEmpty())
+ myMoneyView->slotLedgerSelected(m_selectedAccount.id(), lt.id());
+
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to duplicate transaction(s): %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ // switch off the progress bar
+ slotStatusProgressBar(-1, -1);
+ }
+}
+
+void KMyMoney2App::doDeleteTransactions(void)
+{
+ KMyMoneyRegister::SelectedTransactions list = m_selectedTransactions;
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ int cnt = list.count();
+ int i = 0;
+ slotStatusProgressBar(0, cnt);
+ MyMoneyFileTransaction ft;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ try {
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ // only remove those transactions that do not reference a closed account
+ if(!file->referencesClosedAccount((*it_t).transaction()))
+ file->removeTransaction((*it_t).transaction());
+ slotStatusProgressBar(i++, 0);
+ }
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to delete transaction(s): %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ slotStatusProgressBar(-1, -1);
+}
+
+void KMyMoney2App::slotTransactionsNew(void)
+{
+ // since we jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("transaction_new")->isEnabled()) {
+ if(myMoneyView->createNewTransaction()) {
+ m_transactionEditor = myMoneyView->startEdit(m_selectedTransactions);
+ KMyMoneyPayeeCombo* payeeEdit = dynamic_cast<KMyMoneyPayeeCombo*>(m_transactionEditor->haveWidget("payee"));
+ if(payeeEdit
+ && !d->m_lastPayeeEntered.isEmpty()
+ && KMyMoneyGlobalSettings::autoReusePayee()) {
+ // in case we entered a new transaction before and used a payee,
+ // we reuse it here. Save the text to the edit widget, select it
+ // so that hitting any character will start entering another payee.
+ // close the completion list
+ payeeEdit->setCurrentText(d->m_lastPayeeEntered);
+ payeeEdit->completion()->slotMakeCompletion(d->m_lastPayeeEntered);
+ QStringList payeeId;
+ payeeEdit->selector()->selectedItems(payeeId);
+ if(payeeId.count() == 1) {
+ payeeEdit->setSelectedItem(payeeId[0]);
+ }
+ payeeEdit->lineEdit()->selectAll();
+ payeeEdit->completion()->hide();
+ }
+ if(m_transactionEditor) {
+ connect(m_transactionEditor, SIGNAL(statusProgress(int, int)), this, SLOT(slotStatusProgressBar(int, int)));
+ connect(m_transactionEditor, SIGNAL(statusMsg(const QString&)), this, SLOT(slotStatusMsg(const QString&)));
+ connect(m_transactionEditor, SIGNAL(scheduleTransaction(const MyMoneyTransaction&, MyMoneySchedule::occurenceE)), this, SLOT(slotScheduleNew(const MyMoneyTransaction&, MyMoneySchedule::occurenceE)));
+ connect(m_transactionEditor, SIGNAL(transactionDataSufficient(bool)), this, SLOT(slotUpdateActions()));
+ }
+ slotUpdateActions();
+ }
+ }
+}
+
+void KMyMoney2App::slotTransactionsEdit(void)
+{
+ // qDebug("KMyMoney2App::slotTransactionsEdit()");
+ // since we jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("transaction_edit")->isEnabled()) {
+ // as soon as we edit a transaction, we don't remember the last payee entered
+ d->m_lastPayeeEntered = QString();
+ m_transactionEditor = myMoneyView->startEdit(m_selectedTransactions);
+ connect(m_transactionEditor, SIGNAL(transactionDataSufficient(bool)), this, SLOT(slotUpdateActions()));
+ slotUpdateActions();
+ }
+}
+
+void KMyMoney2App::deleteTransactionEditor(void)
+{
+ // make sure, we don't use the transaction editor pointer
+ // anymore from now on
+ TransactionEditor* p = m_transactionEditor;
+ m_transactionEditor = 0;
+ delete p;
+}
+
+void KMyMoney2App::slotTransactionsEditSplits(void)
+{
+ // since we jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("transaction_editsplits")->isEnabled()) {
+ // as soon as we edit a transaction, we don't remember the last payee entered
+ d->m_lastPayeeEntered = QString();
+ m_transactionEditor = myMoneyView->startEdit(m_selectedTransactions);
+ slotUpdateActions();
+
+ if(m_transactionEditor) {
+ if(m_transactionEditor->slotEditSplits() == QDialog::Accepted) {
+ MyMoneyFileTransaction ft;
+ try {
+ QString id;
+ connect(m_transactionEditor, SIGNAL(balanceWarning(QWidget*, const MyMoneyAccount&, const QString&)), d->m_balanceWarning, SLOT(slotShowMessage(QWidget*, const MyMoneyAccount&, const QString&)));
+ m_transactionEditor->enterTransactions(id);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify transaction: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+ }
+ }
+ deleteTransactionEditor();
+ slotUpdateActions();
+ }
+}
+
+void KMyMoney2App::slotTransactionsCancel(void)
+{
+ // since we jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("transaction_cancel")->isEnabled()) {
+ // make sure, we block the enter function
+ action("transaction_enter")->setEnabled(false);
+ // qDebug("KMyMoney2App::slotTransactionsCancel");
+ deleteTransactionEditor();
+ slotUpdateActions();
+ }
+}
+
+void KMyMoney2App::slotTransactionsEnter(void)
+{
+ // since we jump here via code, we have to make sure to react only
+ // if the action is enabled
+ if(kmymoney2->action("transaction_enter")->isEnabled()) {
+ // qDebug("KMyMoney2App::slotTransactionsEnter");
+ if(m_transactionEditor) {
+ QString accountId = m_selectedAccount.id();
+ QString newId;
+ connect(m_transactionEditor, SIGNAL(balanceWarning(QWidget*, const MyMoneyAccount&, const QString&)), d->m_balanceWarning, SLOT(slotShowMessage(QWidget*, const MyMoneyAccount&, const QString&)));
+ if(m_transactionEditor->enterTransactions(newId)) {
+ KMyMoneyPayeeCombo* payeeEdit = dynamic_cast<KMyMoneyPayeeCombo*>(m_transactionEditor->haveWidget("payee"));
+ if(payeeEdit && !newId.isEmpty()) {
+ d->m_lastPayeeEntered = payeeEdit->currentText();
+ }
+ deleteTransactionEditor();
+ }
+ if(!newId.isEmpty()) {
+ myMoneyView->slotLedgerSelected(accountId, newId);
+ }
+ }
+ slotUpdateActions();
+ }
+}
+
+void KMyMoney2App::slotTransactionsCancelOrEnter(bool& okToSelect)
+{
+ static bool oneTime = false;
+ if(!oneTime) {
+ oneTime = true;
+ QString dontShowAgain = "CancelOrEditTransaction";
+ // qDebug("KMyMoney2App::slotCancelOrEndEdit");
+ if(m_transactionEditor) {
+ if(KMyMoneyGlobalSettings::focusChangeIsEnter() && kmymoney2->action("transaction_enter")->isEnabled()) {
+ slotTransactionsEnter();
+ } else {
+ // okToSelect is preset to true if a cancel of the dialog is useful and false if it is not
+ int rc;
+ if(okToSelect == true) {
+ rc = KMessageBox::warningYesNoCancel(0, QString("<p>")+i18n("Do you really want to cancel editing this transaction without saving it?<p>- <b>Yes</b> cancels editing the transaction<br>- <b>No</b> saves the transaction prior to cancelling and<br>- <b>Cancel</b> returns to the transaction editor.<p>You can also select an option to save the transaction automatically when e.g. selecting another transaction."), i18n("Cancel transaction edit"), KStdGuiItem::yes(), KStdGuiItem::no(), dontShowAgain);
+
+ } else {
+ rc = KMessageBox::warningYesNo(0, QString("<p>")+i18n("Do you really want to cancel editing this transaction without saving it?<p>- <b>Yes</b> cancels editing the transaction<br>- <b>No</b> saves the transaction prior to cancelling.<p>You can also select an option to save the transaction automatically when e.g. selecting another transaction."), i18n("Cancel transaction edit"), KStdGuiItem::yes(), KStdGuiItem::no(), dontShowAgain);
+ }
+
+ switch(rc) {
+ case KMessageBox::Yes:
+ slotTransactionsCancel();
+ break;
+ case KMessageBox::No:
+ slotTransactionsEnter();
+ // make sure that we'll see this message the next time no matter
+ // if the user has chosen the 'Don't show again' checkbox
+ KMessageBox::enableMessage(dontShowAgain);
+ break;
+ case KMessageBox::Cancel:
+ // make sure that we'll see this message the next time no matter
+ // if the user has chosen the 'Don't show again' checkbox
+ KMessageBox::enableMessage(dontShowAgain);
+ okToSelect = false;
+ break;
+ }
+ }
+ }
+ oneTime = false;
+ }
+}
+
+void KMyMoney2App::slotToggleReconciliationFlag(void)
+{
+ markTransaction(MyMoneySplit::Unknown);
+}
+
+void KMyMoney2App::slotMarkTransactionCleared(void)
+{
+ markTransaction(MyMoneySplit::Cleared);
+}
+
+void KMyMoney2App::slotMarkTransactionReconciled(void)
+{
+ markTransaction(MyMoneySplit::Reconciled);
+}
+
+void KMyMoney2App::slotMarkTransactionNotReconciled(void)
+{
+ markTransaction(MyMoneySplit::NotReconciled);
+}
+
+void KMyMoney2App::markTransaction(MyMoneySplit::reconcileFlagE flag)
+{
+ KMyMoneyRegister::SelectedTransactions list = m_selectedTransactions;
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ int cnt = list.count();
+ int i = 0;
+ slotStatusProgressBar(0, cnt);
+ MyMoneyFileTransaction ft;
+ try {
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ // turn on signals before we modify the last entry in the list
+ cnt--;
+ MyMoneyFile::instance()->blockSignals(cnt != 0);
+
+ // get a fresh copy
+ MyMoneyTransaction t = MyMoneyFile::instance()->transaction((*it_t).transaction().id());
+ MyMoneySplit sp = t.splitById((*it_t).split().id());
+ if(sp.reconcileFlag() != flag) {
+ if(flag == MyMoneySplit::Unknown) {
+ if(m_reconciliationAccount.id().isEmpty()) {
+ // in normal mode we cycle through all states
+ switch(sp.reconcileFlag()) {
+ case MyMoneySplit::NotReconciled:
+ sp.setReconcileFlag(MyMoneySplit::Cleared);
+ break;
+ case MyMoneySplit::Cleared:
+ sp.setReconcileFlag(MyMoneySplit::Reconciled);
+ break;
+ case MyMoneySplit::Reconciled:
+ sp.setReconcileFlag(MyMoneySplit::NotReconciled);
+ break;
+ default:
+ break;
+ }
+ } else {
+ // in reconciliation mode we skip the reconciled state
+ switch(sp.reconcileFlag()) {
+ case MyMoneySplit::NotReconciled:
+ sp.setReconcileFlag(MyMoneySplit::Cleared);
+ break;
+ case MyMoneySplit::Cleared:
+ sp.setReconcileFlag(MyMoneySplit::NotReconciled);
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ sp.setReconcileFlag(flag);
+ }
+
+ t.modifySplit(sp);
+ MyMoneyFile::instance()->modifyTransaction(t);
+ }
+ slotStatusProgressBar(i++, 0);
+ }
+ slotStatusProgressBar(-1, -1);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify transaction: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotTransactionsAccept(void)
+{
+ KMyMoneyRegister::SelectedTransactions list = m_selectedTransactions;
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ int cnt = list.count();
+ int i = 0;
+ slotStatusProgressBar(0, cnt);
+ MyMoneyFileTransaction ft;
+ try {
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ // reload transaction in case it got changed during the course of this loop
+ MyMoneyTransaction t = MyMoneyFile::instance()->transaction((*it_t).transaction().id());
+ if(t.isImported()) {
+ t.setImported(false);
+ if(!m_selectedAccount.id().isEmpty()) {
+ QValueList<MyMoneySplit> list = t.splits();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if((*it_s).accountId() == m_selectedAccount.id()) {
+ if((*it_s).reconcileFlag() == MyMoneySplit::NotReconciled) {
+ MyMoneySplit s = (*it_s);
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ t.modifySplit(s);
+ }
+ }
+ }
+ }
+ MyMoneyFile::instance()->modifyTransaction(t);
+ }
+ if((*it_t).split().isMatched()) {
+ // reload split in case it got changed during the course of this loop
+ MyMoneySplit s = t.splitById((*it_t).split().id());
+ TransactionMatcher matcher(m_selectedAccount);
+ matcher.accept(t, s);
+ }
+ slotStatusProgressBar(i++, 0);
+ }
+ slotStatusProgressBar(-1, -1);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to accept transaction: %1, thrown in %2:%3").arg(e->what()).arg(e->file()).arg(e->line()));
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotTransactionGotoAccount(void)
+{
+ if(!m_accountGoto.isEmpty()) {
+ try {
+ QString transactionId;
+ if(m_selectedTransactions.count() == 1) {
+ transactionId = m_selectedTransactions[0].transaction().id();
+ }
+ // make sure to pass a copy, as myMoneyView->slotLedgerSelected() overrides
+ // m_accountGoto while calling slotUpdateActions()
+ QString accountId = m_accountGoto;
+ myMoneyView->slotLedgerSelected(accountId, transactionId);
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotTransactionGotoPayee(void)
+{
+ if(!m_payeeGoto.isEmpty()) {
+ try {
+ QString transactionId;
+ if(m_selectedTransactions.count() == 1) {
+ transactionId = m_selectedTransactions[0].transaction().id();
+ }
+ // make sure to pass copies, as myMoneyView->slotPayeeSelected() overrides
+ // m_payeeGoto and m_selectedAccount while calling slotUpdateActions()
+ QString payeeId = m_payeeGoto;
+ QString accountId = m_selectedAccount.id();
+ myMoneyView->slotPayeeSelected(payeeId, accountId, transactionId);
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotTransactionCreateSchedule(void)
+{
+ if(m_selectedTransactions.count() == 1) {
+ // make sure to have the current selected split as first split in the schedule
+ MyMoneyTransaction t = m_selectedTransactions[0].transaction();
+ MyMoneySplit s = m_selectedTransactions[0].split();
+ QString splitId = s.id();
+ s.clearId();
+ s.setReconcileFlag(MyMoneySplit::NotReconciled);
+ s.setReconcileDate(QDate());
+ t.removeSplits();
+ t.addSplit(s);
+ const QValueList<MyMoneySplit>& splits = m_selectedTransactions[0].transaction().splits();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ if((*it_s).id() != splitId) {
+ MyMoneySplit s0 = (*it_s);
+ s0.clearId();
+ s0.setReconcileFlag(MyMoneySplit::NotReconciled);
+ s0.setReconcileDate(QDate());
+ t.addSplit(s0);
+ }
+ }
+ slotScheduleNew(t);
+ }
+}
+
+void KMyMoney2App::slotTransactionAssignNumber(void)
+{
+ if(m_transactionEditor)
+ m_transactionEditor->assignNextNumber();
+}
+
+void KMyMoney2App::slotTransactionCombine(void)
+{
+ qDebug("slotTransactionCombine() not implemented yet");
+}
+
+void KMyMoney2App::slotMoveToAccount(const QString& id)
+{
+ // close the menu, if it is still open
+ QWidget* w = factory()->container("transaction_move_menu", this);
+ if(w) {
+ if(w->isVisible()) {
+ w->close();
+ }
+ }
+
+ if(m_selectedTransactions.count() > 0) {
+ MyMoneyFileTransaction ft;
+ try {
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ for(it_t = m_selectedTransactions.begin(); it_t != m_selectedTransactions.end(); ++it_t) {
+ if (m_selectedAccount.accountType() == MyMoneyAccount::Investment) {
+ d->moveInvestmentTransaction(m_selectedAccount.id(), id,
+ (*it_t).transaction());
+ } else {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ bool changed = false;
+ MyMoneyTransaction t = (*it_t).transaction();
+ for(it_s = (*it_t).transaction().splits().begin(); it_s != (*it_t).transaction().splits().end(); ++it_s) {
+ if((*it_s).accountId() == m_selectedAccount.id()) {
+ MyMoneySplit s = (*it_s);
+ s.setAccountId(id);
+ t.modifySplit(s);
+ changed = true;
+ }
+ }
+ if(changed) {
+ MyMoneyFile::instance()->modifyTransaction(t);
+ }
+ }
+ }
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+}
+
+// move a stock transaction from one investment account to another
+void KMyMoney2App::Private::moveInvestmentTransaction(const QString& fromId,
+ const QString& toId,
+ const MyMoneyTransaction& tx)
+{
+ MyMoneyAccount toInvAcc = MyMoneyFile::instance()->account(toId);
+ MyMoneyTransaction t(tx);
+ // first determine which stock we are dealing with.
+ // fortunately, investment transactions have only one stock involved
+ QString stockAccountId;
+ QString stockSecurityId;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ stockAccountId = (*it_s).accountId();
+ stockSecurityId =
+ MyMoneyFile::instance()->account(stockAccountId).currencyId();
+ if (!MyMoneyFile::instance()->security(stockSecurityId).isCurrency())
+ break;
+ }
+ // Now check the target investment account to see if it
+ // contains a stock with this id
+ QString newStockAccountId = QString();
+ QStringList accountList = toInvAcc.accountList();
+ QStringList::const_iterator it_a;
+ for (it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ if (MyMoneyFile::instance()->account((*it_a)).currencyId() ==
+ stockSecurityId) {
+ newStockAccountId = (*it_a);
+ break;
+ }
+ }
+ // if it doesn't exist, we need to add it as a copy of the old one
+ // no 'copyAccount()' function??
+ if (newStockAccountId.isEmpty()) {
+ MyMoneyAccount stockAccount =
+ MyMoneyFile::instance()->account(stockAccountId);
+ MyMoneyAccount newStock;
+ newStock.setName(stockAccount.name());
+ newStock.setNumber(stockAccount.number());
+ newStock.setDescription(stockAccount.description());
+ newStock.setInstitutionId(stockAccount.institutionId());
+ newStock.setOpeningDate(stockAccount.openingDate());
+ newStock.setAccountType(stockAccount.accountType());
+ newStock.setCurrencyId(stockAccount.currencyId());
+ newStock.setClosed(stockAccount.isClosed());
+ MyMoneyFile::instance()->addAccount(newStock, toInvAcc);
+ newStockAccountId = newStock.id();
+ }
+ // now update the split and the transaction
+ MyMoneySplit s = (*it_s);
+ s.setAccountId(newStockAccountId);
+ t.modifySplit(s);
+ MyMoneyFile::instance()->modifyTransaction(t);
+}
+
+void KMyMoney2App::slotUpdateMoveToAccountMenu(void)
+{
+ if(!m_selectedAccount.id().isEmpty()) {
+ AccountSet accountSet;
+ if(m_selectedAccount.accountType() == MyMoneyAccount::Investment) {
+ accountSet.addAccountType(MyMoneyAccount::Investment);
+ } else if(m_selectedAccount.isAssetLiability()) {
+ accountSet.addAccountType(MyMoneyAccount::Checkings);
+ accountSet.addAccountType(MyMoneyAccount::Savings);
+ accountSet.addAccountType(MyMoneyAccount::Cash);
+ accountSet.addAccountType(MyMoneyAccount::AssetLoan);
+ accountSet.addAccountType(MyMoneyAccount::CertificateDep);
+ accountSet.addAccountType(MyMoneyAccount::MoneyMarket);
+ accountSet.addAccountType(MyMoneyAccount::Asset);
+ accountSet.addAccountType(MyMoneyAccount::Currency);
+ accountSet.addAccountType(MyMoneyAccount::CreditCard);
+ accountSet.addAccountType(MyMoneyAccount::Loan);
+ accountSet.addAccountType(MyMoneyAccount::Liability);
+ } else if(m_selectedAccount.isIncomeExpense()) {
+ accountSet.addAccountType(MyMoneyAccount::Income);
+ accountSet.addAccountType(MyMoneyAccount::Expense);
+ }
+
+ accountSet.load(d->m_moveToAccountSelector);
+ // remove those accounts that we currently reference
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ for(it_t = m_selectedTransactions.begin(); it_t != m_selectedTransactions.end(); ++it_t) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = (*it_t).transaction().splits().begin(); it_s != (*it_t).transaction().splits().end(); ++it_s) {
+ d->m_moveToAccountSelector->removeItem((*it_s).accountId());
+ }
+ }
+ // remove those accounts from the list that are denominated
+ // in a different currency
+ // also remove the selected account itself
+ //(for investments, which will not have been removed above)
+ QStringList list = d->m_moveToAccountSelector->accountList();
+ QValueList<QString>::const_iterator it_a;
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.currencyId() != m_selectedAccount.currencyId())
+ d->m_moveToAccountSelector->removeItem((*it_a));
+ if (acc.id() == m_selectedAccount.id())
+ d->m_moveToAccountSelector->removeItem((*it_a));
+ }
+ // Now update the width of the list
+ d->m_moveToAccountSelector->setOptimizedWidth();
+ }
+}
+
+void KMyMoney2App::slotTransactionMatch(void)
+{
+ if(action("transaction_match")->text() == i18n("Button text for match transaction", "Match"))
+ transactionMatch();
+ else
+ transactionUnmatch();
+}
+
+void KMyMoney2App::transactionUnmatch(void)
+{
+ KMyMoneyRegister::SelectedTransactions::const_iterator it;
+ MyMoneyFileTransaction ft;
+ try {
+ for(it = m_selectedTransactions.begin(); it != m_selectedTransactions.end(); ++it) {
+ if((*it).split().isMatched()) {
+ TransactionMatcher matcher(m_selectedAccount);
+ matcher.unmatch((*it).transaction(), (*it).split());
+ }
+ }
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to unmatch the selected transactions"), e->what() );
+ delete e;
+ }
+}
+
+void KMyMoney2App::transactionMatch(void)
+{
+ if(m_selectedTransactions.count() != 2)
+ return;
+
+ MyMoneyTransaction startMatchTransaction;
+ MyMoneyTransaction endMatchTransaction;
+ MyMoneySplit startSplit;
+ MyMoneySplit endSplit;
+
+ KMyMoneyRegister::SelectedTransactions::const_iterator it;
+ KMyMoneyRegister::SelectedTransactions toBeDeleted;
+ for(it = m_selectedTransactions.begin(); it != m_selectedTransactions.end(); ++it) {
+ if((*it).transaction().isImported()) {
+ endMatchTransaction = (*it).transaction();
+ endSplit = (*it).split();
+ toBeDeleted << *it;
+ } else if(!(*it).split().isMatched()) {
+ startMatchTransaction = (*it).transaction();
+ startSplit = (*it).split();
+ }
+ }
+
+#if 0
+ KMergeTransactionsDlg dlg(m_selectedAccount);
+ dlg.addTransaction(startMatchTransaction);
+ dlg.addTransaction(endMatchTransaction);
+ if (dlg.exec() == QDialog::Accepted)
+#endif
+ {
+ MyMoneyFileTransaction ft;
+ try
+ {
+ if(startMatchTransaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION(i18n("No manually entered transaction selected for matching"));
+ if(endMatchTransaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION(i18n("No imported transaction selected for matching"));
+
+ TransactionMatcher matcher(m_selectedAccount);
+ matcher.match(startMatchTransaction, startSplit, endMatchTransaction, endSplit);
+ ft.commit();
+ }
+ catch(MyMoneyException *e)
+ {
+ KMessageBox::detailedSorry(0, i18n("Unable to match the selected transactions"), e->what() );
+ delete e;
+ }
+ }
+}
+
+
+void KMyMoney2App::showContextMenu(const QString& containerName)
+{
+ QWidget* w = factory()->container(containerName, this);
+ QPopupMenu *menu = dynamic_cast<QPopupMenu*>(w);
+ if(menu)
+ menu->exec(QCursor::pos());
+}
+
+void KMyMoney2App::slotShowTransactionContextMenu(void)
+{
+ if(m_selectedTransactions.count() == 0 && m_selectedSchedule != MyMoneySchedule()) {
+ showContextMenu("schedule_context_menu");
+ } else {
+ showContextMenu("transaction_context_menu");
+ }
+}
+
+void KMyMoney2App::slotShowInvestmentContextMenu(void)
+{
+ showContextMenu("investment_context_menu");
+}
+
+void KMyMoney2App::slotShowScheduleContextMenu(void)
+{
+ showContextMenu("schedule_context_menu");
+}
+
+void KMyMoney2App::slotShowAccountContextMenu(const MyMoneyObject& obj)
+{
+// qDebug("KMyMoney2App::slotShowAccountContextMenu");
+ if(typeid(obj) != typeid(MyMoneyAccount))
+ return;
+
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(obj);
+
+ // if the selected account is actually a stock account, we
+ // call the right slot instead
+ if(acc.isInvest()) {
+ showContextMenu("investment_context_menu");
+ } else if(acc.isIncomeExpense()){
+ showContextMenu("category_context_menu");
+ } else {
+ showContextMenu("account_context_menu");
+ }
+}
+
+void KMyMoney2App::slotShowInstitutionContextMenu(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyInstitution))
+ return;
+
+ showContextMenu("institution_context_menu");
+}
+
+void KMyMoney2App::slotShowPayeeContextMenu(void)
+{
+ showContextMenu("payee_context_menu");
+}
+
+void KMyMoney2App::slotShowBudgetContextMenu(void)
+{
+ showContextMenu("budget_context_menu");
+}
+
+void KMyMoney2App::slotShowCurrencyContextMenu(void)
+{
+ showContextMenu("currency_context_menu");
+}
+
+void KMyMoney2App::slotPrintView(void)
+{
+ myMoneyView->slotPrintView();
+}
+
+void KMyMoney2App::updateCaption(bool skipActions)
+{
+ QString caption;
+
+ caption = m_fileName.filename(false);
+
+ if(caption.isEmpty() && myMoneyView && myMoneyView->fileOpen())
+ caption = i18n("Untitled");
+
+ // MyMoneyFile::instance()->dirty() throws an exception, if
+ // there's no storage object available. In this case, we
+ // assume that the storage object is not changed. Actually,
+ // this can only happen if we are newly created early on.
+ bool modified;
+ try {
+ modified = MyMoneyFile::instance()->dirty();
+ } catch(MyMoneyException *e) {
+ delete e;
+ modified = false;
+ skipActions = true;
+ }
+
+#if KMM_DEBUG
+ caption += QString(" (%1 x %2)").arg(width()).arg(height());
+#endif
+
+ caption = kapp->makeStdCaption(caption, false, modified);
+ if(caption.length() > 0)
+ caption += " - ";
+ caption += "KMyMoney";
+ setPlainCaption(caption);
+
+ if(!skipActions) {
+ myMoneyView->enableViews();
+ slotUpdateActions();
+ }
+}
+
+void KMyMoney2App::slotUpdateActions(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ bool fileOpen = myMoneyView->fileOpen();
+ bool modified = file->dirty();
+ QWidget* w;
+
+ action("open_database")->setEnabled(true);
+ action("saveas_database")->setEnabled(fileOpen);
+ action("file_save")->setEnabled(modified && !myMoneyView->isDatabase());
+ action("file_save_as")->setEnabled(fileOpen);
+ action("file_close")->setEnabled(fileOpen);
+ action("view_personal_data")->setEnabled(fileOpen);
+ action("file_backup")->setEnabled(fileOpen && !myMoneyView->isDatabase());
+ action("file_print")->setEnabled(fileOpen && myMoneyView->canPrint());
+#if KMM_DEBUG
+ action("view_file_info")->setEnabled(fileOpen);
+ action("file_dump")->setEnabled(fileOpen);
+#endif
+
+ action("edit_find_transaction")->setEnabled(fileOpen);
+
+ bool importRunning = (m_qifReader != 0) || (m_smtReader != 0);
+ action("file_export_qif")->setEnabled(fileOpen && !importRunning);
+ action("file_import_qif")->setEnabled(fileOpen && !importRunning);
+ action("file_import_gnc")->setEnabled(!importRunning);
+ action("file_import_template")->setEnabled(fileOpen && !importRunning);
+ action("file_export_template")->setEnabled(fileOpen && !importRunning);
+
+
+ action("tools_security_editor")->setEnabled(fileOpen);
+ action("tools_currency_editor")->setEnabled(fileOpen);
+ action("tools_price_editor")->setEnabled(fileOpen);
+ action("tools_update_prices")->setEnabled(fileOpen);
+ action("tools_consistency_check")->setEnabled(fileOpen);
+
+ action("account_new")->setEnabled(fileOpen);
+ action("account_reconcile")->setEnabled(false);
+ action("account_reconcile_finish")->setEnabled(false);
+ action("account_reconcile_postpone")->setEnabled(false);
+ action("account_edit")->setEnabled(false);
+ action("account_delete")->setEnabled(false);
+ action("account_open")->setEnabled(false);
+ action("account_close")->setEnabled(false);
+ action("account_reopen")->setEnabled(false);
+ action("account_transaction_report")->setEnabled(false);
+ action("account_online_map")->setEnabled(false);
+ action("account_online_update")->setEnabled(false);
+ action("account_online_update_all")->setEnabled(false);
+ action("account_online_update_menu")->setEnabled(false);
+ action("account_online_unmap")->setEnabled(false);
+#ifdef HAVE_KDCHART
+ action("account_chart")->setEnabled(false);
+#endif
+
+ action("category_new")->setEnabled(fileOpen);
+ action("category_edit")->setEnabled(false);
+ action("category_delete")->setEnabled(false);
+
+ action("institution_new")->setEnabled(fileOpen);
+ action("institution_edit")->setEnabled(false);
+ action("institution_delete")->setEnabled(false);
+ action("investment_new")->setEnabled(false);
+ action("investment_edit")->setEnabled(false);
+ action("investment_delete")->setEnabled(false);
+ action("investment_online_price_update")->setEnabled(false);
+ action("investment_manual_price_update")->setEnabled(false);
+
+ action("schedule_edit")->setEnabled(false);
+ action("schedule_delete")->setEnabled(false);
+ action("schedule_enter")->setEnabled(false);
+ action("schedule_skip")->setEnabled(false);
+
+ action("payee_delete")->setEnabled(false);
+ action("payee_rename")->setEnabled(false);
+
+ action("budget_delete")->setEnabled(false);
+ action("budget_rename")->setEnabled(false);
+ action("budget_change_year")->setEnabled(false);
+ action("budget_new")->setEnabled(true);
+ action("budget_copy")->setEnabled(false);
+ action("budget_forecast")->setEnabled(false);
+
+ QString tooltip = i18n("Create a new transaction");
+ action("transaction_new")->setEnabled(fileOpen && myMoneyView->canCreateTransactions(KMyMoneyRegister::SelectedTransactions(), tooltip));
+ action("transaction_new")->setToolTip(tooltip);
+
+ action("transaction_edit")->setEnabled(false);
+ action("transaction_editsplits")->setEnabled(false);
+ action("transaction_enter")->setEnabled(false);
+ action("transaction_cancel")->setEnabled(false);
+ action("transaction_delete")->setEnabled(false);
+ action("transaction_match")->setEnabled(false);
+ action("transaction_match")->setText(i18n("Button text for match transaction", "Match"));
+ action("transaction_match")->setIcon("connect_creating");
+
+ action("transaction_accept")->setEnabled(false);
+ action("transaction_duplicate")->setEnabled(false);
+ action("transaction_mark_toggle")->setEnabled(false);
+ action("transaction_mark_cleared")->setEnabled(false);
+ action("transaction_mark_reconciled")->setEnabled(false);
+ action("transaction_mark_notreconciled")->setEnabled(false);
+ action("transaction_goto_account")->setEnabled(false);
+ action("transaction_goto_payee")->setEnabled(false);
+ action("transaction_assign_number")->setEnabled(false);
+ action("transaction_create_schedule")->setEnabled(false);
+ action("transaction_combine")->setEnabled(false);
+ action("transaction_select_all")->setEnabled(false);
+
+ action("schedule_new")->setEnabled(fileOpen);
+ action("schedule_edit")->setEnabled(false);
+ action("schedule_delete")->setEnabled(false);
+ action("schedule_duplicate")->setEnabled(false);
+ action("schedule_enter")->setEnabled(false);
+ action("schedule_skip")->setEnabled(false);
+
+ action("currency_new")->setEnabled(fileOpen);
+ action("currency_rename")->setEnabled(false);
+ action("currency_delete")->setEnabled(false);
+ action("currency_setbase")->setEnabled(false);
+
+ w = factory()->container("transaction_move_menu", this);
+ if(w)
+ w->setEnabled(false);
+
+ w = factory()->container("transaction_mark_menu", this);
+ if(w)
+ w->setEnabled(false);
+
+ w = factory()->container("transaction_context_mark_menu", this);
+ if(w)
+ w->setEnabled(false);
+
+ // FIXME for now it's always on, but we should only allow it, if we
+ // can select at least a single transaction
+ action("transaction_select_all")->setEnabled(true);
+ if(!m_selectedTransactions.isEmpty()) {
+ if(m_selectedTransactions.count() != 0) {
+ // enable 'delete transaction' only if at least one of the
+ // selected transactions does not reference a closed account
+ bool enable = false;
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ for(it_t = m_selectedTransactions.begin(); (enable == false) && (it_t != m_selectedTransactions.end()); ++it_t) {
+ enable = !file->referencesClosedAccount((*it_t).transaction());
+ }
+ action("transaction_delete")->setEnabled(enable);
+ }
+
+ if(!m_transactionEditor) {
+ tooltip = i18n("Duplicate the current selected transactions");
+ action("transaction_duplicate")->setEnabled(myMoneyView->canDuplicateTransactions(m_selectedTransactions, tooltip) && !m_selectedTransactions[0].transaction().id().isEmpty());
+ action("transaction_duplicate")->setToolTip(tooltip);
+ if(myMoneyView->canEditTransactions(m_selectedTransactions, tooltip)) {
+ action("transaction_edit")->setEnabled(true);
+ // editing splits is allowed only if we have one transaction selected
+ if(m_selectedTransactions.count() == 1) {
+ action("transaction_editsplits")->setEnabled(true);
+ }
+ if(m_selectedAccount.isAssetLiability() && m_selectedAccount.accountType() != MyMoneyAccount::Investment) {
+ action("transaction_create_schedule")->setEnabled(m_selectedTransactions.count() == 1);
+ }
+ }
+ action("transaction_edit")->setToolTip(tooltip);
+
+ if(!m_selectedAccount.isClosed()) {
+ w = factory()->container("transaction_move_menu", this);
+ if(w)
+ w->setEnabled(true);
+ }
+
+ w = factory()->container("transaction_mark_menu", this);
+ if(w)
+ w->setEnabled(true);
+
+ w = factory()->container("transaction_context_mark_menu", this);
+ if(w)
+ w->setEnabled(true);
+
+ // Allow marking the transaction if at least one is selected
+ action("transaction_mark_cleared")->setEnabled(true);
+ action("transaction_mark_reconciled")->setEnabled(true);
+ action("transaction_mark_notreconciled")->setEnabled(true);
+ action("transaction_mark_toggle")->setEnabled(true);
+
+ if(!m_accountGoto.isEmpty())
+ action("transaction_goto_account")->setEnabled(true);
+ if(!m_payeeGoto.isEmpty())
+ action("transaction_goto_payee")->setEnabled(true);
+
+ // Matching is enabled as soon as one regular and one imported transaction is selected
+ int matchedCount = 0;
+ int importedCount = 0;
+ KMyMoneyRegister::SelectedTransactions::const_iterator it;
+ for(it = m_selectedTransactions.begin(); it != m_selectedTransactions.end(); ++it) {
+ if((*it).transaction().isImported())
+ ++importedCount;
+ if((*it).split().isMatched())
+ ++matchedCount;
+ }
+
+ if(m_selectedTransactions.count() == 2 /* && action("transaction_edit")->isEnabled() */) {
+ if(importedCount == 1 && matchedCount == 0) {
+ action("transaction_match")->setEnabled(true);
+ }
+ }
+ if(importedCount != 0 || matchedCount != 0)
+ action("transaction_accept")->setEnabled(true);
+ if(matchedCount != 0) {
+ action("transaction_match")->setEnabled(true);
+ action("transaction_match")->setText(i18n("Button text for unmatch transaction", "Unmatch"));
+ action("transaction_match")->setIcon("stop");
+ }
+
+ if(m_selectedTransactions.count() > 1) {
+ action("transaction_combine")->setEnabled(true);
+ }
+ } else {
+ action("transaction_assign_number")->setEnabled(m_transactionEditor->canAssignNumber());
+ action("transaction_new")->setEnabled(false);
+ action("transaction_delete")->setEnabled(false);
+ QString reason;
+ action("transaction_enter")->setEnabled(m_transactionEditor->isComplete(reason));
+ action("transaction_enter")->setToolTip(reason);
+ action("transaction_cancel")->setEnabled(true);
+ }
+ }
+
+ QValueList<MyMoneyAccount> accList;
+ file->accountList(accList);
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin*>::const_iterator it_p = m_onlinePlugins.end();
+ for(it_a = accList.begin(); (it_p == m_onlinePlugins.end()) && (it_a != accList.end()); ++it_a) {
+ if ( !(*it_a).onlineBankingSettings().value("provider").isEmpty() ) {
+ // check if provider is available
+ it_p = m_onlinePlugins.find((*it_a).onlineBankingSettings().value("provider"));
+ if(it_p != m_onlinePlugins.end()) {
+ QStringList protocols;
+ (*it_p)->protocols(protocols);
+ if(protocols.count() > 0) {
+ action("account_online_update_all")->setEnabled(true);
+ action("account_online_update_menu")->setEnabled(true);
+ }
+ }
+ }
+ }
+ MyMoneyFileBitArray skip(IMyMoneyStorage::MaxRefCheckBits);
+ if(!m_selectedAccount.id().isEmpty()) {
+ if(!file->isStandardAccount(m_selectedAccount.id())) {
+ switch(m_selectedAccount.accountGroup()) {
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Equity:
+ action("account_transaction_report")->setEnabled(true);
+ action("account_edit")->setEnabled(true);
+ action("account_delete")->setEnabled(!file->isReferenced(m_selectedAccount));
+ action("account_open")->setEnabled(true);
+ if(m_selectedAccount.accountGroup() != MyMoneyAccount::Equity) {
+ if(m_reconciliationAccount.id().isEmpty()) {
+ action("account_reconcile")->setEnabled(true);
+ } else {
+ if(!m_transactionEditor) {
+ action("account_reconcile_finish")->setEnabled(m_selectedAccount.id() == m_reconciliationAccount.id());
+ action("account_reconcile_postpone")->setEnabled(m_selectedAccount.id() == m_reconciliationAccount.id());
+ }
+ }
+ }
+
+ if(m_selectedAccount.accountType() == MyMoneyAccount::Investment)
+ action("investment_new")->setEnabled(true);
+
+ if(m_selectedAccount.isClosed())
+ action("account_reopen")->setEnabled(true);
+ else if(canCloseAccount(m_selectedAccount))
+ action("account_close")->setEnabled(true);
+
+ if ( !m_selectedAccount.onlineBankingSettings().value("provider").isEmpty() ) {
+ action("account_online_unmap")->setEnabled(true);
+ // check if provider is available
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin*>::const_iterator it_p;
+ it_p = m_onlinePlugins.find(m_selectedAccount.onlineBankingSettings().value("provider"));
+ if(it_p != m_onlinePlugins.end()) {
+ QStringList protocols;
+ (*it_p)->protocols(protocols);
+ if(protocols.count() > 0) {
+ action("account_online_update")->setEnabled(true);
+ action("account_online_update_menu")->setEnabled(true);
+ }
+ }
+ } else
+ action("account_online_map")->setEnabled(m_onlinePlugins.count() > 0);
+
+#ifdef HAVE_KDCHART
+ action("account_chart")->setEnabled(true);
+#endif
+ break;
+
+ case MyMoneyAccount::Income :
+ case MyMoneyAccount::Expense :
+ action("category_edit")->setEnabled(true);
+ // enable delete action, if category/account itself is not referenced
+ // by any object except accounts, because we want to allow
+ // deleting of sub-categories. Also, we allow transactions, schedules and budgets
+ // to be present because we can re-assign them during the delete process
+ skip.fill(false);
+ skip.setBit(IMyMoneyStorage::RefCheckTransaction);
+ skip.setBit(IMyMoneyStorage::RefCheckAccount);
+ skip.setBit(IMyMoneyStorage::RefCheckSchedule);
+ skip.setBit(IMyMoneyStorage::RefCheckBudget);
+ action("category_delete")->setEnabled(!file->isReferenced(m_selectedAccount, skip));
+ action("account_open")->setEnabled(true);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if(!m_selectedInstitution.id().isEmpty()) {
+ action("institution_edit")->setEnabled(true);
+ action("institution_delete")->setEnabled(!file->isReferenced(m_selectedInstitution));
+ }
+
+ if(!m_selectedInvestment.id().isEmpty()) {
+ action("investment_edit")->setEnabled(true);
+ action("investment_delete")->setEnabled(!file->isReferenced(m_selectedInvestment));
+ action("investment_manual_price_update")->setEnabled(true);
+ try {
+ MyMoneySecurity security = MyMoneyFile::instance()->security(m_selectedInvestment.currencyId());
+ if(!security.value("kmm-online-source").isEmpty())
+ action("investment_online_price_update")->setEnabled(true);
+
+ } catch(MyMoneyException *e) {
+ qDebug("Error retrieving security for investment %s: %s", m_selectedInvestment.name().data(), e->what().data());
+ delete e;
+ }
+ if(m_selectedInvestment.isClosed())
+ action("account_reopen")->setEnabled(true);
+ else if(canCloseAccount(m_selectedInvestment))
+ action("account_close")->setEnabled(true);
+ }
+
+ if(!m_selectedSchedule.id().isEmpty()) {
+ action("schedule_edit")->setEnabled(true);
+ action("schedule_duplicate")->setEnabled(true);
+ action("schedule_delete")->setEnabled(!file->isReferenced(m_selectedSchedule));
+ if(!m_selectedSchedule.isFinished()) {
+ action("schedule_enter")->setEnabled(true);
+ // a schedule with a single occurence cannot be skipped
+ if(m_selectedSchedule.occurence() != MyMoneySchedule::OCCUR_ONCE) {
+ action("schedule_skip")->setEnabled(true);
+ }
+ }
+ }
+
+ if(m_selectedPayees.count() >= 1) {
+ action("payee_rename")->setEnabled(m_selectedPayees.count() == 1);
+ action("payee_delete")->setEnabled(true);
+ }
+
+ if(m_selectedBudgets.count() >= 1) {
+ action("budget_delete")->setEnabled(true);
+ if(m_selectedBudgets.count() == 1) {
+ action("budget_change_year")->setEnabled(true);
+ action("budget_copy")->setEnabled(true);
+ action("budget_rename")->setEnabled(true);
+ action("budget_forecast")->setEnabled(true);
+ }
+ }
+
+ if(!m_selectedCurrency.id().isEmpty()) {
+ action("currency_rename")->setEnabled(true);
+ // no need to check each transaction. accounts are enough in this case
+ skip.fill(false);
+ skip.setBit(IMyMoneyStorage::RefCheckTransaction);
+ action("currency_delete")->setEnabled(!file->isReferenced(m_selectedCurrency, skip));
+ if(m_selectedCurrency.id() != file->baseCurrency().id())
+ action("currency_setbase")->setEnabled(true);
+ }
+}
+
+void KMyMoney2App::slotResetSelections(void)
+{
+ slotSelectAccount();
+ slotSelectInstitution();
+ slotSelectInvestment();
+ slotSelectSchedule();
+ slotSelectCurrency();
+ slotSelectPayees(QValueList<MyMoneyPayee>());
+ slotSelectBudget(QValueList<MyMoneyBudget>());
+ slotSelectTransactions(KMyMoneyRegister::SelectedTransactions());
+ slotUpdateActions();
+}
+
+void KMyMoney2App::slotSelectCurrency(const MyMoneySecurity& currency)
+{
+ m_selectedCurrency = currency;
+ slotUpdateActions();
+ emit currencySelected(m_selectedCurrency);
+}
+
+void KMyMoney2App::slotSelectBudget(const QValueList<MyMoneyBudget>& list)
+{
+ m_selectedBudgets = list;
+ slotUpdateActions();
+ emit budgetSelected(m_selectedBudgets);
+}
+
+void KMyMoney2App::slotSelectPayees(const QValueList<MyMoneyPayee>& list)
+{
+ m_selectedPayees = list;
+ slotUpdateActions();
+ emit payeesSelected(m_selectedPayees);
+}
+
+void KMyMoney2App::slotSelectTransactions(const KMyMoneyRegister::SelectedTransactions& list)
+{
+ // list can either contain a list of transactions or a single selected scheduled transaction
+ // in the latter case, the transaction id is actually the one of the schedule. In order
+ // to differentiate between the two, we just ask for the schedule. If we don't find one - because
+ // we passed the id of a real transaction - then we know that fact. We use the schedule here,
+ // because the list of schedules is kept in a cache by MyMoneyFile. This way, we save some trips
+ // to the backend which we would have to do if we check for the transaction.
+ m_selectedTransactions.clear();
+ m_selectedSchedule = MyMoneySchedule();
+
+ m_accountGoto = QString();
+ m_payeeGoto = QString();
+ if(list.count() > 0 && !list.first().isScheduled()) {
+ m_selectedTransactions = list;
+ if(list.count() == 1) {
+ const MyMoneySplit& sp = m_selectedTransactions[0].split();
+ if(!sp.payeeId().isEmpty()) {
+ try {
+ MyMoneyPayee payee = MyMoneyFile::instance()->payee(sp.payeeId());
+ if(!payee.name().isEmpty()) {
+ m_payeeGoto = payee.id();
+ QString name = payee.name();
+ name.replace(QRegExp("&(?!&)"), "&&");
+ action("transaction_goto_payee")->setText(i18n("Goto '%1'").arg(name));
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+ try {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ const MyMoneyTransaction& t = m_selectedTransactions[0].transaction();
+ // search the first non-income/non-expense accunt and use it for the 'goto account'
+ const MyMoneySplit& sp = m_selectedTransactions[0].split();
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).id() != sp.id()) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(!acc.isIncomeExpense()) {
+ // for stock accounts we show the portfolio account
+ if(acc.isInvest()) {
+ acc = MyMoneyFile::instance()->account(acc.parentAccountId());
+ }
+ m_accountGoto = acc.id();
+ QString name = acc.name();
+ name.replace(QRegExp("&(?!&)"), "&&");
+ action("transaction_goto_account")->setText(i18n("Goto '%1'").arg(name));
+ break;
+ }
+ }
+ }
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+ }
+
+ slotUpdateActions();
+ emit transactionsSelected(m_selectedTransactions);
+
+ } else if(list.count() > 0) {
+ slotSelectSchedule(MyMoneyFile::instance()->schedule(list.first().scheduleId()));
+
+ } else {
+ slotUpdateActions();
+ }
+
+ // make sure, we show some neutral menu entry if we don't have an object
+ if(m_payeeGoto.isEmpty())
+ action("transaction_goto_payee")->setText(i18n("Goto payee"));
+ if(m_accountGoto.isEmpty())
+ action("transaction_goto_account")->setText(i18n("Goto account"));
+}
+
+void KMyMoney2App::slotSelectInstitution(const MyMoneyObject& institution)
+{
+ if(typeid(institution) != typeid(MyMoneyInstitution))
+ return;
+
+ m_selectedInstitution = dynamic_cast<const MyMoneyInstitution&>(institution);
+ // qDebug("slotSelectInstitution('%s')", m_selectedInstitution.name().data());
+ slotUpdateActions();
+ emit institutionSelected(m_selectedInstitution);
+}
+
+void KMyMoney2App::slotSelectAccount(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyAccount))
+ return;
+
+ m_selectedAccount = MyMoneyAccount();
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(obj);
+ if(!acc.isInvest())
+ m_selectedAccount = acc;
+
+ // qDebug("slotSelectAccount('%s')", m_selectedAccount.name().data());
+ slotUpdateActions();
+ emit accountSelected(m_selectedAccount);
+}
+
+void KMyMoney2App::slotSelectInvestment(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyAccount))
+ return;
+
+ // qDebug("slotSelectInvestment('%s')", account.name().data());
+ m_selectedInvestment = MyMoneyAccount();
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(obj);
+ if(acc.isInvest())
+ m_selectedInvestment = acc;
+
+ slotUpdateActions();
+ emit investmentSelected(m_selectedInvestment);
+}
+
+void KMyMoney2App::slotSelectSchedule(const MyMoneySchedule& schedule)
+{
+ // qDebug("slotSelectSchedule('%s')", schedule.name().data());
+ m_selectedSchedule = schedule;
+ slotUpdateActions();
+ emit scheduleSelected(m_selectedSchedule);
+}
+
+void KMyMoney2App::slotDataChanged(void)
+{
+ // As this method is called everytime the MyMoneyFile instance
+ // notifies a modification, it's the perfect place to start the timer if needed
+ if (m_autoSaveEnabled && !m_autoSaveTimer->isActive()) {
+ m_autoSaveTimer->start(m_autoSavePeriod * 60 * 1000, true); //miliseconds
+ }
+ updateCaption();
+}
+
+void KMyMoney2App::slotCurrencyDialog(void)
+{
+ KCurrencyEditDlg dlg(this, "Currency Editor");
+ connect(&dlg, SIGNAL(selectObject(const MyMoneySecurity&)), this, SLOT(slotSelectCurrency(const MyMoneySecurity&)));
+ connect(&dlg, SIGNAL(openContextMenu(const MyMoneySecurity&)), this, SLOT(slotShowCurrencyContextMenu()));
+ connect(this, SIGNAL(currencyRename()), &dlg, SLOT(slotStartRename()));
+ connect(&dlg, SIGNAL(renameCurrency(QListViewItem*, int, const QString&)), this, SLOT(slotCurrencyRename(QListViewItem*,int,const QString&)));
+ connect(this, SIGNAL(currencyCreated(const QString&)), &dlg, SLOT(slotSelectCurrency(const QString&)));
+ connect(&dlg, SIGNAL(selectBaseCurrency(const MyMoneySecurity&)), this, SLOT(slotCurrencySetBase()));
+
+ dlg.exec();
+
+ slotSelectCurrency(MyMoneySecurity());
+}
+
+void KMyMoney2App::slotPriceDialog(void)
+{
+ KMyMoneyPriceDlg dlg(this, "Price Editor");
+ dlg.exec();
+}
+
+void KMyMoney2App::slotFileConsitencyCheck(void)
+{
+ KMSTATUS(i18n("Running consistency check..."));
+
+ QStringList msg;
+ MyMoneyFileTransaction ft;
+ try {
+ msg = MyMoneyFile::instance()->consistencyCheck();
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ msg = i18n("Consistency check failed: %1").arg(e->what());
+ delete e;
+ }
+
+ KMessageBox::warningContinueCancelList(0, "Result", msg, i18n("Consistency check result"));
+
+ updateCaption();
+}
+
+void KMyMoney2App::slotCheckSchedules(void)
+{
+ if(KMyMoneyGlobalSettings::checkSchedule() == true) {
+
+ KMSTATUS(i18n("Checking for overdue scheduled transactions..."));
+ MyMoneyFile *file = MyMoneyFile::instance();
+ QDate checkDate = QDate::currentDate().addDays(KMyMoneyGlobalSettings::checkSchedulePreview());
+
+ QValueList<MyMoneySchedule> scheduleList = file->scheduleList();
+ QValueList<MyMoneySchedule>::Iterator it;
+
+ KMyMoneyUtils::EnterScheduleResultCodeE rc = KMyMoneyUtils::Enter;
+ for (it=scheduleList.begin(); (it != scheduleList.end()) && (rc != KMyMoneyUtils::Cancel); ++it) {
+ // Get the copy in the file because it might be modified by commitTransaction
+ MyMoneySchedule schedule = file->schedule((*it).id());
+
+ if(schedule.autoEnter()) {
+ try {
+ while(!schedule.isFinished() && (schedule.nextDueDate() <= checkDate)
+ && rc != KMyMoneyUtils::Ignore
+ && rc != KMyMoneyUtils::Cancel) {
+ rc = enterSchedule(schedule, true, true);
+ schedule = file->schedule((*it).id()); // get a copy of the modified schedule
+ }
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+ }
+ }
+ updateCaption();
+ }
+}
+
+void KMyMoney2App::writeLastUsedDir(const QString& directory)
+{
+ //get global config object for our app.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig)
+ {
+ kconfig->setGroup("General Options");
+
+ //write path entry, no error handling since its void.
+ kconfig->writePathEntry("LastUsedDirectory", directory);
+ }
+}
+
+void KMyMoney2App::writeLastUsedFile(const QString& fileName)
+{
+ //get global config object for our app.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig)
+ {
+ kconfig->setGroup("General Options");
+
+ // write path entry, no error handling since its void.
+ // use a standard string, as fileName could contain a protocol
+ // e.g. file:/home/thb/....
+ kconfig->writeEntry("LastUsedFile", fileName);
+ }
+}
+
+QString KMyMoney2App::readLastUsedDir(void) const
+{
+ QString str;
+
+ //get global config object for our app.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig)
+ {
+ kconfig->setGroup("General Options");
+
+ //read path entry. Second parameter is the default if the setting is not found, which will be the default document path.
+ str = kconfig->readPathEntry("LastUsedDirectory", KGlobalSettings::documentPath());
+ // if the path stored is empty, we use the default nevertheless
+ if(str.isEmpty())
+ str = KGlobalSettings::documentPath();
+ }
+
+ return str;
+}
+
+QString KMyMoney2App::readLastUsedFile(void) const
+{
+ QString str;
+
+ // get global config object for our app.
+ KConfig *kconfig = KGlobal::config();
+ if(kconfig)
+ {
+ kconfig->setGroup("General Options");
+
+ // read filename entry.
+ str = kconfig->readEntry("LastUsedFile", "");
+ }
+
+ return str;
+}
+
+const QString KMyMoney2App::filename(void) const
+{
+ return m_fileName.url();
+}
+
+const QValueList<QCString> KMyMoney2App::instanceList(void) const
+{
+ QValueList<QCString> list;
+ QValueList<QCString> apps = kapp->dcopClient()->registeredApplications();
+ QValueList<QCString>::ConstIterator it;
+
+ for(it = apps.begin(); it != apps.end(); ++it) {
+ // skip over myself
+ if((*it) == kapp->dcopClient()->appId())
+ continue;
+ if((*it).find("kmymoney-") == 0) {
+ list += (*it);
+ }
+ }
+ return list;
+}
+
+void KMyMoney2App::slotEquityPriceUpdate(void)
+{
+ KEquityPriceUpdateDlg dlg(this);
+ if(dlg.exec() == QDialog::Accepted)
+ dlg.storePrices();
+}
+
+void KMyMoney2App::webConnect(const QString& url, const QCString& asn_id)
+{
+ //
+ // Web connect attempts to go through the known importers and see if the file
+ // can be importing using that method. If so, it will import it using that
+ // plugin
+ //
+
+ // Bring this window to the forefront. This method was suggested by
+ // Lubos Lunak <l.lunak@suse.cz> of the KDE core development team.
+ KStartupInfo::setNewStartupId(this, asn_id);
+
+ // Make sure we have an open file
+ if ( ! myMoneyView->fileOpen() &&
+ KMessageBox::warningContinueCancel(kmymoney2, i18n("You must first select a KMyMoney file before you can import a statement.")) == KMessageBox::Continue )
+ kmymoney2->slotFileOpen();
+
+ // only continue if the user really did open a file.
+ if ( myMoneyView->fileOpen() )
+ {
+ KMSTATUS(i18n("Importing a statement via Web Connect"));
+
+ // remove the statement files
+ d->unlinkStatementXML();
+
+ QMap<QString,KMyMoneyPlugin::ImporterPlugin*>::const_iterator it_plugin = m_importerPlugins.begin();
+ while ( it_plugin != m_importerPlugins.end() )
+ {
+ if ( (*it_plugin)->isMyFormat(url) )
+ {
+ QValueList<MyMoneyStatement> statements;
+ if (!(*it_plugin)->import(url) )
+ {
+ KMessageBox::error( this, i18n("Unable to import %1 using %2 plugin. The plugin returned the following error: %3").arg(url,(*it_plugin)->formatName(),(*it_plugin)->lastError()), i18n("Importing error"));
+ }
+
+ break;
+ }
+ ++it_plugin;
+ }
+
+ // If we did not find a match, try importing it as a KMM statement file,
+ // which is really just for testing. the statement file is not exposed
+ // to users.
+ if ( it_plugin == m_importerPlugins.end() )
+ if ( MyMoneyStatement::isStatementFile( url ) )
+ slotStatementImport(url);
+
+ }
+}
+
+void KMyMoney2App::slotEnableMessages(void)
+{
+ KMessageBox::enableAllMessages();
+ KMessageBox::information(this, i18n("All messages have been enabled."), i18n("All messages"));
+}
+
+void KMyMoney2App::slotSecurityEditor(void)
+{
+ KSecurityListEditor dlg(this, "KSecurityListEditor");
+ dlg.exec();
+}
+
+void KMyMoney2App::createInterfaces(void)
+{
+ // Sets up the plugin interface, and load the plugins
+ m_pluginInterface = new QObject( this, "_pluginInterface" );
+
+ new KMyMoneyPlugin::KMMViewInterface(this, myMoneyView, m_pluginInterface, "view interface");
+ new KMyMoneyPlugin::KMMStatementInterface(this, m_pluginInterface, "statement interface");
+ new KMyMoneyPlugin::KMMImportInterface(this, m_pluginInterface, "import interface");
+}
+
+void KMyMoney2App::loadPlugins(void)
+{
+ d->m_pluginLoader = new KMyMoneyPlugin::PluginLoader(this);
+
+ connect( d->m_pluginLoader, SIGNAL( plug(KPluginInfo*) ), this, SLOT( slotPluginPlug(KPluginInfo*) ) );
+ connect( d->m_pluginLoader, SIGNAL( unplug(KPluginInfo*) ), this, SLOT( slotPluginUnplug(KPluginInfo*) ) );
+
+ d->m_pluginLoader->loadPlugins();
+}
+
+void KMyMoney2App::slotPluginPlug(KPluginInfo* info)
+{
+ KMyMoneyPlugin::Plugin* plugin = d->m_pluginLoader->getPluginFromInfo(info);
+
+ // check for online plugin
+ KMyMoneyPlugin::OnlinePlugin* op = dynamic_cast<KMyMoneyPlugin::OnlinePlugin *>(plugin);
+ // check for importer plugin
+ KMyMoneyPlugin::ImporterPlugin* ip = dynamic_cast<KMyMoneyPlugin::ImporterPlugin *>(plugin);
+
+ // plug the plugin
+ guiFactory()->addClient(plugin);
+
+ if(op)
+ m_onlinePlugins[plugin->name()] = op;
+
+ if(ip)
+ m_importerPlugins[plugin->name()] = ip;
+
+ slotUpdateActions();
+}
+
+void KMyMoney2App::slotPluginUnplug(KPluginInfo* info)
+{
+ KMyMoneyPlugin::Plugin* plugin = d->m_pluginLoader->getPluginFromInfo(info);
+
+ // check for online plugin
+ KMyMoneyPlugin::OnlinePlugin* op = dynamic_cast<KMyMoneyPlugin::OnlinePlugin *>(plugin);
+ // check for importer plugin
+ KMyMoneyPlugin::ImporterPlugin* ip = dynamic_cast<KMyMoneyPlugin::ImporterPlugin *>(plugin);
+
+ // unplug the plugin
+ guiFactory()->removeClient(plugin);
+
+ if(op)
+ m_onlinePlugins.erase(plugin->name());
+
+ if(ip)
+ m_importerPlugins.erase(plugin->name());
+
+ slotUpdateActions();
+}
+
+void KMyMoney2App::slotAutoSave(void)
+{
+ if(!m_inAutoSaving) {
+ m_inAutoSaving = true;
+ KMSTATUS(i18n("Auto saving..."));
+
+ //calls slotFileSave if needed, and restart the timer
+ //it the file is not saved, reinitializes the countdown.
+ if (myMoneyView->dirty() && m_autoSaveEnabled) {
+ if (!slotFileSave() && m_autoSavePeriod > 0) {
+ m_autoSaveTimer->start(m_autoSavePeriod * 60 * 1000, true);
+ }
+ }
+
+ m_inAutoSaving = false;
+ }
+}
+
+void KMyMoney2App::slotDateChanged(void)
+{
+ QDateTime dt = QDateTime::currentDateTime();
+ QDateTime nextDay( QDate(dt.date().addDays(1)), QTime(0, 0, 0) );
+
+ QTimer::singleShot(dt.secsTo(nextDay)*1000, this, SLOT(slotDateChanged()));
+ myMoneyView->slotRefreshViews();
+}
+
+const MyMoneyAccount& KMyMoney2App::account(const QString& key, const QString& value) const
+{
+ QValueList<MyMoneyAccount> list;
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ MyMoneyFile::instance()->accountList(list);
+ QValueList<MyMoneyAccount> accList;
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ const QString& id = (*it_a).onlineBankingSettings().value(key);
+ if(id.contains(value)) {
+ accList << MyMoneyFile::instance()->account((*it_a).id());
+ }
+ if(id == value) {
+ return MyMoneyFile::instance()->account((*it_a).id());
+ }
+ }
+ // if we did not find an exact match of the value, we take the one that partially
+ // matched, but only if not more than one matched partially.
+ if(accList.count() == 1) {
+ return accList[0];
+ }
+
+ // return reference to empty element
+ return MyMoneyFile::instance()->account(QString());
+}
+
+void KMyMoney2App::setAccountOnlineParameters(const MyMoneyAccount& _acc, const MyMoneyKeyValueContainer& kvps)
+{
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(_acc.id());
+ acc.setOnlineBankingSettings(kvps);
+ MyMoneyFile::instance()->modifyAccount(acc);
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to setup online parameters for account ''%1'").arg(_acc.name()), e->what() );
+ delete e;
+ }
+}
+
+void KMyMoney2App::slotAccountUnmapOnline(void)
+{
+ // no account selected
+ if(m_selectedAccount.id().isEmpty())
+ return;
+
+ // not a mapped account
+ if(m_selectedAccount.onlineBankingSettings().value("provider").isEmpty())
+ return;
+
+ if(KMessageBox::warningYesNo(this, QString("<qt>%1</qt>").arg(i18n("Do you really want to remove the mapping of account <b>%1</b> to an online account? Depending on the details of the online banking method used, this action cannot be reverted.").arg(m_selectedAccount.name())), i18n("Remove mapping to online account")) == KMessageBox::Yes) {
+ MyMoneyFileTransaction ft;
+ try {
+ m_selectedAccount.setOnlineBankingSettings(MyMoneyKeyValueContainer());
+ // delete the kvp that is used in MyMoneyStatementReader too
+ // we should really get rid of it, but since I don't know what it
+ // is good for, I'll keep it around. (ipwizard)
+ m_selectedAccount.deletePair("StatementKey");
+ MyMoneyFile::instance()->modifyAccount(m_selectedAccount);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::error(this, i18n("Unable to unmap account from online account: %1").arg(e->what()));
+ delete e;
+ }
+ }
+}
+
+void KMyMoney2App::slotAccountMapOnline(void)
+{
+ // no account selected
+ if(m_selectedAccount.id().isEmpty())
+ return;
+
+ // already an account mapped
+ if(!m_selectedAccount.onlineBankingSettings().value("provider").isEmpty())
+ return;
+
+ // check if user tries to map a brokerageAccount
+ if(m_selectedAccount.name().contains(i18n(" (Brokerage)"))) {
+ if(KMessageBox::warningContinueCancel(this, i18n("You try to map a brokerage account to an online account. This is usually not advisable. In general, the investment account should be mapped to the online account. Please cancel if you intended to map the investment account, continue otherwise"), i18n("Mapping brokerage account")) == KMessageBox::Cancel) {
+ return;
+ }
+ }
+
+ // if we have more than one provider display a dialog to select the current providers
+ KPluginDlg dlg(this);
+ dlg.setCaption(i18n("Select online banking plugin"));
+ dlg.closeButton->hide();
+ QString provider;
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin*>::const_iterator it_p;
+ switch(m_onlinePlugins.count()) {
+ case 0:
+ break;
+ case 1:
+ provider = m_onlinePlugins.begin().key();
+ break;
+ default:
+ for(it_p = m_onlinePlugins.begin(); it_p != m_onlinePlugins.end(); ++it_p) {
+ QStringList protocolList;
+ (*it_p)->protocols(protocolList);
+ new KListViewItem(dlg.m_listView, it_p.key(), "Loaded", protocolList.join(", "));
+ }
+ if(dlg.exec() == QDialog::Accepted) {
+ if(dlg.m_listView->selectedItem()) {
+ provider = dlg.m_listView->selectedItem()->text(0);
+ }
+ }
+ break;
+ }
+
+ if(provider.isEmpty())
+ return;
+
+ // find the provider
+ it_p = m_onlinePlugins.find(provider);
+ if(it_p != m_onlinePlugins.end()) {
+ // plugin found, call it
+ MyMoneyKeyValueContainer settings;
+ if((*it_p)->mapAccount(m_selectedAccount, settings)) {
+ settings["provider"] = provider;
+ MyMoneyAccount acc(m_selectedAccount);
+ acc.setOnlineBankingSettings(settings);
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifyAccount(acc);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ KMessageBox::error(this, i18n("Unable to map account to online account: %1").arg(e->what()));
+ delete e;
+ }
+ }
+ }
+}
+
+void KMyMoney2App::slotAccountUpdateOnlineAll(void)
+{
+ QValueList<MyMoneyAccount> accList;
+ MyMoneyFile::instance()->accountList(accList);
+ QValueList<MyMoneyAccount>::iterator it_a;
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin*>::const_iterator it_p;
+ d->m_statementResults.clear();
+ d->m_collectingStatements = true;
+
+ // remove all those from the list, that don't have a 'provider' or the
+ // provider is not currently present
+ for(it_a = accList.begin(); it_a != accList.end();) {
+ if ((*it_a).onlineBankingSettings().value("provider").isEmpty()
+ || m_onlinePlugins.find((*it_a).onlineBankingSettings().value("provider")) == m_onlinePlugins.end() ) {
+ it_a = accList.remove(it_a);
+ } else
+ ++it_a;
+ }
+
+ // now work on the remaining list of accounts
+ int cnt = accList.count() - 1;
+ for(it_a = accList.begin(); it_a != accList.end(); ++it_a) {
+ it_p = m_onlinePlugins.find((*it_a).onlineBankingSettings().value("provider"));
+ (*it_p)->updateAccount(*it_a, cnt != 0);
+ --cnt;
+ }
+
+ d->m_collectingStatements = false;
+ if(!d->m_statementResults.isEmpty())
+ KMessageBox::informationList(this, i18n("The statements have been processed with the following results:"), d->m_statementResults, i18n("Statement stats"));
+}
+
+void KMyMoney2App::slotAccountUpdateOnline(void)
+{
+ // no account selected
+ if(m_selectedAccount.id().isEmpty())
+ return;
+
+ // no online account mapped
+ if(m_selectedAccount.onlineBankingSettings().value("provider").isEmpty())
+ return;
+
+ // find the provider
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin*>::const_iterator it_p;
+ it_p = m_onlinePlugins.find(m_selectedAccount.onlineBankingSettings().value("provider"));
+ if(it_p != m_onlinePlugins.end()) {
+ // plugin found, call it
+ d->m_collectingStatements = true;
+ d->m_statementResults.clear();
+ (*it_p)->updateAccount(m_selectedAccount);
+ d->m_collectingStatements = false;
+ if(!d->m_statementResults.isEmpty())
+ KMessageBox::informationList(this, i18n("The statements have been processed with the following results:"), d->m_statementResults, i18n("Statement stats"));
+ }
+}
+
+KMStatus::KMStatus (const QString &text)
+{
+ m_prevText = kmymoney2->slotStatusMsg(text);
+}
+
+KMStatus::~KMStatus()
+{
+ kmymoney2->slotStatusMsg(m_prevText);
+}
+
+void KMyMoney2App::Private::unlinkStatementXML(void)
+{
+ QDir d("/home/thb", "kmm-statement*");
+ for(int i=0; i < d.count(); ++i) {
+ qDebug("Remove %s", d[i].data());
+ d.remove(QString("/home/thb/%1").arg(d[i]));
+ }
+ statementXMLindex = 0;
+}
+
+#include "kmymoney2.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
+
diff --git a/kmymoney2/kmymoney2.desktop b/kmymoney2/kmymoney2.desktop
new file mode 100644
index 0000000..aac7a69
--- /dev/null
+++ b/kmymoney2/kmymoney2.desktop
@@ -0,0 +1,23 @@
+[Desktop Entry]
+Name=KMyMoney
+GenericName=Personal Finance Manager
+GenericName[de]=Persönlicher Finanzassistent
+GenericName[fr]=Gestionnaire de finances personnelles
+GenericName[tr]=Kişisel Finans Yöneticisi
+GenericName[ro]=Gestionar de finanțe personale
+GenericName[ru]=Учёт финансов
+GenericName[zh_CN]=个人财务管理软件
+Exec=kmymoney2 %u
+Comment=Personal Finance Manager
+Comment[de]=Persönlicher Finanzassistent
+Comment[fr]=Gestionnaire de finances personnelles
+Comment[tr]=Kişisel Finans Yöneticisi
+Comment[ro]=Gestionar de finanțe personale
+Comment[ru]=Учёт финансов
+Comment[zh_CN]=个人财务管理软件
+MimeType=application/x-kmymoney;application/vnd.intu.qfx;application/x-ofx;
+Type=Application
+DocPath=kmymoney2/index.html
+Icon=kmymoney2
+ServiceTypes=
+Categories=Office;Finance;
diff --git a/kmymoney2/kmymoney2.h b/kmymoney2/kmymoney2.h
new file mode 100644
index 0000000..77d5c86
--- /dev/null
+++ b/kmymoney2/kmymoney2.h
@@ -0,0 +1,1306 @@
+/***************************************************************************
+ kmymoney2.h
+ -------------------
+ copyright : (C) 2000-2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KMYMONEY2_H
+#define KMYMONEY2_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qapplication.h>
+class QTimer;
+class QLabel;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <kprocess.h>
+#include <kurl.h>
+#include <kfile.h>
+#include <dcopobject.h>
+class KComboBox;
+class KPushButton;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneybudget.h>
+#include <kmymoney/kmymoneyplugin.h>
+#include <kmymoney/register.h>
+#include <kmymoney/kmymoneyutils.h>
+
+class QSignalMapper;
+class KProgress;
+class KMyMoneyView;
+class MyMoneyQifReader;
+class MyMoneyStatementReader;
+class MyMoneyStatement;
+class IMyMoneyStorage;
+class KFindTransactionDlg;
+class TransactionEditor;
+class KEndingBalanceDlg;
+class KPluginInfo;
+
+namespace KMyMoneyPlugin { class ImporterPlugin; }
+
+/*! \mainpage KMyMoney Main Page for API documentation.
+ *
+ * \section intro Introduction
+ *
+ * This is the API documentation for KMyMoney. It should be used as a reference
+ * for KMyMoney developers and users who wish to see how KMyMoney works. This
+ * documentation will be kept up-to-date as development progresses and should be
+ * read for new features that have been developed in KMyMoney.
+ *
+ * The latest version of this document is available from the project's web-site
+ * at http://kmymoney2.sourceforge.net/ and is generated daily by doxygen reading
+ * the header files found in the CVS main branch.
+ */
+
+/**
+ * The base class for KMyMoney application windows. It sets up the main
+ * window and reads the config file as well as providing a menubar, toolbar
+ * and statusbar.
+ *
+ * @see KMyMoneyView
+ *
+ * @author Michael Edwardes 2000-2001
+ * @author Thomas Baumgart 2006-2008
+ *
+ * @short Main application class.
+ */
+class KMyMoney2App : public KMainWindow, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+
+protected slots:
+ void slotFileSaveAsFilterChanged(const QString& filter);
+
+ /**
+ * This slot is intended to be used as part of auto saving. This is used when the
+ * QTimer emits the timeout signal and simply checks that the file is dirty (has
+ * received modifications to it's contents), and call the apropriate method to
+ * save the file. Furthermore, re-starts the timer (possibly not needed).
+ * @author mvillarino 2005
+ * @see KMyMoney2App::slotDataChanged()
+ */
+ void slotAutoSave(void);
+
+ /**
+ * This slot re-enables all message for which the "Don't show again"
+ * option had been selected.
+ */
+ void slotEnableMessages(void);
+
+ /**
+ * Called when the user asks for file information.
+ */
+ void slotFileFileInfo(void);
+
+ void slotPerformanceTest(void);
+
+ /**
+ * Debugging only: turn on/off traces
+ */
+ void slotToggleTraces(void);
+
+ /**
+ * Debugging only: turn on/off timers
+ */
+ void slotToggleTimers(void);
+
+ /**
+ * Called when the user asks for the personal information.
+ */
+ void slotFileViewPersonal(void);
+
+ /**
+ * Called when the user wishes to import tab delimeted transactions
+ * into the current account. An account must be open for this to
+ * work. Calls KMyMoneyView::slotAccountImportAscii.
+ *
+ * @see MyMoneyAccount
+ */
+ void slotQifImport(void);
+
+ /**
+ * Called when a QIF import is finished.
+ */
+ void slotQifImportFinished(void);
+
+ /**
+ * Opens a file selector dialog for the user to choose an existing OFX
+ * file from the file system to be imported. This slot is expected to
+ * be called from the UI.
+ */
+ void slotGncImport(void);
+
+ /**
+ * Open a dialog with a chart of the balance for the currently selected
+ * account (m_selectedAccount). Return once the dialog is closed. Don't do
+ * anything if no account is selected or charts are not available.
+ */
+ void slotAccountChart(void);
+
+ /**
+ * Opens a file selector dialog for the user to choose an existing KMM
+ * statement file from the file system to be imported. This is for testing
+ * only. KMM statement files are not designed to be exposed to the user.
+ */
+ void slotStatementImport(void);
+
+ void slotLoadAccountTemplates(void);
+ void slotSaveAccountTemplates(void);
+
+ /**
+ * Called when the user wishes to export some transaction to a
+ * QIF formatted file. An account must be open for this to work.
+ * Uses MyMoneyQifWriter() for the actual output.
+ */
+ void slotQifExport(void);
+
+ /**
+ * Open up the application wide settings dialog.
+ *
+ * @see KSettingsDlg
+ */
+ void slotSettings(void);
+
+ /** No descriptions */
+ void slotFileBackup(void);
+
+ void slotShowTipOfTheDay(void);
+
+ void slotQifProfileEditor(void);
+
+ void slotShowPreviousView(void);
+
+ void slotShowNextView(void);
+
+ void slotSecurityEditor(void);
+
+ /**
+ * Brings up a dialog to let the user search for specific transaction(s). It then
+ * opens a results window to display those transactions.
+ */
+ void slotFindTransaction(void);
+
+ /**
+ * Destroys a possibly open the search dialog
+ */
+ void slotCloseSearchDialog(void);
+
+ /**
+ * Preloads the input dialog with the data of the current
+ * selected institution and brings up the input dialog
+ * and saves the information entered.
+ */
+ void slotInstitutionEdit(const MyMoneyObject& obj = MyMoneyInstitution());
+
+ /**
+ * Deletes the current selected institution.
+ */
+ void slotInstitutionDelete(void);
+
+ /**
+ * Brings up the new category editor and saves the information.
+ * The dialog will be preset with the name. The parent defaults to
+ * MyMoneyFile::expense()
+ *
+ * @param name Name of the account to be created. Could include a full hierarchy
+ * @param id reference to storage which will receive the id after successful creation
+ *
+ * @note Typically, this slot can be connected to the
+ * StdTransactionEditor::createCategory(const QString&, QString&) or
+ * KMyMoneyCombo::createItem(const QString&, QString&) signal.
+ */
+ void slotCategoryNew(const QString& name, QString& id);
+
+ /**
+ * Calls the print logic for the current view
+ */
+ void slotPrintView(void);
+
+ /**
+ * Create a new investment
+ */
+ void slotInvestmentNew(void);
+
+ /**
+ * Create a new investment in a given @p parent investment account
+ */
+ void slotInvestmentNew(MyMoneyAccount& account, const MyMoneyAccount& parent);
+
+ /**
+ * This slot opens the investment editor to edit the currently
+ * selected investment if possible
+ */
+ void slotInvestmentEdit(void);
+
+ /**
+ * Deletes the current selected investment.
+ */
+ void slotInvestmentDelete(void);
+
+ /**
+ * Performs online update for currently selected investment
+ */
+ void slotOnlinePriceUpdate(void);
+
+ /**
+ * Performs manual update for currently selected investment
+ */
+ void slotManualPriceUpdate(void);
+
+ /**
+ * Call this slot, if any configuration parameter has changed
+ */
+ void slotUpdateConfiguration(void);
+
+ /**
+ */
+ void slotPayeeNew(const QString& newnameBase, QString& id);
+ void slotPayeeNew(void);
+
+ /**
+ */
+ void slotPayeeDelete(void);
+
+ /**
+ */
+ void slotBudgetNew(void);
+
+ /**
+ */
+ void slotBudgetDelete(void);
+
+ /**
+ */
+ void slotBudgetCopy(void);
+
+ /**
+ */
+ void slotBudgetChangeYear(void);
+
+ /**
+ */
+ void slotBudgetForecast(void);
+
+ /**
+ */
+ void slotCurrencyNew(void);
+
+ /**
+ */
+ void slotCurrencyRename(QListViewItem* item, int, const QString& txt);
+
+ /**
+ */
+ void slotCurrencyDelete(void);
+
+ /**
+ */
+ void slotCurrencySetBase(void);
+
+ /**
+ * This slot is used to start new features during the development cycle
+ */
+ void slotNewFeature(void);
+
+ /**
+ */
+ void slotTransactionsNew(void);
+
+ /**
+ */
+ void slotTransactionsEdit(void);
+
+ /**
+ */
+ void slotTransactionsEditSplits(void);
+
+ /**
+ */
+ void slotTransactionsDelete(void);
+
+ /**
+ */
+ void slotTransactionsEnter(void);
+
+ /**
+ */
+ void slotTransactionsCancel(void);
+
+ /**
+ */
+ void slotTransactionsCancelOrEnter(bool& okToSelect);
+
+ /**
+ */
+ void slotTransactionDuplicate(void);
+
+ /**
+ */
+ void slotToggleReconciliationFlag(void);
+
+ /**
+ */
+ void slotMarkTransactionCleared(void);
+
+ /**
+ */
+ void slotMarkTransactionReconciled(void);
+
+ /**
+ */
+ void slotMarkTransactionNotReconciled(void);
+
+ /**
+ */
+ void slotTransactionGotoAccount(void);
+
+ /**
+ */
+ void slotTransactionGotoPayee(void);
+
+ /**
+ */
+ void slotTransactionCreateSchedule(void);
+
+ /**
+ */
+ void slotTransactionAssignNumber(void);
+
+ /**
+ */
+ void slotTransactionCombine(void);
+
+ /**
+ * Accept the selected transactions that are marked as 'imported' and remove the flag
+ */
+ void slotTransactionsAccept(void);
+
+ /**
+ * This slot triggers an update of all views and restarts
+ * a single shot timer to call itself again at beginning of
+ * the next day.
+ */
+ void slotDateChanged(void);
+
+ /**
+ * This slot will be called when the engine data changed
+ * and the application object needs to update it's state.
+ */
+ void slotDataChanged(void);
+
+ void slotMoveToAccount(const QString& id);
+
+ void slotUpdateMoveToAccountMenu(void);
+
+ /**
+ * This slot collects information for a new scheduled transaction
+ * based on transaction @a t and @a occurence and saves it in the engine.
+ */
+ void slotScheduleNew(const MyMoneyTransaction& t, MyMoneySchedule::occurenceE occurence = MyMoneySchedule::OCCUR_MONTHLY);
+
+ /**
+ */
+ void slotScheduleDuplicate(void);
+
+ void slotKDELanguageSettings(void);
+
+ void slotAccountMapOnline(void);
+ void slotAccountUnmapOnline(void);
+ void slotAccountUpdateOnline(void);
+ void slotAccountUpdateOnlineAll(void);
+
+ void slotManageGpgKeys(void);
+ void slotKeySelected(int idx);
+
+public:
+ /**
+ * This method checks if there is at least one asset or liability account
+ * in the current storage object. If not, it starts the new account wizard.
+ */
+ void createInitialAccount(void);
+
+ /**
+ * This method returns the last URL used or an empty URL
+ * depending on the option setting if the last file should
+ * be opened during startup or the open file dialog should
+ * be displayed.
+ *
+ * @return URL of last opened file or empty if the program
+ * should start with the open file dialog
+ */
+ const KURL lastOpenedURL(void);
+
+ /**
+ * construtor of KMyMoney2App, calls all init functions to create the application.
+ */
+ KMyMoney2App(QWidget* parent=0, const char* name=0);
+
+ /**
+ * Destructor
+ */
+ ~KMyMoney2App();
+
+ /** Init wizard dialog */
+ bool initWizard(void);
+
+ static void progressCallback(int current, int total, const QString&);
+
+ void writeLastUsedDir(const QString& directory);
+ QString readLastUsedDir(void) const;
+ void writeLastUsedFile(const QString& fileName);
+ QString readLastUsedFile(void) const;
+
+ /**
+ * Returns whether there is an importer available that can handle this file
+ */
+ bool isImportableFile( const KURL& url );
+
+ /**
+ * This method is used to update the caption of the application window.
+ * It set's the caption to "filename [modified] - KMyMoney".
+ *
+ * @param skipActions if true, the actions will not be updated. This
+ * is usually onyl required by some early calls when
+ * these widgets are not yet created (the default is false).
+ */
+ void updateCaption(bool skipActions = false);
+
+ /**
+ * This method returns a list of all 'other' dcop registered kmymoney processes.
+ * It's a subset of the return of DCOPclient()->registeredApplications().
+ *
+ * @retval QStringList of process ids
+ */
+ const QValueList<QCString> instanceList(void) const;
+
+ /**
+ * Dump a list of the names of all defined KActions to stdout.
+ */
+ void dumpActions(void) const;
+
+ /**
+ * Popup the context menu with the respective @p containerName.
+ * Valid container names are defined in kmymoney2ui.rc
+ */
+ void showContextMenu(const QString& containerName);
+
+ /**
+ * This method opens the category editor with the data found in @a account. The
+ * parent account is preset to @a parent but can be modified. If the user
+ * acknowledges, the category is created.
+ */
+ void createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent);
+
+ /**
+ * This method returns the account for a given @a key - @a value pair.
+ * If the account is not found in the list of accounts, MyMoneyAccount()
+ * is returned.
+ */
+ const MyMoneyAccount& account(const QString& key, const QString& value) const;
+
+ /**
+ * This method set the online parameters stored in @a kvps with the
+ * account referenced by @a acc.
+ */
+ void setAccountOnlineParameters(const MyMoneyAccount& acc, const MyMoneyKeyValueContainer& kvps);
+
+ KURL selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode);
+
+ const MyMoneyAccount& findAccount(const MyMoneyAccount& acc, const MyMoneyAccount& parent) const;
+
+ void createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal);
+
+k_dcop:
+ // Note: Don't use e.g. filename(void) but use filename() because
+ // otherwise the kidl compiler produces uncompilable results.
+ const QString filename() const;
+
+ void webConnect(const QString&, const QCString& asn_id);
+
+ /**
+ * Checks if the file with the @a url already exists. If so,
+ * the user is asked if he/she wants to override the file.
+ * If the user's answer is negative, @p false will be returned.
+ * @p true will be returned in all other cases.
+ */
+ bool okToWriteFile(const KURL& url);
+
+ // QValueList<MyMoneyAccount> accountList() const;
+
+protected:
+ /** save general Options like all bar positions and status as well as the geometry and the recent file list to the configuration
+ * file
+ */
+ void saveOptions(void);
+
+ /**
+ * Creates the interfaces necessary for the plugins to work. Therefore,
+ * this method must be called prior to loadPlugins().
+ */
+ void createInterfaces(void);
+
+ /**
+ * load all available plugins. Make sure you have called createInterfaces()
+ * before you call this one.
+ */
+ void loadPlugins(void);
+
+ /** read general Options again and initialize all variables like the recent file list
+ */
+ void readOptions(void);
+
+ /** initializes the KActions of the application */
+ void initActions(void);
+
+ /** initializes the dynamic menus (account selectors) */
+ void initDynamicMenus(void);
+
+ /** sets up the statusbar for the main window by initialzing a statuslabel.
+ */
+ void initStatusBar(void);
+
+ /** queryClose is called by KTMainWindow on each closeEvent of a window. Against the
+ * default implementation (only returns true), this calles saveModified() on the document object to ask if the document shall
+ * be saved if Modified; on cancel the closeEvent is rejected.
+ * @see KTMainWindow#queryClose
+ * @see KTMainWindow#closeEvent
+ */
+ virtual bool queryClose(void);
+
+ /** queryExit is called by KTMainWindow when the last window of the application is going to be closed during the closeEvent().
+ * Against the default implementation that just returns true, this calls saveOptions() to save the settings of the last window's
+ * properties.
+ * @see KTMainWindow#queryExit
+ * @see KTMainWindow#closeEvent
+ */
+ virtual bool queryExit(void);
+
+ void slotCheckSchedules(void);
+
+ virtual void resizeEvent(QResizeEvent*);
+
+ void createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount);
+
+ /**
+ * This method checks, if an account can be closed or not. An account
+ * can be closed if:
+ *
+ * - the balance is zero and
+ * - all children are already closed and
+ * - there is no unfinished schedule referencing the account
+ *
+ * @param acc reference to MyMoneyAccount object in question
+ * @retval true account can be closed
+ * @retval false account cannot be closed
+ */
+ bool canCloseAccount(const MyMoneyAccount& acc) const;
+
+ /**
+ * Check if a list contains a payee with a given id
+ *
+ * @param list const reference to value list
+ * @param id const reference to id
+ *
+ * @retval true object has been found
+ * @retval false object is not in list
+ */
+ bool payeeInList(const QValueList<MyMoneyPayee>& list, const QString& id) const;
+
+ /**
+ * Mark the selected transactions as provided by @a flag. If
+ * flag is @a MyMoneySplit::Unknown, the future state depends
+ * on the current stat of the split's flag accoring to the
+ * following table:
+ *
+ * - NotReconciled --> Cleared
+ * - Cleared --> Reconciled
+ * - Reconciled --> NotReconciled
+ */
+ void markTransaction(MyMoneySplit::reconcileFlagE flag);
+
+ /**
+ * This method allows to enter the next scheduled transaction of
+ * the given schedule @a s. In case @a extendedKeys is @a true,
+ * the given schedule can also be skipped or ignored.
+ * If @a autoEnter is @a true and the schedule does not contain
+ * an estimated value, the schedule is entered as is without further
+ * interaction with the user. In all other cases, the user will
+ * be presented a dialog and allowed to adjust the values for this
+ * instance of the schedule.
+ *
+ * The transaction will be created and entered into the ledger
+ * and the schedule updated.
+ */
+ KMyMoneyUtils::EnterScheduleResultCodeE enterSchedule(MyMoneySchedule& s, bool autoEnter = false, bool extendedKeys = false);
+
+ /**
+ * Creates a new institution entry in the MyMoneyFile engine
+ *
+ * @param institution MyMoneyInstitution object containing the data of
+ * the institution to be created.
+ */
+ void createInstitution(MyMoneyInstitution& institution);
+
+ /**
+ * This method unmatches the currently selected transactions
+ */
+ void transactionUnmatch(void);
+
+ /**
+ * This method matches the currently selected transactions
+ */
+ void transactionMatch(void);
+
+public slots:
+ void slotFileInfoDialog(void);
+
+ /** */
+ void slotFileNew(void);
+
+ /** Open a new window */
+ void slotFileNewWindow(void);
+
+ /** open a file and load it into the document*/
+ void slotFileOpen(void);
+
+ /** opens a file from the recent files menu */
+
+ void slotFileOpenRecent(const KURL& url);
+
+ /** open a SQL database */
+ void slotOpenDatabase(void);
+
+ /**
+ * saves the current document. If it has no name yet, the user
+ * will be queried for it.
+ *
+ * @retval false save operation failed
+ * @retval true save operation was successful
+ */
+ bool slotFileSave(void);
+
+ /**
+ * ask the user for the filename and save the current document
+ *
+ * @retval false save operation failed
+ * @retval true save operation was successful
+ */
+ bool slotFileSaveAs(void);
+
+ /**
+ * ask the user to select a database and save the current document
+ *
+ * @retval false save operation failed
+ * @retval true save operation was successful
+ */
+ bool slotSaveAsDatabase(void);
+
+ /** asks for saving if the file is modified, then closes the actual file and window */
+ void slotFileCloseWindow(void);
+
+ /** asks for saving if the file is modified, then closes the actual file */
+ void slotFileClose(void);
+
+ /**
+ * closes all open windows by calling close() on each memberList item
+ * until the list is empty, then quits the application.
+ * If queryClose() returns false because the user canceled the
+ * saveModified() dialog, the closing breaks.
+ */
+ void slotFileQuit(void);
+
+ void slotFileConsitencyCheck(void);
+
+ /**
+ * fires up the price table editor
+ */
+ void slotPriceDialog(void);
+
+ /**
+ * fires up the currency table editor
+ */
+ void slotCurrencyDialog(void);
+
+ /**
+ * Toggles the hide reconciled transactions setting
+ */
+ void slotHideReconciledTransactions(void);
+
+ /**
+ * Toggles the hide unused categories setting
+ */
+ void slotHideUnusedCategories(void);
+
+ /**
+ * Toggles the show all accounts setting
+ */
+ void slotShowAllAccounts(void);
+
+
+ /**
+ * changes the statusbar contents for the standard label permanently,
+ * used to indicate current actions. Returns the previous value for
+ * 'stacked' usage.
+ *
+ * @param text the text that is displayed in the statusbar
+ */
+ const QString slotStatusMsg(const QString &text);
+
+ /**
+ * This method changes the progress bar in the status line according
+ * to the parameters @p current and @p total. The following special
+ * cases exist:
+ *
+ * - current = -1 and total = -1 will reset the progress bar
+ * - current = ?? and total != 0 will setup the 100% mark to @p total
+ * - current = xx and total == 0 will set the percentage
+ *
+ * @param current the current value with respect to the initialised
+ * 100% mark
+ * @param total the total value (100%)
+ */
+ void slotStatusProgressBar(int current, int total = 0);
+
+ /** No descriptions */
+ void slotProcessExited(void);
+
+ /**
+ * Called to update stock and currency prices from the user menu
+ */
+ void slotEquityPriceUpdate(void);
+
+ /**
+ * Imports a KMM statement into the engine, triggering the appropriate
+ * UI to handle account matching, payee creation, and someday
+ * payee and transaction matching.
+ */
+ bool slotStatementImport(const MyMoneyStatement& s);
+
+ /**
+ * Essentially similiar to the above slot, except this will load the file
+ * from disk first, given the URL.
+ */
+ bool slotStatementImport(const QString& url);
+
+ /**
+ * This slot starts the reconciliation of the currently selected account
+ */
+ void slotAccountReconcileStart(void);
+
+ /**
+ * This slot finishes a previously started reconciliation
+ */
+ void slotAccountReconcileFinish(void);
+
+ /**
+ * This slot postpones a previously started reconciliations
+ */
+ void slotAccountReconcilePostpone(void);
+
+ /**
+ * This slot deletes the currently selected account if possible
+ */
+ void slotAccountDelete(void);
+
+ /**
+ * This slot opens the account editor to edit the currently
+ * selected account if possible
+ */
+ void slotAccountEdit(void);
+
+ /**
+ * This slot opens the selected account in the ledger view
+ */
+ void slotAccountOpen(const MyMoneyObject& = MyMoneyAccount());
+
+ /**
+ * This slot closes the currently selected account if possible
+ */
+ void slotAccountClose(void);
+
+ /**
+ * This slot re-openes the currently selected account if possible
+ */
+ void slotAccountReopen(void);
+
+ /**
+ * This slot reparents account @p src to be a child of account @p dest
+ *
+ * @param src account to be reparented
+ * @param dest new parent
+ */
+ void slotReparentAccount(const MyMoneyAccount& src, const MyMoneyAccount& dest);
+
+ /**
+ * This slot reparents account @p src to be a held at institution @p dest
+ *
+ * @param src account to be reparented
+ * @param dest new parent institution
+ */
+ void slotReparentAccount(const MyMoneyAccount& src, const MyMoneyInstitution& dest);
+
+ /**
+ * This slot creates a transaction report for the selected account
+ * and opens it in the reports view.
+ */
+ void slotAccountTransactionReport(void);
+
+ /**
+ * This slot opens the account options menu at the current cursor
+ * position.
+ */
+ void slotShowAccountContextMenu(const MyMoneyObject&);
+
+ /**
+ * This slot opens the schedule options menu at the current cursor
+ * position.
+ */
+ void slotShowScheduleContextMenu(void);
+
+ /**
+ * This slot opens the institution options menu at the current cursor
+ * position.
+ */
+ void slotShowInstitutionContextMenu(const MyMoneyObject&);
+
+ /**
+ * This slot opens the investment options menu at the current cursor
+ * position.
+ */
+ void slotShowInvestmentContextMenu(void);
+
+ /**
+ * This slot opens the payee options menu at the current cursor
+ * position.
+ */
+ void slotShowPayeeContextMenu(void);
+
+ /**
+ * This slot opens the budget options menu at the current cursor
+ * position.
+ */
+ void slotShowBudgetContextMenu(void);
+
+ /**
+ * This slot opens the transaction options menu at the current cursor
+ * position.
+ */
+ void slotShowTransactionContextMenu(void);
+
+ /**
+ * This slot opens the currency options menu at the current cursor
+ * position.
+ */
+ void slotShowCurrencyContextMenu(void);
+
+ /**
+ * This slot collects information for a new scheduled transaction
+ * and saves it in the engine. @sa slotScheduleNew(const MyMoneyTransaction&)
+ */
+ void slotScheduleNew(void);
+
+ /**
+ * This slot allows to edit information the currently selected schedule
+ */
+ void slotScheduleEdit(void);
+
+ /**
+ * This slot allows to delete the currently selected schedule
+ */
+ void slotScheduleDelete(void);
+
+ /**
+ * This slot allows to enter the next scheduled transaction of
+ * the currently selected schedule
+ */
+ void slotScheduleEnter(void);
+
+ /**
+ * This slot allows to skip the next scheduled transaction of
+ * the currently selected schedule
+ */
+ void slotScheduleSkip(void);
+
+ /**
+ * This slot fires up the KCalc application
+ */
+ void slotToolsStartKCalc(void);
+
+ void slotResetSelections(void);
+
+ void slotSelectAccount(const MyMoneyObject& account = MyMoneyAccount());
+
+ void slotSelectInstitution(const MyMoneyObject& institution = MyMoneyInstitution());
+
+ void slotSelectInvestment(const MyMoneyObject& account = MyMoneyAccount());
+
+ void slotSelectSchedule(const MyMoneySchedule& schedule = MyMoneySchedule());
+
+ void slotSelectPayees(const QValueList<MyMoneyPayee>& list);
+
+ void slotSelectBudget(const QValueList<MyMoneyBudget>& list);
+
+ void slotSelectTransactions(const KMyMoneyRegister::SelectedTransactions& list);
+
+ void slotSelectCurrency(const MyMoneySecurity& currency = MyMoneySecurity());
+
+ void slotTransactionMatch(void);
+
+ /**
+ * Brings up the new account wizard and saves the information.
+ */
+ void slotAccountNew(void);
+ void slotAccountNew(MyMoneyAccount&);
+
+ /**
+ * Brings up the new category editor and saves the information.
+ */
+ void slotCategoryNew(void);
+
+ /**
+ * Brings up the new category editor and saves the information.
+ * The dialog will be preset with the name and parent account.
+ *
+ * @param account reference of category to be created. The @p name member
+ * should be filled by the caller. The object will be filled
+ * with additional information during the creation process
+ * esp. the @p id member.
+ * @param parent reference to parent account (defaults to none)
+ */
+ void slotCategoryNew(MyMoneyAccount& account, const MyMoneyAccount& parent = MyMoneyAccount());
+
+ /**
+ * This method updates all KAction items to the current state.
+ */
+ void slotUpdateActions(void);
+
+ /**
+ * Brings up the input dialog and saves the information.
+ */
+ void slotInstitutionNew(void);
+
+ /**
+ * Brings up the input dialog and saves the information. If
+ * the institution has been created, the @a id member is filled,
+ * otherwise it is empty.
+ *
+ * @param institution reference to data to be used to create the
+ * institution. id member will be updated.
+ */
+ void slotInstitutionNew(MyMoneyInstitution& institution);
+
+ /**
+ * Called whenever a plugin is plugged in
+ */
+ void slotPluginPlug(KPluginInfo*);
+
+ /**
+ * Called whenever a plugin is unplugged
+ */
+ void slotPluginUnplug(KPluginInfo*);
+
+private:
+ // bool verifyImportedData(const MyMoneyAccount& account);
+
+ /**
+ * Load the status bar with the 'ready' message. This is hold in a single
+ * place, so that is consistent with isReady().
+ */
+ void ready(void);
+
+ /**
+ * Check if the status bar contains the 'ready' message. The return
+ * value is used e.g. to detect if a quit operation is allowed or not.
+ *
+ * @retval true application is idle
+ * @retval false application is active working on a longer operation
+ */
+ bool isReady(void);
+
+ /**
+ * Delete a possibly existing transaction editor but make sure to remove
+ * any reference to it so that we avoid using a half-dead object
+ */
+ void deleteTransactionEditor(void);
+
+ /**
+ * delete all selected transactions w/o further questions
+ */
+ void doDeleteTransactions(void);
+
+ /**
+ * Exchanges all references in transaction @a _t to account @a fromId
+ * into references to account @a toId. Returns @a true if at least
+ * one split has been changed, @a false otherwise.
+ */
+ bool exchangeAccountInTransaction(MyMoneyTransaction& _t, const QString& fromId, const QString& toId);
+
+signals:
+ /**
+ * This signal is emitted when a new file is loaded. In the case file
+ * is closed, this signal is also emitted with an empty url.
+ */
+ void fileLoaded(const KURL& url);
+
+ /**
+ * This signal is emitted when a payee/list of payees has been selected by
+ * the GUI. If no payee is selected or the selection is removed,
+ * @p payees is identical to an empty QValueList. This signal is used
+ * by plugins to get information about changes.
+ */
+ void payeesSelected(const QValueList<MyMoneyPayee>& payees);
+
+ /**
+ * This signal is emitted when a transaction/list of transactions has been selected by
+ * the GUI. If no transaction is selected or the selection is removed,
+ * @p transactions is identical to an empty QValueList. This signal is used
+ * by plugins to get information about changes.
+ */
+ void transactionsSelected(const KMyMoneyRegister::SelectedTransactions& transactions);
+
+ /**
+ * This signal is sent out, when the user presses Ctrl+A or activates
+ * the Select all transactions action.
+ */
+ void selectAllTransactions(void);
+
+ /**
+ * This signal is emitted when a list of budgets has been selected by
+ * the GUI. If no budget is selected or the selection is removed,
+ * @a budget is identical to an empty QValueList. This signal is used
+ * by plugins to get information about changes.
+ */
+ void budgetSelected(const QValueList<MyMoneyBudget>& budget);
+ void budgetRename(void);
+
+ /**
+ * This signal is emitted when a new account has been selected by
+ * the GUI. If no account is selected or the selection is removed,
+ * @a account is identical to MyMoneyAccount(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void accountSelected(const MyMoneyAccount& account);
+ void investmentSelected(const MyMoneyAccount& account);
+
+ /**
+ * This signal is emitted when a new institution has been selected by
+ * the GUI. If no institution is selected or the selection is removed,
+ * @a institution is identical to MyMoneyInstitution(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void institutionSelected(const MyMoneyInstitution& institution);
+
+ /**
+ * This signal is emitted when a new schedule has been selected by
+ * the GUI. If no schedule is selected or the selection is removed,
+ * @a schedule is identical to MyMoneySchedule(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void scheduleSelected(const MyMoneySchedule& schedule);
+
+ /**
+ * This signal is emitted when a new currency has been selected by
+ * the GUI. If no currency is selected or the selection is removed,
+ * @a currency is identical to MyMoneySecurity(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void currencySelected(const MyMoneySecurity& currency);
+
+ void payeeRename(void);
+ void payeeCreated(const QString& id);
+
+ void currencyRename(void);
+ void currencyCreated(const QString& id);
+
+ void startMatchTransaction(const MyMoneyTransaction& t);
+ void cancelMatchTransaction(void);
+
+ /**
+ * This signal is emitted when an account has been successfully reconciled
+ * and all transactions are updated in the engine. It can be used by plugins
+ * to create reconciliation reports.
+ *
+ * @param account the account data
+ * @param date the reconciliation date as provided through the dialog
+ * @param startingBalance the starting balance as provided through the dialog
+ * @param endingBalance the ending balance as provided through the dialog
+ * @param transactionList reference to QValueList of QPair containing all
+ * transaction/split pairs processed by the reconciliation.
+ */
+ void accountReconciled(const MyMoneyAccount& account, const QDate& date, const MyMoneyMoney& startingBalance, const MyMoneyMoney& endingBalance, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& transactionList);
+
+public:
+ /**
+ * This method retrieves a pointer to a KAction object from actionCollection().
+ * If the action with the name @p actionName is not found, a pointer to
+ * a static non-configured KAction object is returned and a warning is
+ * printed to stderr.
+ *
+ * @param actionName name of the action to be retrieved
+ * @return pointer to KAction object (or derivative)
+ */
+ KAction* action(const QString& actionName) const;
+
+ /**
+ * This method is implemented for convenience. It returns a dynamic_cast-ed
+ * pointer to an action found in actionCollection().
+ * If the action with the name @p actionName is not found or the object
+ * is not of type KToggleAction, a pointer to a static non-configured
+ * KToggleAction object is returned and a warning is printed to stderr.
+ */
+ KToggleAction* toggleAction(const QString& actionName) const;
+
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /*
+ * Actually, one should write "Private * const d" but that confuses the KIDL
+ * compiler in this context. It complains about the const keyword. So we leave
+ * it out here
+ */
+ /// \internal d-pointer instance.
+ Private* d;
+
+ /** the configuration object of the application */
+ KConfig *config;
+
+ QMap<QString,KMyMoneyPlugin::ImporterPlugin*> m_importerPlugins;
+
+ QMap<QString, KMyMoneyPlugin::OnlinePlugin*> m_onlinePlugins;
+
+ enum backupStateE {
+ BACKUP_IDLE = 0,
+ BACKUP_MOUNTING,
+ BACKUP_COPYING,
+ BACKUP_UNMOUNTING
+ };
+ /**
+ * The following variable represents the state while crafting a backup.
+ * It can have the following values
+ *
+ * - IDLE: the default value if not performing a backup
+ * - MOUNTING: when a mount command has been issued
+ * - COPYING: when a copy command has been issued
+ * - UNMOUNTING: when an unmount command has been issued
+ */
+ backupStateE m_backupState;
+
+ /**
+ * This variable keeps the result of the backup operation.
+ */
+ int m_backupResult;
+
+ /**
+ * This variable is set, when the user selected to mount/unmount
+ * the backup volume.
+ */
+ bool m_backupMount;
+
+ KProcess proc;
+
+ /// A pointer to the view holding the tabs.
+ KMyMoneyView *myMoneyView;
+
+ /// The URL of the file currently being edited when open.
+ KURL m_fileName;
+
+ bool m_startDialog;
+ QString m_mountpoint;
+
+ KProgress* progressBar;
+
+ QString m_statusMsg;
+
+ int m_progressUpdate;
+ int m_nextUpdate;
+
+ MyMoneyQifReader* m_qifReader;
+ MyMoneyStatementReader* m_smtReader;
+ KFindTransactionDlg* m_searchDlg;
+
+ bool m_bCheckSchedules;
+
+ KToolBarPopupAction* m_previousViewButton;
+ KToolBarPopupAction* m_nextViewButton;
+
+ QObject* m_pluginInterface;
+
+ MyMoneyAccount m_selectedAccount;
+ MyMoneyAccount m_reconciliationAccount;
+ MyMoneyAccount m_selectedInvestment;
+ MyMoneyInstitution m_selectedInstitution;
+ MyMoneySchedule m_selectedSchedule;
+ MyMoneySecurity m_selectedCurrency;
+ QValueList<MyMoneyPayee> m_selectedPayees;
+ QValueList<MyMoneyBudget> m_selectedBudgets;
+ KMyMoneyRegister::SelectedTransactions m_selectedTransactions;
+
+ // This is Auto Saving related
+ bool m_autoSaveEnabled;
+ QTimer* m_autoSaveTimer;
+ int m_autoSavePeriod;
+ bool m_inAutoSaving;
+
+ // Pointer to the combo box used for key selection during
+ // File/Save as
+ KComboBox* m_saveEncrypted;
+
+ // pointer to the current transaction editor
+ TransactionEditor* m_transactionEditor;
+
+ // Reconciliation dialog
+ KEndingBalanceDlg* m_endingBalanceDlg;
+
+ // id's that need to be remembered
+ QString m_accountGoto, m_payeeGoto;
+
+ QStringList m_additionalGpgKeys;
+ QLabel* m_additionalKeyLabel;
+ KPushButton* m_additionalKeyButton;
+};
+
+extern KMyMoney2App *kmymoney2;
+
+class KMStatus
+{
+public:
+ KMStatus (const QString &text);
+ ~KMStatus();
+private:
+ QString m_prevText;
+};
+
+#define KMSTATUS(msg) KMStatus _thisStatus(msg)
+
+#endif // KMYMONEY2_H
diff --git a/kmymoney2/kmymoney2.kcfg b/kmymoney2/kmymoney2.kcfg
new file mode 100644
index 0000000..c6f53f3
--- /dev/null
+++ b/kmymoney2/kmymoney2.kcfg
@@ -0,0 +1,381 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+<kcfg>
+ <kcfgfile name="kmymoney2rc" />
+ <group name="General Options">
+ <entry name="AlwaysShowNrField" type="Bool">
+ <label>Always show a No. field in transaction form</label>
+ <default>false</default>
+ </entry>
+ <entry name="AutoFillTransaction" type="Int">
+ <label>Auto fill with previous transaction data</label>
+ <default>1</default>
+ </entry>
+ <entry name="AutoReusePayee" type="Bool">
+ <label>Prefill payee with previous used value</label>
+ <default>true</default>
+ </entry>
+ <entry name="AutoFillDifference" type="Int">
+ <label>Treat two transactions as identical, if amount differs less than</label>
+ <default>10</default>
+ </entry>
+ <entry name="AutoIncCheckNumber" type="Bool">
+ <label>Auto increment check number</label>
+ <default>true</default>
+ </entry>
+ <entry name="AutoSaveFile" type="Bool">
+ <label>Autosave file periodically</label>
+ <default>false</default>
+ </entry>
+ <entry name="AutoSavePeriod" type="Int">
+ <label>Autosave interval in minutes</label>
+ <default>10</default>
+ <min>0</min>
+ <max>60</max>
+ </entry>
+ <entry name="CheckSchedule" type="Bool">
+ <label>Check schedules upon startup</label>
+ <default>false</default>
+ </entry>
+ <entry name="CheckSchedulePreview" type="Int">
+ <label>Enter transactions this number of days in advance</label>
+ <default>0</default>
+ <min>0</min>
+ <max>999</max>
+ </entry>
+ <entry name="ExternalCalculator" type="String">
+ <label>Name of external calculator program</label>
+ <default>kcalc</default>
+ </entry>
+ <entry name="SchedulePreview" type="Int">
+ <label>Number of days to preview schedules in ledger</label>
+ <default>0</default>
+ <min>0</min>
+ <max>999</max>
+ </entry>
+ <entry name="CopyTypeToNr" type="Bool">
+ <label>Insert transaction type into No. field for new transactions</label>
+ <default>false</default>
+ </entry>
+ <entry name="FocusChangeIsEnter" type="Bool">
+ <label>Keep changes when selecting a different transaction/split</label>
+ <default>false</default>
+ </entry>
+ <entry name="EnterMovesBetweenFields" type="Bool">
+ <label>Using the Enter key moves between the fields</label>
+ <default>false</default>
+ </entry>
+ <entry name="LedgerLens" type="Bool">
+ <label>Use the ledger lens</label>
+ <default>false</default>
+ </entry>
+ <entry name="PricePrecision" type="Int">
+ <label>Price Precision</label>
+ <default>4</default>
+ <min>4</min>
+ <max>10</max>
+ </entry>
+ <entry name="PriceHistoryUpdate" type="Bool">
+ <label>Update price history</label>
+ <default>true</default>
+ </entry>
+ <entry name="TransactionForm" type="Bool">
+ <label>Show transaction form</label>
+ <default>true</default>
+ </entry>
+ <entry name="StartLastViewSelected" type="Int">
+ <label>Start with last selected view or homepage</label>
+ <default>0</default>
+ </entry>
+ <entry name="WriteDataEncrypted" type="Bool">
+ <label>Use GPG to encrypt data file</label>
+ <default>false</default>
+ </entry>
+ <entry name="EncryptRecover" type="Bool">
+ <label>Also encrypt against recover key</label>
+ <default>false</default>
+ </entry>
+ <entry name="GpgRecipient" type="String">
+ <label>GPG User ID (deprecated)</label>
+ </entry>
+ <entry name="GpgRecipientList" type="StringList">
+ <label>GPG User ID</label>
+ </entry>
+ <entry name="ExpertMode" type="Bool">
+ <label>Run in expert (accountant) mode</label>
+ <default>false</default>
+ </entry>
+ <entry name="ShowSplash" type="Bool">
+ <label>Show splash screen during startup</label>
+ <default>true</default>
+ </entry>
+ <entry name="syncLedgerInvestment" type="Bool">
+ <label>Synchronize account in ledger and investment view</label>
+ <default>true</default>
+ </entry>
+ <entry name="iconSize" type="Int">
+ <label>Icon size for view selection</label>
+ <default>2</default>
+ </entry>
+ <entry name="hiddenViews" type="String">
+ <label>list of hidden views</label>
+ <default/>
+ </entry>
+ <entry name="firstTimeRun" type="Bool">
+ <label>Firsttime switch to start new user wizard</label>
+ <default>true</default>
+ </entry>
+ <entry name="showTitleBar" type="Bool">
+ <label>Show title bar on each view</label>
+ <default>true</default>
+ </entry>
+ <entry name="stringMatchFromStart" type="Bool">
+ <label>Start string matches for e.g. payees at start of string</label>
+ <default>false</default>
+ </entry>
+ <entry name="stdTransactionFormTabOrder" type="String">
+ <label>Tab order of edit widgets in transaction form</label>
+ <default>account,cashflow,payee,category,memo,number,date,amount,state</default>
+ </entry>
+ <entry name="stdTransactionRegisterTabOrder" type="String">
+ <label>Tab order of edit widgets in register</label>
+ <default>number,date,payee,category,memo,payment,deposit,state</default>
+ </entry>
+ </group>
+ <group name="Homepage Options">
+ <entry name="ItemList" type="String">
+ <label>Order of items on homepage</label>
+ <default>8,1,2,3,4,5,6,7,-9,10</default>
+ </entry>
+ <entry name="FontSizePercentage" type="Int">
+ <label>Percentage of default font size used for home view HTML page</label>
+ <default>100</default>
+ </entry>
+ <entry name="RememberFontSize" type="Bool">
+ <label>Remember (manually adjusted) font size in home view on program end.</label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowLimitInfo" type="Bool">
+ <label>Show account limit information on the Homepage</label>
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="Investment Settings">
+ </group>
+ <group name="List Options">
+ <entry name="HideUnusedCategory" type="Bool">
+ <label>Hide unused categories</label>
+ <default>false</default>
+ </entry>
+ <entry name="HideClosedAccounts" type="Bool">
+ <label>Hide closed accounts</label>
+ <default>false</default>
+ </entry>
+ <entry name="HideFinishedSchedules" type="Bool">
+ <label>Hide finished schedules</label>
+ <default>false</default>
+ </entry>
+ <entry name="HideReconciledTransactions" type="Bool">
+ <label>Hide reconciled transactions</label>
+ <default>false</default>
+ </entry>
+ <entry name="ShowRegisterDetailed" type="Bool">
+ <label>Show all register entries in full detail</label>
+ <default>false</default>
+ </entry>
+ <entry name="ShowGrid" type="Bool">
+ <label>Show a grid in the register</label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowFancyMarker" type="Bool">
+ <label>Show fancy group markers</label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowFiscalMarker" type="Bool">
+ <label>Show fancy markers for previous and current fiscal year</label>
+ <default>true</default>
+ </entry>
+ <entry name="FiscalYearBegin" type="Int">
+ <label>Starting month of the fiscal year</label>
+ <default>0</default>
+ <min>0</min>
+ <max>11</max>
+ </entry>
+ <entry name="FiscalYearBeginDay" type="Int">
+ <label>Starting day of the fiscal year</label>
+ <default>1</default>
+ <min>1</min>
+ <max>28</max>
+ </entry>
+ <entry name="StartDate" type="DateTime">
+ <label>Start date</label>
+ <default>QDateTime::fromString("1900-01-01T00:00:00", Qt::ISODate)</default>
+ </entry>
+ <entry name="useSystemColors" type="Bool">
+ <label>Use system colors</label>
+ <default>false</default>
+ </entry>
+ <entry name="listColor" type="Color">
+ <label>List color</label>
+ <default>240,240,240</default>
+ </entry>
+ <entry name="listBGColor" type="Color">
+ <label>List background color</label>
+ <default>255,255,255</default>
+ </entry>
+ <entry name="listGridColor" type="Color">
+ <label>List grid color</label>
+ <default>154,154,154</default>
+ </entry>
+ <entry name="importedTransactionColor" type="Color">
+ <label>Background color for imported transactions</label>
+ <default>255,255,0</default>
+ </entry>
+ <entry name="matchedTransactionColor" type="Color">
+ <label>Background color for matched transactions</label>
+ <default>152,251,152</default>
+ </entry>
+ <entry name="listErronousTransactionColor" type="Color">
+ <label>List color for erronous transactions</label>
+ <default>255,0,0</default>
+ </entry>
+ <entry name="listMissingConversionRate" type="Color">
+ <label>List color for missing conversion rate</label>
+ <default>0,0,255</default>
+ </entry>
+ <entry name="listNegativeValueColor" type="Color">
+ <label>List color for negative values</label>
+ <default>255,0,0</default>
+ </entry>
+ <entry name="groupMarkerColor" type="Color">
+ <label>Background color for group marker</label>
+ <default>255,242,155</default>
+ </entry>
+ <entry name="requiredFieldColor" type="Color">
+ <label>Background color for required fields</label>
+ <default>255,255,221</default>
+ </entry>
+ <entry name="useSystemFont" type="Bool">
+ <label>Use system font</label>
+ <default>false</default>
+ </entry>
+ <entry name="listCellFont" type="Font">
+ <label>Cell font</label>
+ </entry>
+ <entry name="listHeaderFont" type="Font">
+ <label>Header font</label>
+ </entry>
+ <entry name="sortNormalView" type="String">
+ <label>Sort order of register in normal view</label>
+ <default>1,-9,-4</default>
+ </entry>
+ <entry name="sortReconcileView" type="String">
+ <label>Sort order of register in normal view</label>
+ <default>1,-4</default>
+ </entry>
+ <entry name="sortSearchView" type="String">
+ <label>Sort order of register in search dialog</label>
+ <default>1,-9,-4</default>
+ </entry>
+ <entry name="defaultReconciliationState" type="Int">
+ <label>Default reconciliation state for transactions entered during reconciliation</label>
+ <default>0</default>
+ </entry>
+ </group>
+ <group name="Import options">
+ <entry name="matchInterval" type="Int">
+ <label>Number of days (plus/minus) to search for matching transactions</label>
+ <default>4</default>
+ </entry>
+ <entry name="askForPayeeCategory" type="Bool">
+ <label>During import, ask for a new payee's default category</label>
+ <default>false</default>
+ </entry>
+ </group>
+ <group name="Schedule Options">
+ </group>
+ <group name="Forecast Options">
+ <entry name="forecastMethod" type="Int">
+ <label>Method to calculate forecast</label>
+ <default>0</default>
+ </entry>
+ <entry name="forecastDays" type="Int">
+ <label>Days to forecast</label>
+ <default>90</default>
+ <min>1</min>
+ <max>999</max>
+ </entry>
+ <entry name="forecastAccountCycle" type="Int">
+ <label>Days of normal account cycle</label>
+ <default>30</default>
+ <min>1</min>
+ <max>999</max>
+ </entry>
+ <entry name="forecastCycles" type="Int">
+ <label>Number of historic cycles to use in forecast</label>
+ <default>3</default>
+ <min>1</min>
+ <max>999</max>
+ </entry>
+ <entry name="beginForecastDay" type="Int">
+ <label>Day of month to start forecast</label>
+ <default>0</default>
+ <min>0</min>
+ <max>31</max>
+ </entry>
+ <entry name="historyMethod" type="Int">
+ <label>Method to calculate history-based forecast</label>
+ <default>1</default>
+ </entry>
+ <entry name="skipOpeningDate" type="Bool">
+ <label>Skip opening date when fetching transactions</label>
+ <default>true</default>
+ </entry>
+ <entry name="includeFutureTransactions" type="Bool">
+ <label>Include future transaction when using Schedule Forecast</label>
+ <default>true</default>
+ </entry>
+ <entry name="includeScheduledTransactions" type="Bool">
+ <label>Include scheduled transactions when using Schedule Forecast</label>
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="QIF Options">
+ <entry name="qifCash" type="String">
+ <label>additional names for cash account</label>
+ <default>Bar</default>
+ </entry>
+ <entry name="qifBank" type="String">
+ <label>additional names for checking account</label>
+ <default>Banca,Banque</default>
+ </entry>
+ <entry name="qifCreditCard" type="String">
+ <label>additional names for credit card account</label>
+ <default>Kreditkarte</default>
+ </entry>
+ <entry name="qifAsset" type="String">
+ <label>additional names for asset account</label>
+ <default>And. Kto.</default>
+ </entry>
+ <entry name="qifOpeningBalance" type="String">
+ <label>additional names for opening balance payee</label>
+ <default>Eröffnungssaldo</default>
+ </entry>
+ <entry name="qifInvoice" type="String">
+ <label>additional names for invoice accounts</label>
+ <default>Rechnung</default>
+ </entry>
+ </group>
+ <group name="Account View Settings">
+ <entry name="showAccountsExpanded" type="Bool">
+ <label>Show accounts view expanded when loaded</label>
+ <default>false</default>
+ </entry>
+ </group>
+</kcfg>
+<!--
+ <entry name="" type="">
+ <label>...</label>
+ <default>...</default>
+ </entry>
+-->
diff --git a/kmymoney2/kmymoney2ui.rc b/kmymoney2/kmymoney2ui.rc
new file mode 100644
index 0000000..c39a76d
--- /dev/null
+++ b/kmymoney2/kmymoney2ui.rc
@@ -0,0 +1,260 @@
+<!DOCTYPE kpartgui>
+<kpartgui version="38" name="kmymoney2" >
+ <MenuBar>
+ <Menu name="file" >
+ <Action append="open_merge" name="open_database" />
+ <Action append="save_merge" name="saveas_database" />
+ <Menu icon="fileimport" append="save_merge" name="import" >
+ <text>&amp;Import</text>
+ <Action name="file_import_qif" />
+ <Action name="file_import_gnc" />
+ <MergeLocal name="import_merge"/>
+ <Separator/>
+ <Action name="file_import_template" />
+ </Menu>
+ <Menu icon="fileexport" append="save_merge" name="export" >
+ <text>E&amp;xport</text>
+ <Action name="file_export_qif" />
+ <Separator/>
+ <Action name="file_export_template" />
+ </Menu>
+ <Action name="file_backup" />
+ <Separator/>
+ <Action icon="personal_data" name="view_personal_data" />
+ <Action name="view_file_info" />
+ <Action icon="info" name="file_dump" />
+ </Menu>
+ <Menu name="edit" >
+ <Action icon="transaction_find" name="edit_find_transaction" />
+ </Menu>
+ <Menu name="view" >
+ <Action name="view_show_transaction_detail" />
+ <Action name="view_hide_reconciled_transactions" />
+ <Action name="view_hide_unused_categories" />
+ <Action name="view_show_all_accounts" />
+ </Menu>
+ <Menu name="institution" >
+ <text>&amp;Institution</text>
+ <Action icon="institution_add" name="institution_new" />
+ <Action name="institution_edit" />
+ <Action name="institution_delete" />
+ </Menu>
+ <Menu name="account" >
+ <text>&amp;Account</text>
+ <Action icon="account_add" name="account_new" />
+ <Action name="account_edit" />
+ <Action name="account_delete" />
+ <Action name="account_open" />
+ <Separator/>
+ <Action name="account_reconcile" />
+ <Action name="account_reconcile_postpone" />
+ <Action name="account_reconcile_finish" />
+ <Separator/>
+ <Action name="account_transaction_report" />
+ <Separator/>
+ <Action name="account_close" />
+ <Action name="account_reopen" />
+ <Separator/>
+ <Action name="account_online_unmap" />
+ <Action name="account_online_map" />
+ <Action name="account_online_update" />
+ <Action name="account_online_update_all" />
+ </Menu>
+ <Menu name="category" >
+ <text>&amp;Category</text>
+ <Action name="category_new" />
+ <Action name="category_edit" />
+ <Action name="category_delete" />
+ <Action name="account_open" />
+ </Menu>
+ <Menu name="transaction" >
+ <text>&amp;Transaction</text>
+ <Action name="transaction_new" />
+ <Action name="transaction_edit" />
+ <Action name="transaction_editsplits" />
+ <Action name="transaction_delete" />
+ <Action name="transaction_duplicate" />
+ <Menu name="transaction_mark_menu">
+ <text>Mark transaction as...</text>
+ <title>Mark transaction</title>
+ <Action name="transaction_mark_notreconciled"/>
+ <Action name="transaction_mark_cleared"/>
+ <Action name="transaction_mark_reconciled"/>
+ </Menu>
+ <Separator />
+ <Action name="transaction_goto_account"/>
+ <Action name="transaction_goto_payee"/>
+ <Action name="transaction_create_schedule"/>
+ <Separator />
+ <Action name="transaction_match" />
+ <Action name="transaction_accept" />
+ <Separator />
+ <Action name="transaction_select_all" />
+ </Menu>
+ <Merge/>
+ <Menu name="kmmtools" >
+ <Text>T&amp;ools</Text>
+ <Action name="tools_qif_editor" />
+ <Action name="tools_security_editor" />
+ <Action name="tools_currency_editor" />
+ <Action name="tools_price_editor" />
+ <Action name="tools_update_prices" />
+ <Action name="tools_consistency_check" />
+ <Action name="tools_performancetest" />
+ <Separator/>
+ <Action name="tools_plugin_list" />
+ <Action name="debug_traces" />
+ <Action name="debug_timers" />
+ </Menu>
+ <Menu name="settings" >
+ <Action append="show_merge" name="settings_enable_messages" />
+ <Action append="show_merge" name="settings_language"/>
+ </Menu>
+ <Menu name="help" >
+ <Action name="show_tip" />
+ </Menu>
+ </MenuBar>
+ <Menu name="account_context_menu">
+ <title>Account options</title>
+ <Action name="account_new" />
+ <Action name="category_new" />
+ <Action name="account_open" />
+ <Action name="account_edit" />
+ <Action name="account_delete" />
+ <Separator/>
+ <Action name="account_reconcile" />
+ <Action name="account_reconcile_postpone" />
+ <Action name="account_reconcile_finish" />
+ <Separator/>
+ <Action name="account_transaction_report" />
+ <Separator/>
+ <Action name="account_close" />
+ <Action name="account_reopen" />
+ <Separator/>
+ <Action name="account_online_unmap" />
+ <Action name="account_online_map" />
+ <Action name="account_online_update" />
+ <Separator/>
+ <Action name="investment_new" />
+ <Action name="investment_edit" />
+ <Action name="investment_delete" />
+ <Action name="investment_online_price_update" />
+ <Action name="investment_manual_price_update" />
+ </Menu>
+ <Menu name="category_context_menu">
+ <title>Category options</title>
+ <Action name="category_new" />
+ <Action name="category_edit" />
+ <Action name="category_delete" />
+ <Action name="account_open" />
+ </Menu>
+ <Menu name="institution_context_menu">
+ <title>Institution options</title>
+ <Action name="institution_new" />
+ <Action name="institution_edit" />
+ <Action name="institution_delete" />
+ <Separator />
+ <Action name="account_new"/>
+ </Menu>
+ <Menu name="payee_context_menu">
+ <title>Payee options</title>
+ <Action name="payee_new" />
+ <Action name="payee_rename" />
+ <Action name="payee_delete" />
+ </Menu>
+ <Menu name="budget_context_menu">
+ <title>Budget options</title>
+ <Action name="budget_new" />
+ <Action name="budget_rename" />
+ <Action name="budget_change_year" />
+ <Action name="budget_delete" />
+ <Action name="budget_copy" />
+ <Action name="budget_forecast" />
+ </Menu>
+ <Menu name="investment_context_menu">
+ <title>Investment options</title>
+ <Action name="investment_new" />
+ <Action name="investment_edit" />
+ <Action name="investment_delete" />
+ <Action name="investment_online_price_update" />
+ <Action name="investment_manual_price_update" />
+ <Separator />
+ <Action name="tools_update_prices" />
+ <Separator />
+ <Action name="account_close" />
+ <Action name="account_reopen" />
+ </Menu>
+ <Menu name="schedule_context_menu">
+ <title>Scheduled transactions options</title>
+ <Action name="schedule_new" />
+ <Action name="schedule_edit" />
+ <Action name="schedule_delete" />
+ <Action name="schedule_duplicate" />
+ <Separator />
+ <Action name="schedule_enter" />
+ <Action name="schedule_skip" />
+ </Menu>
+ <Menu name="schedule_create_menu">
+ <Action name="schedule_new_bill" />
+ <Action name="schedule_new_deposit" />
+ <Action name="schedule_new_transfer" />
+ </Menu>
+ <Menu name="transaction_context_menu">
+ <title>Transaction options</title>
+ <Action name="transaction_new" />
+ <Action name="transaction_edit" />
+ <Action name="transaction_editsplits" />
+ <Action name="transaction_delete" />
+ <Action name="transaction_duplicate" />
+ <Menu name="transaction_move_menu">
+ <text>Move transaction to...</text>
+ <title>Select account</title>
+ <ActionList name="transaction_move" />
+ </Menu>
+ <Menu name="transaction_context_mark_menu">
+ <text>Mark transaction as...</text>
+ <title>Mark transaction</title>
+ <Action name="transaction_mark_notreconciled"/>
+ <Action name="transaction_mark_cleared"/>
+ <Action name="transaction_mark_reconciled"/>
+ </Menu>
+ <Separator />
+ <Action name="transaction_goto_account"/>
+ <Action name="transaction_goto_payee"/>
+ <Action name="transaction_create_schedule"/>
+ <Separator />
+ <Action name="transaction_match" />
+ <Action name="transaction_accept" />
+ </Menu>
+ <Menu name="currency_context_menu">
+ <title>Currency options</title>
+ <Action name="currency_new" />
+ <Action name="currency_rename" />
+ <Action name="currency_delete" />
+ <Action name="currency_setbase" />
+ </Menu>
+ <Menu name="account_online_menu">
+ <Action name="account_online_update" />
+ <Action name="account_online_update_all" />
+ </Menu>
+ <ToolBar noMerge="1" name="mainToolBar" fullWidth="true" >
+ <text>Main Toolbar</text>
+ <Action name="file_new" />
+ <Action name="file_open" />
+ <Action name="file_save" />
+ <Action name="file_print" />
+ <Separator lineSeparator="true"/>
+ <Action name="institution_new" />
+ <Action name="account_new" />
+ <Separator lineSeparator="true"/>
+ <Action name="account_open" />
+ <Action name="account_edit" />
+ <Action name="account_reconcile" />
+ <Action name="account_online_update_menu" />
+ <Action name="account_chart" />
+ <Separator lineSeparator="true"/>
+ <Action name="edit_find_transaction" />
+ <Separator />
+ <Action name="tools_kcalc" />
+ </ToolBar>
+</kpartgui>
diff --git a/kmymoney2/kmymoney_wizard.png b/kmymoney2/kmymoney_wizard.png
new file mode 100644
index 0000000..be61ab7
--- /dev/null
+++ b/kmymoney2/kmymoney_wizard.png
Binary files differ
diff --git a/kmymoney2/kmymoneyglobalsettings.cpp b/kmymoney2/kmymoneyglobalsettings.cpp
new file mode 100644
index 0000000..2dcd964
--- /dev/null
+++ b/kmymoney2/kmymoneyglobalsettings.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+ kmymoneyglobalsettings.cpp
+ -------------------
+ copyright : (C) 2006 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobalsettings.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+QFont KMyMoneyGlobalSettings::listCellFont(void)
+{
+ if(useSystemFont()) {
+ return KGlobalSettings::generalFont();
+ } else {
+ return KMyMoneySettings::listCellFont();
+ }
+}
+
+QFont KMyMoneyGlobalSettings::listHeaderFont(void)
+{
+ if(useSystemFont()) {
+ QFont font = KGlobalSettings::generalFont();
+ font.setBold(true);
+ return font;
+ } else {
+ return KMyMoneySettings::listHeaderFont();
+ }
+}
+
+QColor KMyMoneyGlobalSettings::listColor(void)
+{
+ if(useSystemColors())
+ return KGlobalSettings::baseColor();
+ else
+ return KMyMoneySettings::listColor();
+}
+
+QColor KMyMoneyGlobalSettings::listBGColor(void)
+{
+ if(useSystemColors())
+ return KGlobalSettings::alternateBackgroundColor();
+ else
+ return KMyMoneySettings::listBGColor();
+}
+
+QStringList KMyMoneyGlobalSettings::itemList(void)
+{
+ bool prevValue = self()->useDefaults(true);
+ QStringList all = QStringList::split(",", KMyMoneySettings::itemList());
+ self()->useDefaults(prevValue);
+ QStringList list = QStringList::split(",", KMyMoneySettings::itemList());
+
+ // now add all from 'all' that are missing in 'list'
+ QRegExp exp("-?(\\d+)");
+ QStringList::iterator it_s;
+ for(it_s = all.begin(); it_s != all.end(); ++it_s) {
+ exp.search(*it_s);
+ if(!list.contains(exp.cap(1)) && !list.contains(QString("-%1").arg(exp.cap(1)))) {
+ list << *it_s;
+ }
+ }
+ return list;
+}
+
+int KMyMoneyGlobalSettings::firstFiscalMonth(void)
+{
+ return KMyMoneySettings::fiscalYearBegin()+1;
+}
+
+int KMyMoneyGlobalSettings::firstFiscalDay(void)
+{
+ return KMyMoneySettings::fiscalYearBeginDay();
+}
+
diff --git a/kmymoney2/kmymoneyglobalsettings.h b/kmymoney2/kmymoneyglobalsettings.h
new file mode 100644
index 0000000..16ca4a2
--- /dev/null
+++ b/kmymoney2/kmymoneyglobalsettings.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ kmymoneyglobalsettings.h
+ -------------------
+ copyright : (C) 2006 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYGLOBALSETTINGS_H
+#define KMYMONEYGLOBALSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneysettings.h>
+
+class KMyMoneyGlobalSettings : public KMyMoneySettings
+{
+public:
+ static QFont listCellFont(void);
+ static QFont listHeaderFont(void);
+ static QColor listColor(void);
+ static QColor listBGColor(void);
+ static QStringList itemList(void);
+ static int firstFiscalMonth(void);
+ static int firstFiscalDay(void);
+};
+#endif
diff --git a/kmymoney2/kmymoneysettings.kcfgc b/kmymoney2/kmymoneysettings.kcfgc
new file mode 100644
index 0000000..baa39ae
--- /dev/null
+++ b/kmymoney2/kmymoneysettings.kcfgc
@@ -0,0 +1,4 @@
+File=kmymoney2.kcfg
+ClassName=KMyMoneySettings
+Singleton=true
+Mutators=true
diff --git a/kmymoney2/kmymoneytest.cpp b/kmymoney2/kmymoneytest.cpp
new file mode 100644
index 0000000..f3c7222
--- /dev/null
+++ b/kmymoney2/kmymoneytest.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+ autotest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "config.h"
+
+#include <iostream>
+#include <string>
+#include <stdexcept>
+
+/* required for Q_UNUSED( ) */
+#include <qglobal.h>
+
+#ifdef HAVE_LIBCPPUNIT
+
+#include <kcmdlineargs.h>
+#include <kapplication.h>
+
+#include "cppunit/TextTestRunner.h"
+#include "cppunit/TextTestResult.h"
+#include "cppunit/TestSuite.h"
+#include "cppunit/extensions/HelperMacros.h"
+
+#include "mymoney/mymoneyutils.h"
+
+#define private public
+#include "mymoney/mymoneysubject.h"
+#include "mymoney/mymoneyobserver.h"
+#undef private
+
+#include "mymoney/mymoneyexceptiontest.h"
+#include "mymoney/mymoneymoneytest.h"
+#include "mymoney/mymoneyobservertest.h"
+#include "mymoney/mymoneyinstitutiontest.h"
+#include "mymoney/mymoneysplittest.h"
+#include "mymoney/mymoneyaccounttest.h"
+#include "mymoney/mymoneytransactiontest.h"
+#include "mymoney/storage/mymoneyseqaccessmgrtest.h"
+#include "mymoney/storage/mymoneydatabasemgrtest.h"
+#include "mymoney/mymoneyfiletest.h"
+#include "mymoney/mymoneykeyvaluecontainertest.h"
+#include "mymoney/mymoneyscheduletest.h"
+#include "mymoney/mymoneyfinancialcalculatortest.h"
+#include "mymoney/mymoneysecuritytest.h"
+#include "mymoney/mymoneypricetest.h"
+#include "mymoney/mymoneyobjecttest.h"
+#include "mymoney/mymoneyforecasttest.h"
+#include "mymoney/mymoneypayeetest.h"
+
+#include "mymoney/storage/mymoneymaptest.h"
+
+#include "reports/pivottabletest.h"
+#include "reports/pivotgridtest.h"
+#include "reports/querytabletest.h"
+
+#include "converter/convertertest.h"
+
+#include "cppunit/TextTestProgressListener.h"
+
+class MyProgressListener : public CppUnit::TextTestProgressListener
+{
+ void startTest(CppUnit::Test *test) {
+ QString name = test->getName().c_str();
+ if(name.find('.') != -1) { // in CPPUNIT 1.8.0
+ name = name.mid(2); // cut off first 2 chars
+ name = name.left(name.find('.'));
+ } else if(name.find("::") != -1) { // in CPPUNIT 1.9.14
+ name = name.left(name.find("::"));
+ }
+ if(m_name != name) {
+ if(m_name != "")
+ std::cout << std::endl;
+ std::cout << "Running: " << name << std::endl;
+ m_name = name;
+ }
+ }
+private:
+ QString m_name;
+};
+
+void unexpectedException(MyMoneyException *e)
+{
+ std::string msg = "Unexpected exception: ";
+ msg += e->what().latin1();
+ msg += " thrown in ";
+ msg += e->file().latin1();
+ msg += ":";
+ char line[8];
+ sprintf(line, "%ld", e->line());
+ msg += line;
+ delete e;
+ CPPUNIT_FAIL(msg);
+}
+
+#endif // HAVE_LIBCPPUNIT
+
+int main(int testargc, char** testargv)
+{
+ int rc = 0;
+
+#ifdef HAVE_LIBCPPUNIT
+ static const KCmdLineOptions options[] =
+ {
+ { "+[test_suite]", ("Optionally specify a test suite"), 0 },
+ { "", ("Optional arguments are for ctest"), 0 },
+ KCmdLineLastOption // End of options.
+ };
+
+ // we seem to need a KApplication object to use KGlobal::locale()
+ KCmdLineArgs::init(testargc, testargv, testargv[0], "UNIT TESTS", "", "0.1");
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication::disableAutoDcopRegistration();
+ KApplication app(false, false);
+
+#ifdef _CHECK_MEMORY
+ _CheckMemory_Init(0);
+#endif
+
+ // mymoney tests
+ //CPPUNIT_TEST_SUITE_REGISTRATION(KReportsViewTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyMapTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(ConverterTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyKeyValueContainerTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneySplitTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyMoneyTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyAccountTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyScheduleTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyDatabaseMgrTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneySeqAccessMgrTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyFileTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyObjectTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyInstitutionTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyFinancialCalculatorTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyTransactionTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneySecurityTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyForecastTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyExceptionTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyObserverTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyPriceTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(MyMoneyPayeeTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(PivotGridTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(PivotTableTest);
+ CPPUNIT_TEST_SUITE_REGISTRATION(QueryTableTest);
+
+ // off we go
+ CppUnit::TestFactoryRegistry &registry =
+ CppUnit::TestFactoryRegistry::getRegistry();
+
+ // run all tests if no test is specified on the command line
+ // this way, CTest can perform each test individually
+ CppUnit::Test *suite = registry.makeTest();
+ if (testargc>1)
+ {
+ try
+ {
+ suite = suite->findTest(testargv[1]);
+ }
+ catch(const std::invalid_argument &ex)
+ {
+ // oh, cmake perfomed bad at guessing the correct test names.
+ std::cout << ex.what() << std::endl;
+ // we output that the test passed since the test is deactivated
+ return 0;
+ }
+ }
+
+ CppUnit::TextTestRunner* runner = new CppUnit::TextTestRunner();
+
+ runner->addTest(suite);
+
+ MyProgressListener progress;
+ CppUnit::TestResultCollector result;
+
+ runner->eventManager().addListener(&progress);
+ runner->eventManager().addListener(&result);
+
+ runner->run();
+ std::cout << "Tests were run with CPPUNIT version " CPPUNIT_VERSION << std::endl;
+
+ rc = result.wasSuccessful() ? 0 : 1;
+ delete runner;
+
+ // make sure to delete the singletons before we start memory checking
+ // to avoid false error reports
+ // delete MyMoneyFile::instance();
+
+#ifdef _CHECK_MEMORY
+ chkmem.CheckMemoryLeak( true );
+ _CheckMemory_End();
+#endif // _CHECK_MEMORY
+
+#else
+ std::cout << "libcppunit not installed. no automatic tests available."
+ << std::endl;
+#endif // HAVE_LIBCPPUNIT
+ return rc;
+}
+
+// required for the testcases (mymoneystoragesql references it)
+void timetrace(const char *txt)
+{
+ Q_UNUSED(txt);
+}
+
+#if 0
+#ifdef HAVE_LIBOFX
+
+// these symbols are needed when linking with libofx because it requires
+// these global symbols as part of its callback interface
+extern "C" {
+ void ofx_proc_security_cb() {}
+ void ofx_proc_transaction_cb() {}
+ void ofx_proc_statement_cb() {}
+ void ofx_proc_status_cb() {}
+ void ofx_proc_account_cb() {}
+}
+#endif
+#endif
+
diff --git a/kmymoney2/kmymoneyutils.cpp b/kmymoney2/kmymoneyutils.cpp
new file mode 100644
index 0000000..83cf113
--- /dev/null
+++ b/kmymoney2/kmymoneyutils.cpp
@@ -0,0 +1,480 @@
+/***************************************************************************
+ kmymoneyutils.cpp - description
+ -------------------
+ begin : Wed Feb 5 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyforecast.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/investtransactioneditor.h>
+
+#include "kmymoneyutils.h"
+
+KMyMoneyUtils::KMyMoneyUtils()
+{
+}
+
+KMyMoneyUtils::~KMyMoneyUtils()
+{
+}
+
+const QString KMyMoneyUtils::accountTypeToString(const MyMoneyAccount::accountTypeE accountType)
+{
+ return MyMoneyAccount::accountTypeToString(accountType);
+}
+
+MyMoneyAccount::accountTypeE KMyMoneyUtils::stringToAccountType(const QString& type)
+{
+ MyMoneyAccount::accountTypeE rc = MyMoneyAccount::UnknownAccountType;
+ QString tmp = type.lower();
+
+ if(tmp == i18n("Checking").lower())
+ rc = MyMoneyAccount::Checkings;
+ else if(tmp == i18n("Savings").lower())
+ rc = MyMoneyAccount::Savings;
+ else if(tmp == i18n("Credit Card").lower())
+ rc = MyMoneyAccount::CreditCard;
+ else if(tmp == i18n("Cash").lower())
+ rc = MyMoneyAccount::Cash;
+ else if(tmp == i18n("Loan").lower())
+ rc = MyMoneyAccount::Loan;
+ else if(tmp == i18n("Certificate of Deposit").lower())
+ rc = MyMoneyAccount::CertificateDep;
+ else if(tmp == i18n("Investment").lower())
+ rc = MyMoneyAccount::Investment;
+ else if(tmp == i18n("Money Market").lower())
+ rc = MyMoneyAccount::MoneyMarket;
+ else if(tmp == i18n("Asset").lower())
+ rc = MyMoneyAccount::Asset;
+ else if(tmp == i18n("Liability").lower())
+ rc = MyMoneyAccount::Liability;
+ else if(tmp == i18n("Currency").lower())
+ rc = MyMoneyAccount::Currency;
+ else if(tmp == i18n("Income").lower())
+ rc = MyMoneyAccount::Income;
+ else if(tmp == i18n("Expense").lower())
+ rc = MyMoneyAccount::Expense;
+ else if(tmp == i18n("Investment Loan").lower())
+ rc = MyMoneyAccount::AssetLoan;
+ else if(tmp == i18n("Stock").lower())
+ rc = MyMoneyAccount::Stock;
+ else if(tmp == i18n("Equity").lower())
+ rc = MyMoneyAccount::Equity;
+
+ return rc;
+}
+
+MyMoneySecurity::eSECURITYTYPE KMyMoneyUtils::stringToSecurity(const QString& txt)
+{
+ MyMoneySecurity::eSECURITYTYPE rc = MyMoneySecurity::SECURITY_NONE;
+ QString tmp = txt.lower();
+
+ if(tmp == i18n("Stock").lower())
+ rc = MyMoneySecurity::SECURITY_STOCK;
+ else if(tmp == i18n("Mutual Fund").lower())
+ rc = MyMoneySecurity::SECURITY_MUTUALFUND;
+ else if(tmp == i18n("Bond").lower())
+ rc = MyMoneySecurity::SECURITY_BOND;
+ else if(tmp == i18n("Currency").lower())
+ rc = MyMoneySecurity::SECURITY_CURRENCY;
+
+ return rc;
+}
+
+const QString KMyMoneyUtils::securityTypeToString(const MyMoneySecurity::eSECURITYTYPE securityType)
+{
+ return i18n(MyMoneySecurity::securityTypeToString(securityType));
+}
+
+const QString KMyMoneyUtils::occurenceToString(const MyMoneySchedule::occurenceE occurence)
+{
+ return i18n(MyMoneySchedule::occurenceToString(occurence));
+}
+
+const QString KMyMoneyUtils::paymentMethodToString(MyMoneySchedule::paymentTypeE paymentType)
+{
+ return i18n(MyMoneySchedule::paymentMethodToString(paymentType));
+}
+
+const QString KMyMoneyUtils::weekendOptionToString(MyMoneySchedule::weekendOptionE weekendOption)
+{
+ return i18n(MyMoneySchedule::weekendOptionToString(weekendOption));
+}
+
+const QString KMyMoneyUtils::scheduleTypeToString(MyMoneySchedule::typeE type)
+{
+ return i18n(MyMoneySchedule::scheduleTypeToString(type));
+}
+
+KGuiItem KMyMoneyUtils::scheduleNewGuiItem(void)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+
+ KGuiItem splitGuiItem( i18n("&New Schedule..."),
+ QIconSet(ic->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new schedule."),
+ i18n("Use this to create a new schedule."));
+
+ return splitGuiItem;
+}
+
+KGuiItem KMyMoneyUtils::accountsFilterGuiItem(void)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+
+ KGuiItem splitGuiItem( i18n("&Filter"),
+ QIconSet(ic->loadIcon("filter", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Filter out accounts"),
+ i18n("Use this to filter out accounts"));
+
+ return splitGuiItem;
+}
+
+QPixmap KMyMoneyUtils::billScheduleIcon(int size)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+ return ic->loadIcon("billschedule", KIcon::User, size);
+}
+
+QPixmap KMyMoneyUtils::depositScheduleIcon(int size)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+ return ic->loadIcon("depositschedule", KIcon::User, size);
+}
+
+QPixmap KMyMoneyUtils::transferScheduleIcon(int size)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+ return ic->loadIcon("transferschedule", KIcon::User, size);
+}
+
+QPixmap KMyMoneyUtils::scheduleIcon(int size)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+ return ic->loadIcon("schedule", KIcon::User, size);
+}
+
+const char* homePageItems[] = {
+ I18N_NOOP("Payments"),
+ I18N_NOOP("Preferred accounts"),
+ I18N_NOOP("Payment accounts"),
+ I18N_NOOP("Favorite reports"),
+ I18N_NOOP("Forecast (schedule)"),
+ I18N_NOOP("Networth forecast"),
+ I18N_NOOP("Forecast (history)"),
+ I18N_NOOP("Assets and Liabilities"),
+ I18N_NOOP("Budget"),
+ I18N_NOOP("CashFlow"),
+ // insert new items above this comment
+ 0
+};
+
+const QString KMyMoneyUtils::homePageItemToString(const int idx)
+{
+ QString rc;
+ if(abs(idx) > 0 && abs(idx) < static_cast<int>(sizeof(homePageItems)/sizeof(homePageItems[0]))) {
+ rc = i18n(homePageItems[abs(idx-1)]);
+ }
+ return rc;
+}
+
+int KMyMoneyUtils::stringToHomePageItem(const QString& txt)
+{
+ int idx = 0;
+ for(idx = 0; homePageItems[idx] != 0; ++idx) {
+ if(txt == i18n(homePageItems[idx]))
+ return idx+1;
+ }
+ return 0;
+}
+
+bool KMyMoneyUtils::appendCorrectFileExt(QString& str, const QString& strExtToUse)
+{
+ bool rc = false;
+
+ if(!str.isEmpty()) {
+ //find last . delminator
+ int nLoc = str.findRev('.');
+ if(nLoc != -1) {
+ QString strExt, strTemp;
+ strTemp = str.left(nLoc + 1);
+ strExt = str.right(str.length() - (nLoc + 1));
+ if(strExt.find(strExtToUse, 0, FALSE) == -1) {
+ // if the extension given contains a period, we remove our's
+ if(strExtToUse.find('.') != -1)
+ strTemp = strTemp.left(strTemp.length()-1);
+ //append extension to make complete file name
+ strTemp.append(strExtToUse);
+ str = strTemp;
+ rc = true;
+ }
+ } else {
+ str.append(".");
+ str.append(strExtToUse);
+ rc = true;
+ }
+ }
+ return rc;
+}
+
+void KMyMoneyUtils::checkConstants(void)
+{
+ Q_ASSERT(static_cast<int>(KLocale::ParensAround) == static_cast<int>(MyMoneyMoney::ParensAround));
+ Q_ASSERT(static_cast<int>(KLocale::BeforeQuantityMoney) == static_cast<int>(MyMoneyMoney::BeforeQuantityMoney));
+ Q_ASSERT(static_cast<int>(KLocale::AfterQuantityMoney) == static_cast<int>(MyMoneyMoney::AfterQuantityMoney));
+ Q_ASSERT(static_cast<int>(KLocale::BeforeMoney) == static_cast<int>(MyMoneyMoney::BeforeMoney));
+ Q_ASSERT(static_cast<int>(KLocale::AfterMoney) == static_cast<int>(MyMoneyMoney::AfterMoney));
+}
+
+QString KMyMoneyUtils::variableCSS(void)
+{
+ QColor tcolor = KGlobalSettings::textColor();
+
+ QString css;
+ css += "<style type=\"text/css\">\n<!--\n";
+ css += QString(".row-even, .item0 { background-color: %1; color: %2 }\n")
+ .arg((KMyMoneyGlobalSettings::listBGColor()).name()).arg(tcolor.name());
+ css += QString(".row-odd, .item1 { background-color: %1; color: %2 }\n")
+ .arg((KMyMoneyGlobalSettings::listColor()).name()).arg(tcolor.name());
+ css += "-->\n</style>\n";
+ return css;
+}
+
+QString KMyMoneyUtils::findResource(const char* type, const QString& filename)
+{
+ QString language = KGlobal::locale()->language();
+ QString country = KGlobal::locale()->country();
+ QString rc, mask;
+
+ // check that the placeholder is present
+ if(!filename.find("%1")) {
+ qWarning("%%1 not found in '%s'", filename.latin1());
+ return filename;
+ }
+
+ // search the given resource
+ mask = filename.arg("_%1.%2");
+ rc = KGlobal::dirs()->findResource(type, mask.arg(country).arg(language));
+ if(rc.isEmpty()) {
+ mask = filename.arg("_%1");
+ rc = KGlobal::dirs()->findResource(type, mask.arg(language));
+ }
+ if(rc.isEmpty()) {
+ // qDebug(QString("html/home_%1.html not found").arg(country).latin1());
+ rc = KGlobal::dirs()->findResource(type, mask.arg(country));
+ }
+ if(rc.isEmpty()) {
+ rc = KGlobal::dirs()->findResource(type, filename.arg(""));
+ }
+
+ if(rc.isEmpty()) {
+ qWarning("No resource found for (%s,%s)", type, filename.latin1());
+ }
+ return rc;
+}
+
+const MyMoneySplit KMyMoneyUtils::stockSplit(const MyMoneyTransaction& t)
+{
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ MyMoneySplit investmentAccountSplit;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if(!(*it_s).accountId().isEmpty()) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.isInvest()) {
+ return *it_s;
+ }
+ // if we have a reference to an investment account, we remember it here
+ if(acc.accountType() == MyMoneyAccount::Investment)
+ investmentAccountSplit = *it_s;
+ }
+ }
+ // if we haven't found a stock split, we see if we've seen
+ // an investment account on the way. If so, we return it.
+ if(!investmentAccountSplit.id().isEmpty())
+ return investmentAccountSplit;
+
+ // if none was found, we return an empty split.
+ return MyMoneySplit();
+}
+
+KMyMoneyUtils::transactionTypeE KMyMoneyUtils::transactionType(const MyMoneyTransaction& t)
+{
+ if(!stockSplit(t).id().isEmpty())
+ return InvestmentTransaction;
+
+ if(t.splitCount() < 2) {
+ return Unknown;
+ } else if(t.splitCount() > 2) {
+ // FIXME check for loan transaction here
+ return SplitTransaction;
+ }
+ QString ida, idb;
+ ida = t.splits()[0].accountId();
+ idb = t.splits()[1].accountId();
+ if(ida.isEmpty() || idb.isEmpty())
+ return Unknown;
+
+ MyMoneyAccount a, b;
+ a = MyMoneyFile::instance()->account(ida);
+ b = MyMoneyFile::instance()->account(idb);
+ if((a.accountGroup() == MyMoneyAccount::Asset
+ || a.accountGroup() == MyMoneyAccount::Liability)
+ && (b.accountGroup() == MyMoneyAccount::Asset
+ || b.accountGroup() == MyMoneyAccount::Liability))
+ return Transfer;
+ return Normal;
+}
+
+void KMyMoneyUtils::calculateAutoLoan(const MyMoneySchedule& schedule, MyMoneyTransaction& transaction, const QMap<QString, MyMoneyMoney>& balances)
+{
+ try {
+ MyMoneyForecast::calculateAutoLoan(schedule, transaction, balances);
+ } catch (MyMoneyException* e) {
+ KMessageBox::detailedError(0, i18n("Unable to load schedule details"), e->what());
+ delete e;
+ }
+}
+
+QString KMyMoneyUtils::nextCheckNumber(const MyMoneyAccount& acc)
+{
+ // determine next check number
+ QString number;
+ QRegExp exp(QString("(.*\\D)?(\\d+)(\\D.*)?"));
+ if(exp.search(acc.value("lastNumberUsed")) != -1) {
+ number = QString("%1%2%3").arg(exp.cap(1)).arg(exp.cap(2).toULongLong() + 1).arg(exp.cap(3));
+ } else {
+ number = "1";
+ }
+ return number;
+}
+
+QString KMyMoneyUtils::reconcileStateToString(MyMoneySplit::reconcileFlagE flag, bool text)
+{
+ QString txt;
+ if(text) {
+ switch(flag) {
+ case MyMoneySplit::NotReconciled:
+ txt = i18n("Reconcile state 'Not reconciled'", "Not reconciled");
+ break;
+ case MyMoneySplit::Cleared:
+ txt = i18n("Reconcile state 'Cleared'", "Cleared");
+ break;
+ case MyMoneySplit::Reconciled:
+ txt = i18n("Reconcile state 'Reconciled'", "Reconciled");
+ break;
+ case MyMoneySplit::Frozen:
+ txt = i18n("Reconcile state 'Frozen'", "Frozen");
+ break;
+ default:
+ txt = i18n("Unknown");
+ break;
+ }
+ } else {
+ switch(flag) {
+ case MyMoneySplit::NotReconciled:
+ break;
+ case MyMoneySplit::Cleared:
+ txt = i18n("Reconcile flag C", "C");
+ break;
+ case MyMoneySplit::Reconciled:
+ txt = i18n("Reconcile flag R", "R");
+ break;
+ case MyMoneySplit::Frozen:
+ txt = i18n("Reconcile flag F", "F");
+ break;
+ default:
+ txt = i18n("Flag for unknown reconciliation state", "?");
+ break;
+ }
+ }
+ return txt;
+}
+
+MyMoneyTransaction KMyMoneyUtils::scheduledTransaction(const MyMoneySchedule& schedule)
+{
+ MyMoneyTransaction t = schedule.transaction();
+
+ try {
+ if (schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT) {
+ calculateAutoLoan(schedule, t, QMap<QString, MyMoneyMoney>());
+ }
+ } catch (MyMoneyException* e) {
+ qDebug("Unable to load schedule details for '%s' during transaction match: %s", schedule.name().data(), e->what().data());
+ delete e;
+ }
+
+ t.clearId();
+ t.setEntryDate(QDate());
+ return t;
+}
+
+void KMyMoneyUtils::previouslyUsedCategories(const QString& investmentAccount, QString& feesId, QString& interestId)
+{
+ feesId = interestId = QString();
+ MyMoneyFile* file = MyMoneyFile::instance();
+ try {
+ MyMoneyAccount acc = file->account(investmentAccount);
+ MyMoneyTransactionFilter filter(investmentAccount);
+ filter.setReportAllSplits(false);
+ // since we assume an investment account here, we need to collect the stock accounts as well
+ filter.addAccount(acc.accountList());
+ QValueList< QPair<MyMoneyTransaction, MyMoneySplit> > list;
+ file->transactionList(list, filter);
+ QValueList< QPair<MyMoneyTransaction, MyMoneySplit> >::const_iterator it_t;
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ const MyMoneyTransaction& t = (*it_t).first;
+ const MyMoneySplit&s = (*it_t).second;
+ MyMoneySplit assetAccountSplit;
+ QValueList<MyMoneySplit> feeSplits;
+ QValueList<MyMoneySplit> interestSplits;
+ MyMoneySecurity security;
+ MyMoneySecurity currency;
+ MyMoneySplit::investTransactionTypeE transactionType;
+ InvestTransactionEditor::dissectTransaction(t, s, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType);
+ if(feeSplits.count() == 1) {
+ feesId = feeSplits.first().accountId();
+ }
+ if(interestSplits.count() == 1) {
+ interestId = interestSplits.first().accountId();
+ }
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+}
+
+
diff --git a/kmymoney2/kmymoneyutils.h b/kmymoney2/kmymoneyutils.h
new file mode 100644
index 0000000..8acb5c4
--- /dev/null
+++ b/kmymoney2/kmymoneyutils.h
@@ -0,0 +1,382 @@
+/***************************************************************************
+ kmymoneyutils.h - description
+ -------------------
+ begin : Wed Feb 5 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYUTILS_H
+#define KMYMONEYUTILS_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcolor.h>
+#include <qfont.h>
+
+// ----------------------------------------------------------------------------
+// KDE Headers
+
+#include <kguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneytransaction.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KMyMoneyUtils
+{
+public:
+ /**
+ * This enum is used to describe the bits of an account type filter mask.
+ * Each bit is used to define a specific account class. Multiple classes
+ * can be specified by OR'ing multiple entries. The special entry @p last
+ * marks the left most bit in the mask and is used by scanners of this
+ * bitmask to determine the end of processing.
+ */
+ enum categoryTypeE {
+ none = 0x00, ///< no account class selected
+ liability = 0x01, ///< liability accounts selected
+ asset = 0x02, ///< asset accounts selected
+ expense = 0x04, ///< expense accounts selected
+ income = 0x08, ///< income accounts selected
+ equity = 0x10, ///< equity accounts selected
+ last = 0x20 ///< the leftmost bit in the mask
+ };
+
+ enum transactionTypeE {
+ /**
+ * Unknown transaction type (e.g. used for a transaction with only
+ * a single split)
+ */
+ Unknown,
+
+ /**
+ * A 'normal' transaction is one that consists out two splits: one
+ * referencing an income/expense account, the other referencing
+ * an asset/liability account.
+ */
+ Normal,
+
+ /**
+ * A transfer denotes a transaction consisting of two splits.
+ * Both of the splits reference an asset/liability
+ * account.
+ */
+ Transfer,
+
+ /**
+ * Whenever a transaction consists of more than 2 splits,
+ * it is treated as 'split transaction'.
+ */
+ SplitTransaction,
+
+ /**
+ * This transaction denotes a specific transaction where
+ * a loan account is involved. Ususally, a special dialog
+ * is used to modify this transaction.
+ */
+ LoanPayment,
+
+ /**
+ * This transaction denotes a specific transaction where
+ * an investment is involved. Ususally, a special dialog
+ * is used to modify this transaction.
+ */
+ InvestmentTransaction
+ };
+
+ enum EnterScheduleResultCodeE {
+ Cancel = 0, // cancel the operation
+ Enter, // enter the schedule
+ Skip, // skip the schedule
+ Ignore // ignore the schedule
+ };
+
+ static const int maxHomePageItems = 5;
+
+ KMyMoneyUtils();
+ ~KMyMoneyUtils();
+
+ /**
+ * This method is used to convert the internal representation of
+ * an account type into a human readable format
+ *
+ * @param accountType numerical representation of the account type.
+ * For possible values, see MyMoneyAccount::accountTypeE
+ * @return QString representing the human readable form translated according to the language cataglogue
+ *
+ * @sa MyMoneyAccount::accountTypeToString()
+ */
+ static const QString accountTypeToString(const MyMoneyAccount::accountTypeE accountType);
+
+ /**
+ * This method is used to convert an account type from it's
+ * string form to the internal used numeric value.
+ *
+ * @param type reference to a QString containing the string to convert
+ * @return accountTypeE containing the internal used numeric value. For possible
+ * values see MyMoneyAccount::accountTypeE
+ */
+ static MyMoneyAccount::accountTypeE stringToAccountType(const QString& type);
+
+ /**
+ * This method is used to convert a security type from it's
+ * string form to the internal used numeric value.
+ *
+ * @param txt reference to a QString containing the string to convert
+ * @return eSECURITYTYPE containing the internal used numeric value. For possible
+ * values see MyMoneySecurity::eSECURITYTYPE
+ */
+ static MyMoneySecurity::eSECURITYTYPE stringToSecurity(const QString& txt);
+
+ /**
+ * This method is used to convert the internal representation of
+ * an security type into a human readable format
+ *
+ * @param securityType enumerated representation of the security type.
+ * For possible values, see MyMoneySecurity::eSECURITYTYPE
+ * @return QString representing the human readable form translated according to the language cataglogue
+ *
+ * @sa MyMoneySecurity::securityTypeToString()
+ */
+ static const QString securityTypeToString(const MyMoneySecurity::eSECURITYTYPE securityType);
+
+ /**
+ * This method is used to convert the occurence type from it's
+ * internal representation into a human readable format.
+ *
+ * @param occurence numerical representation of the MyMoneySchedule
+ * occurence type
+ *
+ * @return QString representing the human readable format translated according to the language cataglogue
+ *
+ * @sa MyMoneySchedule::occurenceToString()
+ *
+ * @deprecated Use i18n(MyMoneySchedule::occurenceToString(occurence)) instead
+ */
+ static const QString occurenceToString(const MyMoneySchedule::occurenceE occurence);
+
+ /**
+ * This method is used to convert the payment type from it's
+ * internal representation into a human readable format.
+ *
+ * @param paymentType numerical representation of the MyMoneySchedule
+ * payment type
+ *
+ * @return QString representing the human readable format translated according to the language cataglogue
+ *
+ * @sa MyMoneySchedule::paymentMethodToString()
+ */
+ static const QString paymentMethodToString(MyMoneySchedule::paymentTypeE paymentType);
+
+ /**
+ * This method is used to convert the schedule weekend option from it's
+ * internal representation into a human readable format.
+ *
+ * @param weekendOption numerical representation of the MyMoneySchedule
+ * weekend option
+ *
+ * @return QString representing the human readable format translated according to the language cataglogue
+ *
+ * @sa MyMoneySchedule::weekendOptionToString()
+ */
+ static const QString weekendOptionToString(MyMoneySchedule::weekendOptionE weekendOption);
+
+ /**
+ * This method is used to convert the schedule type from it's
+ * internal representation into a human readable format.
+ *
+ * @param type numerical representation of the MyMoneySchedule
+ * schedule type
+ *
+ * @return QString representing the human readable format translated according to the language cataglogue
+ *
+ * @sa MyMoneySchedule::scheduleTypeToString()
+ */
+ static const QString scheduleTypeToString(MyMoneySchedule::typeE type);
+
+ /**
+ * This method is used to convert a numeric index of an item
+ * represented on the home page into it's string form.
+ *
+ * @param idx numeric index of item
+ *
+ * @return QString with text of this item
+ */
+ static const QString homePageItemToString(const int idx);
+
+ /**
+ * This method is used to convert the name of a home page item
+ * to it's internal numerical representation
+ *
+ * @param txt QString reference of the items name
+ *
+ * @retval 0 @p txt is unknown
+ * @retval >0 numeric value for @p txt
+ */
+ static int stringToHomePageItem(const QString& txt);
+
+ /**
+ * Retrieve a KDE KGuiItem for the new schedule button.
+ *
+ * @return The KGuiItem that can be used to display the icon and text
+ */
+ static KGuiItem scheduleNewGuiItem(void);
+
+ /**
+ * Retrieve a KDE KGuiItem for the account filter button
+ *
+ * @return The KGuiItem that can be used to display the icon and text
+ */
+ static KGuiItem accountsFilterGuiItem(void);
+
+ /**
+ * This method adds the file extension passed as argument @p extension
+ * to the end of the file name passed as argument @p name if it is not present.
+ * If @p name contains an extension it will be removed.
+ *
+ * @param name filename to be checked
+ * @param extension extension to be added (w/o the dot)
+ *
+ * @retval true if @p name was changed
+ * @retval false if @p name remained unchanged
+ */
+ static bool appendCorrectFileExt(QString& name, const QString& extension);
+
+ static QPixmap billScheduleIcon(int size);
+ static QPixmap depositScheduleIcon(int size);
+ static QPixmap transferScheduleIcon(int size);
+ static QPixmap scheduleIcon(int size);
+
+ /**
+ * Check that internal MyMoney engine constants use the same
+ * values as the KDE constants.
+ */
+ static void checkConstants(void);
+
+ static QString variableCSS(void);
+
+ /**
+ * This method searches a KDE specific resource and applies country and
+ * language settings during the search. Therefore, the parameter @p filename must contain
+ * the characters '%1' which gets replaced with the language/country values.
+ *
+ * The search is performed in the following order (stopped immediately if a file was found):
+ * - @c \%1 is replaced with <tt>_\<country\>.\<language\></tt>
+ * - @c \%1 is replaced with <tt>_\<language\></tt>
+ * - @c \%1 is replaced with <tt>_\<country\></tt>
+ * - @c \%1 is replaced with the empty string
+ *
+ * @c \<country\> and @c \<language\> denote the respective KDE settings.
+ *
+ * Example: The KDE settings for country is Spain (es) and language is set
+ * to Galician (gl). The code for looking up a file looks like this:
+ *
+ * @code
+ *
+ * :
+ * QString fname = KMyMoneyUtils::findResource("appdata", "html/home%1.html")
+ * :
+ *
+ * @endcode
+ *
+ * The method calls KStandardDirs::findResource() with the following values for the
+ * parameter @p filename:
+ *
+ * - <tt>html/home_es.gl.html</tt>
+ * - <tt>html/home_gl.html</tt>
+ * - <tt>html/home_es.html</tt>
+ * - <tt>html/home.html</tt>
+ *
+ * @note See KStandardDirs::findResource() for details on the parameters
+ */
+ static QString findResource(const char* type, const QString& filename);
+
+ /**
+ * This method returns the split referencing a stock account if
+ * one exists in the transaction passed as @p t. If none is present
+ * in @p t, an empty MyMoneySplit() object will be returned.
+ *
+ * @param t transaction to be checked for a stock account
+ * @return MyMoneySplit object referencing a stock account or an
+ * empty MyMoneySplit object.
+ */
+ static const MyMoneySplit stockSplit(const MyMoneyTransaction& t);
+
+ /**
+ * This method analyses the splits of a transaction and returns
+ * the type of transaction. Possible values are defined by the
+ * KMyMoneyUtils::transactionTypeE enum.
+ *
+ * @param t const reference to the transaction
+ *
+ * @return KMyMoneyUtils::transactionTypeE value of the action
+ */
+ static transactionTypeE transactionType(const MyMoneyTransaction& t);
+
+ /**
+ * This method modifies a scheduled loan transaction such that all
+ * references to automatic calculated values are resolved to actual values.
+ *
+ * @param schedule const reference to the schedule the transaction is based on
+ * @param transaction reference to the transaction to be checked and modified
+ * @param balances QMap of (account-id,balance) pairs to be used as current balance
+ * for the calculation of interest. If map is empty, the engine
+ * will be interrogated for current balances.
+ */
+ static void calculateAutoLoan(const MyMoneySchedule& schedule, MyMoneyTransaction& transaction, const QMap<QString, MyMoneyMoney>& balances);
+
+ /**
+ * Return next check number for account @a acc.
+ */
+ static QString nextCheckNumber(const MyMoneyAccount& acc);
+
+ /**
+ * Returns the text representing the reconcile flag. If @a text is @p true
+ * then the full text will be returned otherwise a short form (usually one character).
+ */
+ static QString reconcileStateToString(MyMoneySplit::reconcileFlagE flag, bool text = false);
+
+ /**
+ * Returns the transaction for @a schedule. In case of a loan payment the
+ * transaction will be modified by calculateAutoLoan().
+ * The ID of the transaction as well as the entryDate will be reset.
+ *
+ * @returns adjusted transaction
+ */
+ static MyMoneyTransaction scheduledTransaction(const MyMoneySchedule& schedule);
+
+ /**
+ * This method tries to figure out the category to be used for fees and interest
+ * from previous transactions in the given @a investmentAccount and returns the
+ * ids of those categories in @a feesId and @a interestId. The last used category
+ * will be returned.
+ */
+ static void previouslyUsedCategories(const QString& investmentAccount, QString& feesId, QString& interestId);
+
+};
+
+#endif
diff --git a/kmymoney2/kstartuplogo.cpp b/kmymoney2/kstartuplogo.cpp
new file mode 100644
index 0000000..566f8ad
--- /dev/null
+++ b/kmymoney2/kstartuplogo.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+ kstartuplogo.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kdecompat.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qapplication.h>
+#include <qpixmap.h>
+#include <qframe.h>
+#include <qpainter.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kstartuplogo.h"
+#include "kmymoneyglobalsettings.h"
+
+class KStartupSplash::Private
+{
+ public:
+ QString message;
+ QColor color;
+ int align;
+};
+
+KStartupSplash::KStartupSplash(const QPixmap &pixmap, WFlags f) :
+ KSplashScreen(pixmap, f),
+ d(new Private)
+{
+}
+
+KStartupSplash::~KStartupSplash()
+{
+ delete d;
+}
+
+void KStartupSplash::message( const QString &message, int alignment, const QColor &color)
+{
+ d->message = message;
+ d->align = alignment;
+ d->color = color;
+ // the next line causes the base class signal management to happen
+ // and also forces a repaint
+ KSplashScreen::clear();
+}
+
+void KStartupSplash::drawContents( QPainter *painter )
+{
+ painter->setPen( d->color );
+ QRect r = rect();
+ r.setRect( r.x() + 15, r.y() + r.height() - 28, r.width() - 20, 20 );
+ painter->drawText( r, d->align, d->message);
+}
+
+KStartupLogo::KStartupLogo() :
+ QObject(0, 0),
+ m_splash(0)
+{
+ // splash screen setting
+ if(!KMyMoneyGlobalSettings::showSplash())
+ return;
+
+ QString filename = KGlobal::dirs()->findResource("appdata", "pics/startlogo.png");
+ QPixmap splashPixmap(filename);
+
+ if(!splashPixmap.isNull()) {
+ QPixmap backGround(splashPixmap);
+ backGround.fill(KGlobalSettings::highlightColor());
+ bitBlt ( &backGround, 0, 0, &splashPixmap, 0, 0, splashPixmap.width(), splashPixmap.height(), Qt::CopyROP );
+
+ KStartupSplash* splash = new KStartupSplash(backGround);
+ splash->setFixedSize(backGround.size());
+
+ // FIXME: I added the 'Loading file...' message here, because this was the only
+ // existing string we have and I did not want to change the strings. We should
+ // change that in the future.
+ splash->message(i18n("Loading..."), AlignLeft, white);
+
+ splash->show();
+ splash->repaint();
+ m_splash = splash;
+ }
+}
+
+KStartupLogo::~KStartupLogo()
+{
+ delete m_splash;
+}
+
+#include "kstartuplogo.moc"
diff --git a/kmymoney2/kstartuplogo.h b/kmymoney2/kstartuplogo.h
new file mode 100644
index 0000000..2d3b305
--- /dev/null
+++ b/kmymoney2/kstartuplogo.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ kstartuplogo.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSTARTUPLOGO_H
+#define KSTARTUPLOGO_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qguardedptr.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <ksplashscreen.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KStartupSplash : public KSplashScreen
+{
+ Q_OBJECT
+ public:
+ KStartupSplash(const QPixmap &pixmap, WFlags f = 0);
+ ~KStartupSplash();
+ void message( const QString &message, int alignment = AlignLeft, const QColor &color = black);
+
+ protected:
+ void drawContents(QPainter *p);
+
+ private:
+ class Private;
+ Private *d;
+};
+
+// Simple class that just shows a picture
+class KStartupLogo : public QObject
+{
+ Q_OBJECT
+public:
+ KStartupLogo();
+ ~KStartupLogo();
+
+private:
+ QGuardedPtr<QWidget> m_splash;
+};
+
+#endif
diff --git a/kmymoney2/lo16-app-kmymoney2.png b/kmymoney2/lo16-app-kmymoney2.png
new file mode 100644
index 0000000..5a245b7
--- /dev/null
+++ b/kmymoney2/lo16-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/lo32-app-kmymoney2.png b/kmymoney2/lo32-app-kmymoney2.png
new file mode 100644
index 0000000..2c094bd
--- /dev/null
+++ b/kmymoney2/lo32-app-kmymoney2.png
Binary files differ
diff --git a/kmymoney2/main.cpp b/kmymoney2/main.cpp
new file mode 100644
index 0000000..008210d
--- /dev/null
+++ b/kmymoney2/main.cpp
@@ -0,0 +1,315 @@
+/***************************************************************************
+ main.cpp
+ -------------------
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidgetlist.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+#include <qeventloop.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <ktip.h>
+#include <dcopclient.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoney/mymoneyfile.h"
+#include "kmymoney2.h"
+#include "kstartuplogo.h"
+#include "kmymoneyutils.h"
+#include "kmymoneyglobalsettings.h"
+
+static const char *description =
+ I18N_NOOP("\nKMyMoney, the Personal Finance Manager for KDE.\n\nPlease consider contributing to this project with code and/or suggestions.");
+
+static KCmdLineOptions options[] =
+{
+ { "lang <lang-code>", I18N_NOOP("language to be used"), 0 },
+ { "n", I18N_NOOP("don't open last used file"), 0},
+ { "timers", I18N_NOOP("enable performance timers"), 0},
+
+#if KMM_DEBUG
+ // The following options are only available when compiled in debug mode
+ { "trace", I18N_NOOP("turn on program traces"), 0},
+ { "dump-actions", I18N_NOOP("dump the names of all defined KAction objects to stdout and quit"), 0},
+#endif
+
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+ { "+[File]", I18N_NOOP("file to open"), 0 },
+ KCmdLineLastOption
+};
+
+QTime timer;
+bool timersOn = false;
+
+KMyMoney2App* kmymoney2;
+
+static KCmdLineArgs* args = 0;
+
+static void _cleanup(void)
+{
+#ifdef _CHECK_MEMORY
+ chkmem.CheckMemoryLeak( false );
+ _CheckMemory_End();
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ timer.start();
+
+ QString feature;
+
+#ifdef _CHECK_MEMORY
+ feature += "\t- " I18N_NOOP("Memory leakage detection") "\n";
+#endif
+
+ if(!feature.isEmpty())
+ feature = I18N_NOOP("Compiled with the following settings:\n") + feature;
+
+ KAboutData aboutData( "kmymoney2", I18N_NOOP("KMyMoney"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 2000-2009 The KMyMoney development team", feature,
+ "http://kmymoney2.sourceforge.net/",
+ "kmymoney2-developer@lists.sourceforge.net");
+
+ aboutData.addAuthor("Michael Edwardes.", I18N_NOOP("Initial idea, much initial source code, Project admin"), "mte@users.sourceforge.net");
+ aboutData.addAuthor("Thomas Baumgart", I18N_NOOP("Core engine, Release Manager, Project admin"), "ipwizard@users.sourceforge.net");
+ aboutData.addAuthor("Ace Jones", I18N_NOOP("Reporting logic, OFX Import"), "acejones@users.sourceforge.net");
+ aboutData.addAuthor("Tony Bloomfield", I18N_NOOP("Database backend, maintainer stable branch"), "tonybloom@users.sourceforge.net");
+ aboutData.addAuthor("Alvaro Soliverez", I18N_NOOP("Forecast, Reports"), "asoliverez@gmail.com");
+ aboutData.addAuthor("Felix Rodriguez", I18N_NOOP("Project Admin"), "frodriguez@users.sourceforge.net");
+ aboutData.addAuthor("John C", I18N_NOOP("Developer"), "tacoturtle@users.sourceforge.net");
+ aboutData.addAuthor("Fernando Vilas", I18N_NOOP("Database backend"), "fvilas@iname.com");
+
+ aboutData.addCredit("Kevin Tambascio", I18N_NOOP("Initial investment support"), "ktambascio@users.sourceforge.net");
+ aboutData.addCredit("Javier Campos Morales", I18N_NOOP("Developer & Artist"), "javi_c@users.sourceforge.net");
+ aboutData.addCredit("Robert Wadley", I18N_NOOP("Icons & splash screen"), "rob@robntina.fastmail.us");
+ aboutData.addCredit("Laurent Montel", I18N_NOOP("Patches"), "montel@kde.org");
+ aboutData.addCredit("Wolfgang Rohdewald", I18N_NOOP("Patches"), "woro@users.sourceforge.net");
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ // create the singletons before we start memory checking
+ // to avoid false error reports
+ MyMoneyFile::instance();
+
+#ifdef _CHECK_MEMORY
+ _CheckMemory_Init(0);
+#endif
+ atexit(_cleanup);
+
+ KMyMoneyUtils::checkConstants();
+
+ KApplication* a = new KApplication();
+
+ if(KGlobal::locale()->monetaryDecimalSymbol().isEmpty()) {
+ KMessageBox::error(0, i18n("The monetary decimal symbol is not correctly set in the KDE Control Center's Country/Region & Language settings. Please set it to a reasonable value and start KMyMoney again."), i18n("Invalid settings"));
+ delete a;
+ exit(1);
+ }
+
+ // show startup logo
+ KStartupLogo* splash = new KStartupLogo();
+ a->processEvents();
+
+ args = KCmdLineArgs::parsedArgs();
+
+ // setup the MyMoneyMoney locale settings according to the KDE settings
+ MyMoneyMoney::setThousandSeparator(*(KGlobal::locale()->monetaryThousandsSeparator().latin1()));
+ MyMoneyMoney::setDecimalSeparator(*(KGlobal::locale()->monetaryDecimalSymbol().latin1()));
+ MyMoneyMoney::setNegativeMonetarySignPosition(static_cast<MyMoneyMoney::signPosition>(KGlobal::locale()->negativeMonetarySignPosition()));
+ MyMoneyMoney::setPositiveMonetarySignPosition(static_cast<MyMoneyMoney::signPosition>(KGlobal::locale()->positiveMonetarySignPosition()));
+ MyMoneyMoney::setNegativePrefixCurrencySymbol(KGlobal::locale()->negativePrefixCurrencySymbol());
+ MyMoneyMoney::setPositivePrefixCurrencySymbol(KGlobal::locale()->positivePrefixCurrencySymbol());
+
+ QCString language = args->getOption("lang");
+ if(!language.isEmpty()) {
+ if(!KGlobal::locale()->setLanguage(language)) {
+ qWarning("Unable to select language '%s'. This has one of two reasons:\n\ta) the standard KDE message catalogue is not installed\n\tb) the KMyMoney message catalogue is not installed", language.data());
+ }
+ }
+
+#if KMM_DEBUG
+ if(args->isSet("trace"))
+ MyMoneyTracer::on();
+ timersOn = args->isSet("timers");
+#endif
+
+ kmymoney2 = 0;
+ kmymoney2 = new KMyMoney2App();
+ a->setMainWidget( kmymoney2 );
+
+#if KMM_DEBUG
+ if(args->isSet("dump-actions")) {
+ kmymoney2->dumpActions();
+
+ // Before we delete the application, we make sure that we destroy all
+ // widgets by running the event loop for some time to catch all those
+ // widgets that are requested to be destroyed using the deleteLater() method.
+ QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 10);
+
+ delete kmymoney2;
+ delete splash;
+ delete a;
+ exit(0);
+ }
+#endif
+
+ int rc = 0;
+ try {
+ do {
+ // connect to DCOP server
+ DCOPClient* client = a->dcopClient();
+ if(client->registerAs("kmymoney", true) != false) {
+ const QCStringList instances = kmymoney2->instanceList();
+ if(instances.count() > 0) {
+
+ // If the user launches a second copy of the app and includes a file to
+ // open, they are probably attempting a "WebConnect" session. In this case,
+ // we'll check to make sure it's an importable file that's passed in, and if so, we'll
+ // notify the primary instance of the file and kill ourselves.
+
+ if(args->count() > 0) {
+ KURL url = args->url(0);
+ if ( kmymoney2->isImportableFile( url.path() ) )
+ {
+ // if there are multiple instances, we'll send this to the first one
+ QCString primary = instances[0];
+
+ // send a message to the primary client to import this file
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url.path();
+ arg << kapp->startupId();
+ if (!client->send(primary, "kmymoney2app", "webConnect(QString,QCString)",data))
+ qDebug("Unable to launch WebConnect via DCOP.");
+
+ // Before we delete the application, we make sure that we destroy all
+ // widgets by running the event loop for some time to catch all those
+ // widgets that are requested to be destroyed using the deleteLater() method.
+ QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 10);
+
+ delete kmymoney2;
+ delete splash;
+ break;
+ }
+ }
+
+ if(KMessageBox::questionYesNo(0, i18n("Another instance of KMyMoney is already running. Do you want to quit?")) == KMessageBox::Yes) {
+ rc = 1;
+ delete kmymoney2;
+ delete splash;
+ break;
+ }
+ }
+ } else {
+ qDebug("DCOP registration failed. Some functions are not available.");
+ }
+
+ kmymoney2->show();
+ kmymoney2->setEnabled(false);
+
+ delete splash;
+
+ // force complete paint of widgets
+ qApp->processEvents();
+
+ QString importfile;
+ KURL url;
+ // make sure, we take the file provided on the command
+ // line before we go and open the last one used
+ if(args->count() > 0) {
+ url = args->url(0);
+
+ // Check to see if this is an importable file, as opposed to a loadable
+ // file. If it is importable, what we really want to do is load the
+ // last used file anyway and then immediately import this file. This
+ // implements a "web connect" session where there is not already an
+ // instance of the program running.
+
+ if ( kmymoney2->isImportableFile( url.path() ) )
+ {
+ importfile = url.path();
+ url = kmymoney2->readLastUsedFile();
+ }
+
+ } else {
+ url = kmymoney2->readLastUsedFile();
+ }
+
+ KTipDialog::showTip(kmymoney2, "", false);
+ if(url.isValid() && !args->isSet("n")) {
+ kmymoney2->slotFileOpenRecent(url);
+ } else if(KMyMoneyGlobalSettings::firstTimeRun()) {
+ kmymoney2->slotFileNew();
+ }
+ KMyMoneyGlobalSettings::setFirstTimeRun(false);
+
+ if ( ! importfile.isEmpty() )
+ kmymoney2->webConnect( importfile, kapp->startupId() );
+
+ if(kmymoney2 != 0) {
+ kmymoney2->updateCaption();
+ args->clear();
+ kmymoney2->setEnabled(true);
+ rc = a->exec();
+ }
+ } while(0);
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedError(0, i18n("Uncaught error. Please report the details to the developers"),
+ QString("%1 in file %2 line %3").arg(e->what()).arg(e->file()).arg(e->line()));
+ throw e;
+ }
+
+ delete a;
+
+ return rc;
+}
+
+void timestamp(char *txt)
+{
+ if(timersOn)
+ {
+ qDebug("Time(%s): %d", txt, timer.elapsed());
+ }
+}
+
+void timetrace(const char *txt)
+{
+ if(timersOn)
+ {
+ qDebug("Timer(%s): %d elapsed", txt, timer.elapsed());
+ timer.restart();
+ }
+}
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mimetype_kmy_128x128.png b/kmymoney2/mimetype_kmy_128x128.png
new file mode 100644
index 0000000..b7b0775
--- /dev/null
+++ b/kmymoney2/mimetype_kmy_128x128.png
Binary files differ
diff --git a/kmymoney2/mimetype_kmy_16x16.png b/kmymoney2/mimetype_kmy_16x16.png
new file mode 100644
index 0000000..6ba3367
--- /dev/null
+++ b/kmymoney2/mimetype_kmy_16x16.png
Binary files differ
diff --git a/kmymoney2/mimetype_kmy_32x32.png b/kmymoney2/mimetype_kmy_32x32.png
new file mode 100644
index 0000000..13a8bd2
--- /dev/null
+++ b/kmymoney2/mimetype_kmy_32x32.png
Binary files differ
diff --git a/kmymoney2/mimetype_kmy_48x48.png b/kmymoney2/mimetype_kmy_48x48.png
new file mode 100644
index 0000000..d362bf4
--- /dev/null
+++ b/kmymoney2/mimetype_kmy_48x48.png
Binary files differ
diff --git a/kmymoney2/mimetype_kmy_64x64.png b/kmymoney2/mimetype_kmy_64x64.png
new file mode 100644
index 0000000..f045903
--- /dev/null
+++ b/kmymoney2/mimetype_kmy_64x64.png
Binary files differ
diff --git a/kmymoney2/misc/Makefile.am b/kmymoney2/misc/Makefile.am
new file mode 100644
index 0000000..d078911
--- /dev/null
+++ b/kmymoney2/misc/Makefile.am
@@ -0,0 +1,19 @@
+KDE_OPTIONS = noautodist
+
+SUBDIRS =
+
+EXTRA_DIST = financequote.pl
+
+LOCAL_DIR = kmymoney2/misc
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)
+ for file in $(EXTRA_DIST); do \
+ $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR); \
+ done
+
+uninstall-local:
+ for file in $(EXTRA_DIST); do \
+ rm -f $(DESTDIR)$(kde_datadir)/$(LOCAL_DIR)/$$file; \
+ done
+
diff --git a/kmymoney2/misc/financequote.pl b/kmymoney2/misc/financequote.pl
new file mode 100644
index 0000000..201c342
--- /dev/null
+++ b/kmymoney2/misc/financequote.pl
@@ -0,0 +1,117 @@
+######################################################################
+### financequote.pl - KMyMoney interface to Finance::Quote
+###
+### derived from GnuCash finance-quote-helper script which is
+### Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
+###
+### This program is free software; you can redistribute it and/or
+### modify it under the terms of the GNU General Public License as
+### published by the Free Software Foundation; either version 2 of
+### the License, or (at your option) any later version.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program# if not, contact:
+###
+### Free Software Foundation Voice: +1-617-542-5942
+### 59 Temple Place - Suite 330 Fax: +1-617-542-2652
+### Boston, MA 02111-1307, USA gnu@gnu.org
+######################################################################
+
+use diagnostics; # while testing
+use strict;
+use Data::Dumper;
+
+my $prgnam = "kmymoneyfq.pl";
+my $version = "1.00";
+# perl modules required by this routine and Finance::Quote
+my @modules = qw(Date::Manip Finance::Quote LWP XML::Parser XML::Writer);
+
+# main - check command line arguments
+
+my $testonly;
+my $listonly;
+# analyze the arguments
+foreach my $arg (@ARGV) {
+ my $listopt = "-l"; # I had a much slicker way of doing this but it stopped working...
+ my $testopt = "-t";
+ $testonly = 1 if $arg =~ $testopt;
+ $listonly = 1 if $arg =~ $listopt;
+}
+
+# test call; check that all required modules are present
+if ($testonly) {
+ my @absent_modules; # to build list of missing modules
+
+ foreach my $module (@modules) {
+ if (!eval "require $module") {
+ push (@absent_modules, $module);
+ }
+ }
+ if (@absent_modules) {
+ foreach my $module (@absent_modules) {
+ print STDERR " ".$module."\n";
+ }
+ exit 254; # missing modules exit code for kmymoney
+ }
+ exit 0;
+}
+
+# load the required modules
+foreach my $module (@modules) {
+ eval "require $module";
+ $module->import();
+}
+
+# create a finance quote object and set required parameters
+my $q = Finance::Quote->new();
+$q->set_currency(); # disable any currency conversion
+$q->timeout(60); # timeout 60 seconds
+$q->failover(0); # disable failover
+
+# process call for exchange list only
+if ($listonly) {
+ my @sources = $q->sources();
+ foreach my $source (@sources) {
+ print "$source\n";
+ }
+ exit 0;
+}
+
+my $source = $ARGV[0];
+my $symbol = $ARGV[1];
+
+#print "\tfinding price for <$symbol> from <$source>\n";
+my %qhash = $q->fetch($source, $symbol); # get price data from F::Q
+#my %qhash = ("RHATsuccess" => 1, "RHATdate" => "4/4/2004", "RHATcurrency" => "USD",
+ #"RHATbid" => "25.55", "RHATask" => "26.04");
+#print Dumper(%qhash);
+my $errcode;
+$errcode = 0;
+
+if (!%qhash) { $errcode = 1;} # no data from fq (?bad exchange?)
+ elsif ($qhash {$symbol, "success"} != 1) {$errcode = 2;} # got data but quote failed (?bad symbol?)
+ elsif (!$qhash{$symbol, "last"}) {$errcode = 3;} # can't find a price (?hmmm?)
+if ($errcode != 0) {
+ print "Error " => "$errcode";
+} else {
+ # extract the date and convert from m/d/yyyy to yyyy-mm-dd
+ my ($usdate, $month, $day, $year, $yyyymmdd);
+ $usdate = $qhash{$symbol, "date"};
+ ($month,$day,$year) = ($usdate =~ /([0-9]+)\/([0-9]+)\/([0-9]+)/);
+ # i'm sure I can do the folowing with a regex but I'm just too idle...
+ $month = "0$month" if ($month < 9);
+ $day = "0$day" if ($day < 9);
+ $yyyymmdd = "$year-$month-$day";
+ # and the price
+ # (tried having bid and ask here, but could be undef for some stocks (IBM)
+ # and looked pretty unrealistic for others (e.g. RHAT on 15/5/04 was 12.09-38.32!))
+ my $price = $qhash {$symbol, "last"};
+
+ print "\"$symbol\",\"$yyyymmdd\",\"$price\"";
+}
+
diff --git a/kmymoney2/mymoney/Makefile.am b/kmymoney2/mymoney/Makefile.am
new file mode 100644
index 0000000..84ec924
--- /dev/null
+++ b/kmymoney2/mymoney/Makefile.am
@@ -0,0 +1,50 @@
+KDE_OPTIONS = noautodist
+
+#
+# The LIBVERSION setting controls the libtool versioning system for shared
+# libraries. It is constructed out of the triplet CURRENT:REVISION:AGE.
+#
+# Here are the rules on howto update the version info:
+#
+# 1. Update the version information only immediately before a public
+# release of your software. More frequent updates are unnecessary,
+# and only guarantee that the current interface number gets larger
+# faster.
+#
+# 2. If the library source code has changed at all since the last
+# update, then increment REVISION (`C:R:A' becomes `C:r+1:A').
+#
+# 3. If any interfaces have been added, removed, or changed since the
+# last update, increment CURRENT, and set REVISION to 0.
+#
+# 4. If any interfaces have been added since the last public release,
+# then increment AGE.
+#
+# 5. If any interfaces have been removed since the last public release,
+# then set AGE to 0.
+#
+# The above information is copied from 'info libtool'.
+
+LIBVERSION=5:0:0
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+lib_LTLIBRARIES = libkmm_mymoney.la
+
+libkmm_mymoney_la_METASOURCES = AUTO
+
+libkmm_mymoney_la_SOURCES = mymoneymoney.cpp mymoneyfinancialcalculator.cpp mymoneytransactionfilter.cpp mymoneyobject.cpp mymoneykeyvaluecontainer.cpp mymoneyobserver.cpp mymoneysubject.cpp mymoneysplit.cpp mymoneyinstitution.cpp mymoneyexception.cpp mymoneyinvesttransaction.cpp mymoneyutils.cpp mymoneysecurity.cpp mymoneytransaction.cpp mymoneyscheduled.cpp mymoneypayee.cpp mymoneyfile.cpp mymoneycategory.cpp mymoneyaccount.cpp mymoneyreport.cpp mymoneystatement.cpp mymoneyprice.cpp mymoneybudget.cpp mymoneyobjectcontainer.cpp mymoneyforecast.cpp
+libkmm_mymoney_la_LDFLAGS = $(all_libraries) -version-info $(LIBVERSION)
+
+SUBDIRS = storage
+
+instdir=$(includedir)/kmymoney
+inst_HEADERS = mymoneyobject.h mymoneyaccount.h mymoneycategory.h mymoneyexception.h mymoneyfile.h mymoneyfinancialcalculator.h mymoneyinstitution.h mymoneyinvesttransaction.h mymoneykeyvaluecontainer.h mymoneymoney.h mymoneyobserver.h mymoneypayee.h mymoneyprice.h mymoneyreport.h mymoneyscheduled.h mymoneysecurity.h mymoneysplit.h mymoneystatement.h mymoneysubject.h mymoneytransactionfilter.h mymoneytransaction.h mymoneyutils.h mymoneybudget.h mymoneyobjectcontainer.h mymoneyforecast.h
+
+noinst_HEADERS = autotest.h mymoneyaccounttest.h mymoneyfinancialcalculatortest.h mymoneykeyvaluecontainertest.h mymoneyexceptiontest.h mymoneyfiletest.h mymoneyinstitutiontest.h mymoneymoneytest.h mymoneyobservertest.h mymoneyscheduletest.h mymoneysplittest.h mymoneysecuritytest.h mymoneytransactiontest.h mymoneypricetest.h mymoneyobjecttest.h mymoneyforecasttest.h mymoneypayeetest.h
+
+if CPPUNIT
+check_LIBRARIES = libmymoneytest.a
+
+libmymoneytest_a_SOURCES = mymoneytransactiontest.cpp mymoneysplittest.cpp mymoneymoneytest.cpp mymoneyfiletest.cpp mymoneyaccounttest.cpp mymoneyexceptiontest.cpp mymoneyinstitutiontest.cpp mymoneykeyvaluecontainertest.cpp mymoneyscheduletest.cpp mymoneyfinancialcalculatortest.cpp mymoneysecuritytest.cpp mymoneypricetest.cpp mymoneyobjecttest.cpp mymoneyforecasttest.cpp mymoneypayeetest.cpp
+endif
+
diff --git a/kmymoney2/mymoney/autotest.h b/kmymoney2/mymoney/autotest.h
new file mode 100644
index 0000000..31b372f
--- /dev/null
+++ b/kmymoney2/mymoney/autotest.h
@@ -0,0 +1,24 @@
+/***************************************************************************
+ autotest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __AUTOTEST_H
+#define __AUTOTEST_H
+
+#include "mymoneyexception.h"
+
+void unexpectedException(MyMoneyException *e);
+
+#endif // __AUTOTEST_H
diff --git a/kmymoney2/mymoney/mymoneyaccount.cpp b/kmymoney2/mymoney/mymoneyaccount.cpp
new file mode 100644
index 0000000..8c304cd
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyaccount.cpp
@@ -0,0 +1,744 @@
+/***************************************************************************
+ mymoneyaccount.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ (C) 2002 by Thomas Baumagrt
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregexp.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyexception.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneysplit.h>
+
+MyMoneyAccount::MyMoneyAccount() :
+ m_fraction(-1)
+{
+ m_accountType = UnknownAccountType;
+}
+
+MyMoneyAccount::~MyMoneyAccount()
+{
+}
+
+MyMoneyAccount::MyMoneyAccount(const QString& id, const MyMoneyAccount& right) :
+ MyMoneyObject(id)
+{
+ *this = right;
+ setId(id);
+}
+
+MyMoneyAccount::MyMoneyAccount(const QDomElement& node) :
+ MyMoneyObject(node),
+ MyMoneyKeyValueContainer(node.elementsByTagName("KEYVALUEPAIRS").item(0).toElement()),
+ m_fraction(-1)
+{
+ if("ACCOUNT" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not ACCOUNT");
+
+ setName(node.attribute("name"));
+
+ // qDebug("Reading information for account %s", acc.name().data());
+
+ setParentAccountId(QStringEmpty(node.attribute("parentaccount")));
+ setLastModified(stringToDate(QStringEmpty(node.attribute("lastmodified"))));
+ setLastReconciliationDate(stringToDate(QStringEmpty(node.attribute("lastreconciled"))));
+
+ if(!m_lastReconciliationDate.isValid()) {
+ // for some reason, I was unable to access our own kvp at this point through
+ // the value() method. It always returned empty strings. The workaround for
+ // this is to construct a local kvp the same way as we have done before and
+ // extract the value from it.
+ //
+ // Since we want to get rid of the lastStatementDate record anyway, this seems
+ // to be ok for now. (ipwizard - 2008-08-14)
+ QString txt = MyMoneyKeyValueContainer(node.elementsByTagName("KEYVALUEPAIRS").item(0).toElement()).value("lastStatementDate");
+ if(!txt.isEmpty()) {
+ setLastReconciliationDate(QDate::fromString(txt, Qt::ISODate));
+ }
+ }
+
+ setInstitutionId(QStringEmpty(node.attribute("institution")));
+ setNumber(QStringEmpty(node.attribute("number")));
+ setOpeningDate(stringToDate(QStringEmpty(node.attribute("opened"))));
+ setCurrencyId(QStringEmpty(node.attribute("currency")));
+
+ QString tmp = QStringEmpty(node.attribute("type"));
+ bool bOK = false;
+ int type = tmp.toInt(&bOK);
+ if(bOK) {
+ setAccountType(static_cast<MyMoneyAccount::accountTypeE>(type));
+ } else {
+ qWarning("XMLREADER: Account %s had invalid or no account type information.", name().data());
+ }
+
+ if(node.hasAttribute("openingbalance")) {
+ if(!MyMoneyMoney(node.attribute("openingbalance")).isZero()) {
+ QString msg = i18n("Account %1 contains an opening balance. Please use a KMyMoney version >= 0.8 and < 0.9 to correct the problem.").arg(m_name);
+ throw new MYMONEYEXCEPTION(msg);
+ }
+ }
+ setDescription(node.attribute("description"));
+
+ m_id = QStringEmpty(node.attribute("id"));
+ // qDebug("Account %s has id of %s, type of %d, parent is %s.", acc.name().data(), id.data(), type, acc.parentAccountId().data());
+
+ // Process any Sub-Account information found inside the account entry.
+ m_accountList.clear();
+ QDomNodeList nodeList = node.elementsByTagName("SUBACCOUNTS");
+ if(nodeList.count() > 0) {
+ nodeList = nodeList.item(0).toElement().elementsByTagName("SUBACCOUNT");
+ for(unsigned int i = 0; i < nodeList.count(); ++i) {
+ addAccountId(QString(nodeList.item(i).toElement().attribute("id")));
+ }
+ }
+
+ nodeList = node.elementsByTagName("ONLINEBANKING");
+ if(nodeList.count() > 0) {
+ QDomNamedNodeMap attributes = nodeList.item(0).toElement().attributes();
+ for(unsigned int i = 0; i < attributes.count(); ++i) {
+ const QDomAttr& it_attr = attributes.item(i).toAttr();
+ m_onlineBankingSettings.setValue(it_attr.name().utf8(), it_attr.value());
+ }
+ }
+
+}
+
+void MyMoneyAccount::setName(const QString& name)
+{
+ m_name = name;
+}
+
+void MyMoneyAccount::setNumber(const QString& number)
+{
+ m_number = number;
+}
+
+void MyMoneyAccount::setDescription(const QString& desc)
+{
+ m_description = desc;
+}
+
+void MyMoneyAccount::setInstitutionId(const QString& id)
+{
+ m_institution = id;
+}
+
+void MyMoneyAccount::setLastModified(const QDate& date)
+{
+ m_lastModified = date;
+}
+
+void MyMoneyAccount::setOpeningDate(const QDate& date)
+{
+ m_openingDate = date;
+}
+
+void MyMoneyAccount::setLastReconciliationDate(const QDate& date)
+{
+ // FIXME: for a limited time (maybe until we delivered 1.0) we
+ // keep the last reconciliation date also in the KVP for backward
+ // compatability. After that, the setValue() statemetn should be removed
+ // and the XML ctor should remove the value completely from the KVP
+ setValue("lastStatementDate", date.toString(Qt::ISODate));
+ m_lastReconciliationDate = date;
+}
+
+void MyMoneyAccount::setParentAccountId(const QString& parent)
+{
+ m_parentAccount = parent;
+}
+
+void MyMoneyAccount::setAccountType(const accountTypeE type)
+{
+ m_accountType = type;
+}
+
+void MyMoneyAccount::addAccountId(const QString& account)
+{
+ if(!m_accountList.contains(account))
+ m_accountList += account;
+}
+
+void MyMoneyAccount::removeAccountIds(void)
+{
+ m_accountList.clear();
+}
+
+void MyMoneyAccount::removeAccountId(const QString& account)
+{
+ QStringList::Iterator it;
+
+ it = m_accountList.find(account);
+ if(it != m_accountList.end())
+ m_accountList.remove(it);
+}
+
+MyMoneyAccount::accountTypeE MyMoneyAccount::accountGroup(MyMoneyAccount::accountTypeE type)
+{
+ switch(type) {
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::Currency:
+ case MyMoneyAccount::Investment:
+ case MyMoneyAccount::MoneyMarket:
+ case MyMoneyAccount::CertificateDep:
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Stock:
+ return MyMoneyAccount::Asset;
+
+ case MyMoneyAccount::CreditCard:
+ case MyMoneyAccount::Loan:
+ return MyMoneyAccount::Liability;
+
+ default:
+ return type;
+ }
+}
+
+bool MyMoneyAccount::operator == (const MyMoneyAccount& right) const
+{
+ return (MyMoneyKeyValueContainer::operator==(right) &&
+ MyMoneyObject::operator==(right) &&
+ (m_accountList == right.m_accountList) &&
+ (m_accountType == right.m_accountType) &&
+ (m_lastModified == right.m_lastModified) &&
+ (m_lastReconciliationDate == right.m_lastReconciliationDate) &&
+ ((m_name.length() == 0 && right.m_name.length() == 0) || (m_name == right.m_name)) &&
+ ((m_number.length() == 0 && right.m_number.length() == 0) || (m_number == right.m_number)) &&
+ ((m_description.length() == 0 && right.m_description.length() == 0) || (m_description == right.m_description)) &&
+ (m_openingDate == right.m_openingDate) &&
+ (m_parentAccount == right.m_parentAccount) &&
+ (m_currencyId == right.m_currencyId) &&
+ (m_institution == right.m_institution) );
+}
+
+MyMoneyAccount::accountTypeE MyMoneyAccount::accountGroup(void) const
+{
+ return accountGroup(m_accountType);
+}
+
+void MyMoneyAccount::setCurrencyId(const QString& id)
+{
+ m_currencyId = id;
+}
+
+bool MyMoneyAccount::isAssetLiability(void) const
+{
+ return accountGroup() == Asset || accountGroup() == Liability;
+}
+
+bool MyMoneyAccount::isIncomeExpense(void) const
+{
+ return accountGroup() == Income || accountGroup() == Expense;
+}
+
+bool MyMoneyAccount::isLoan(void) const
+{
+ return accountType() == Loan || accountType() == AssetLoan;
+}
+
+bool MyMoneyAccount::isInvest(void) const
+{
+ return accountType() == Stock;
+}
+
+
+MyMoneyAccountLoan::MyMoneyAccountLoan(const MyMoneyAccount& acc)
+ : MyMoneyAccount(acc)
+{
+}
+
+const MyMoneyMoney MyMoneyAccountLoan::loanAmount(void) const
+{
+ return MyMoneyMoney(value("loan-amount"));
+}
+
+void MyMoneyAccountLoan::setLoanAmount(const MyMoneyMoney& amount)
+{
+ setValue("loan-amount", amount.toString());
+}
+
+const MyMoneyMoney MyMoneyAccountLoan::interestRate(const QDate& date) const
+{
+ MyMoneyMoney rate;
+ QString key;
+ QString val;
+
+ if(!date.isValid())
+ return rate;
+
+ key.sprintf("ir-%04d-%02d-%02d", date.year(), date.month(), date.day());
+
+ QRegExp regExp("ir-(\\d{4})-(\\d{2})-(\\d{2})");
+
+ QMap<QString, QString>::ConstIterator it;
+
+ for(it = pairs().begin(); it != pairs().end(); ++it) {
+ if(regExp.search(it.key()) > -1) {
+ if(qstrcmp(it.key(),key) <= 0)
+ val = *it;
+ else
+ break;
+
+ } else if(!val.isEmpty())
+ break;
+ }
+
+ if(!val.isEmpty()) {
+ rate = MyMoneyMoney(val);
+ }
+
+ return rate;
+}
+
+void MyMoneyAccountLoan::setInterestRate(const QDate& date, const MyMoneyMoney& value)
+{
+ if(!date.isValid())
+ return;
+
+ QString key;
+ key.sprintf("ir-%04d-%02d-%02d", date.year(), date.month(), date.day());
+ setValue(key, value.toString());
+}
+
+MyMoneyAccountLoan::interestDueE MyMoneyAccountLoan::interestCalculation(void) const
+{
+ QString payTime(value("interest-calculation"));
+ if(payTime == "paymentDue")
+ return paymentDue;
+ return paymentReceived;
+}
+
+void MyMoneyAccountLoan::setInterestCalculation(const MyMoneyAccountLoan::interestDueE onReception)
+{
+ if(onReception == paymentDue)
+ setValue("interest-calculation", "paymentDue");
+ else
+ setValue("interest-calculation", "paymentReceived");
+}
+
+const QDate MyMoneyAccountLoan::nextInterestChange(void) const
+{
+ QDate rc;
+
+ QRegExp regExp("(\\d{4})-(\\d{2})-(\\d{2})");
+ if(regExp.search(value("interest-nextchange")) != -1) {
+ rc.setYMD(regExp.cap(1).toInt(), regExp.cap(2).toInt(), regExp.cap(3).toInt());
+ }
+ return rc;
+}
+
+void MyMoneyAccountLoan::setNextInterestChange(const QDate& date)
+{
+ setValue("interest-nextchange", date.toString(Qt::ISODate));
+}
+
+int MyMoneyAccountLoan::interestChangeFrequency(int* unit) const
+{
+ int rc = -1;
+
+ if(unit)
+ *unit = 1;
+
+ QRegExp regExp("(\\d+)/(\\d{1})");
+ if(regExp.search(value("interest-changefrequency")) != -1) {
+ rc = regExp.cap(1).toInt();
+ if(unit != 0) {
+ *unit = regExp.cap(2).toInt();
+ }
+ }
+ return rc;
+}
+
+void MyMoneyAccountLoan::setInterestChangeFrequency(const int amount, const int unit)
+{
+ QString val;
+ val.sprintf("%d/%d", amount, unit);
+ setValue("interest-changeFrequency", val);
+}
+
+const QString MyMoneyAccountLoan::schedule(void) const
+{
+ return QString(value("schedule").latin1());
+}
+
+void MyMoneyAccountLoan::setSchedule(const QString& sched)
+{
+ setValue("schedule", sched);
+}
+
+bool MyMoneyAccountLoan::fixedInterestRate(void) const
+{
+ // make sure, that an empty kvp element returns true
+ return !(value("fixed-interest") == "no");
+}
+
+void MyMoneyAccountLoan::setFixedInterestRate(const bool fixed)
+{
+ setValue("fixed-interest", fixed ? "yes" : "no");
+ if(fixed) {
+ deletePair("interest-nextchange");
+ deletePair("interest-changeFrequency");
+ }
+}
+
+const MyMoneyMoney MyMoneyAccountLoan::finalPayment(void) const
+{
+ return MyMoneyMoney(value("final-payment"));
+}
+
+void MyMoneyAccountLoan::setFinalPayment(const MyMoneyMoney& finalPayment)
+{
+ setValue("final-payment", finalPayment.toString());
+}
+
+unsigned int MyMoneyAccountLoan::term(void) const
+{
+ return value("term").toUInt();
+}
+
+void MyMoneyAccountLoan::setTerm(const unsigned int payments)
+{
+ setValue("term", QString::number(payments));
+}
+
+const MyMoneyMoney MyMoneyAccountLoan::periodicPayment(void) const
+{
+ return MyMoneyMoney(value("periodic-payment"));
+}
+
+void MyMoneyAccountLoan::setPeriodicPayment(const MyMoneyMoney& payment)
+{
+ setValue("periodic-payment", payment.toString());
+}
+
+const QString MyMoneyAccountLoan::payee(void) const
+{
+ return value("payee");
+}
+
+void MyMoneyAccountLoan::setPayee(const QString& payee)
+{
+ setValue("payee", payee);
+}
+
+const QString MyMoneyAccountLoan::interestAccountId(void) const
+{
+ return QString();
+}
+
+void MyMoneyAccountLoan::setInterestAccountId(const QString& /* id */)
+{
+
+}
+
+bool MyMoneyAccountLoan::hasReferenceTo(const QString& id) const
+{
+ return MyMoneyAccount::hasReferenceTo(id)
+ || (id == payee())
+ || (id == schedule());
+}
+
+void MyMoneyAccountLoan::setInterestCompounding(int frequency)
+{
+ setValue("compoundingFrequency", QString("%1").arg(frequency));
+}
+
+int MyMoneyAccountLoan::interestCompounding(void) const
+{
+ return value("compoundingFrequency").toInt();
+}
+
+void MyMoneyAccount::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("ACCOUNT");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("parentaccount", parentAccountId());
+ el.setAttribute("lastreconciled", dateToString(lastReconciliationDate()));
+ el.setAttribute("lastmodified", dateToString(lastModified()));
+ el.setAttribute("institution", institutionId());
+ el.setAttribute("opened", dateToString(openingDate()));
+ el.setAttribute("number", number());
+ // el.setAttribute("openingbalance", openingBalance().toString());
+ el.setAttribute("type", accountType());
+ el.setAttribute("name", name());
+ el.setAttribute("description", description());
+ if(!currencyId().isEmpty())
+ el.setAttribute("currency", currencyId());
+
+ //Add in subaccount information, if this account has subaccounts.
+ if(accountCount())
+ {
+ QDomElement subAccounts = document.createElement("SUBACCOUNTS");
+ QStringList::ConstIterator it;
+ for(it = accountList().begin(); it != accountList().end(); ++it)
+ {
+ QDomElement temp = document.createElement("SUBACCOUNT");
+ temp.setAttribute("id", (*it));
+ subAccounts.appendChild(temp);
+ }
+
+ el.appendChild(subAccounts);
+ }
+
+ // Write online banking settings
+ if(m_onlineBankingSettings.pairs().count()) {
+ QDomElement onlinesettings = document.createElement("ONLINEBANKING");
+ QMap<QString,QString>::const_iterator it_key = m_onlineBankingSettings.pairs().begin();
+ while ( it_key != m_onlineBankingSettings.pairs().end() ) {
+ onlinesettings.setAttribute(it_key.key(), it_key.data());
+ ++it_key;
+ }
+ el.appendChild(onlinesettings);
+ }
+
+ // FIXME drop the lastStatementDate record from the KVP when it is
+ // not stored there after setLastReconciliationDate() has been changed
+ // See comment there when this will happen
+ // deletePair("lastStatementDate");
+
+
+ //Add in Key-Value Pairs for accounts.
+ MyMoneyKeyValueContainer::writeXML(document, el);
+
+ parent.appendChild(el);
+}
+
+bool MyMoneyAccount::hasReferenceTo(const QString& id) const
+{
+ return (id == m_institution) || (id == m_parentAccount) || (id == m_currencyId);
+}
+
+void MyMoneyAccount::setOnlineBankingSettings(const MyMoneyKeyValueContainer& values)
+{
+ m_onlineBankingSettings = values;
+}
+
+const MyMoneyKeyValueContainer& MyMoneyAccount::onlineBankingSettings(void) const
+{
+ return m_onlineBankingSettings;
+}
+
+void MyMoneyAccount::setClosed(bool closed)
+{
+ if(closed)
+ setValue("mm-closed", "yes");
+ else
+ deletePair("mm-closed");
+}
+
+bool MyMoneyAccount::isClosed(void) const
+{
+ return !(value("mm-closed").isEmpty());
+}
+
+int MyMoneyAccount::fraction(const MyMoneySecurity& sec) const
+{
+ int fraction;
+ if(m_accountType == Cash)
+ fraction = sec.smallestCashFraction();
+ else
+ fraction = sec.smallestAccountFraction();
+ return fraction;
+}
+
+int MyMoneyAccount::fraction(const MyMoneySecurity& sec)
+{
+ if(m_accountType == Cash)
+ m_fraction = sec.smallestCashFraction();
+ else
+ m_fraction = sec.smallestAccountFraction();
+ return m_fraction;
+}
+
+int MyMoneyAccount::fraction(void) const
+{
+ Q_ASSERT(m_fraction != -1);
+
+ return m_fraction;
+}
+
+bool MyMoneyAccount::isCategory(void) const
+{
+ return m_accountType == Income || m_accountType == Expense;
+}
+
+QString MyMoneyAccount::brokerageName(void) const
+{
+ if(m_accountType == Investment)
+ return QString("%1 (%2)").arg(m_name, i18n("Brokerage (suffix for account names)", "Brokerage"));
+ return m_name;
+}
+
+void MyMoneyAccount::adjustBalance(const MyMoneySplit& s, bool reverse)
+{
+ if(s.action() == MyMoneySplit::ActionSplitShares) {
+ if(reverse)
+ m_balance = m_balance / s.shares();
+ else
+ m_balance = m_balance * s.shares();
+ } else {
+ if(reverse)
+ m_balance -= s.shares();
+ else
+ m_balance += s.shares();
+ }
+
+}
+
+QPixmap MyMoneyAccount::accountPixmap(bool reconcileFlag, int size) const
+{
+ QString icon;
+ switch(accountType()) {
+ default:
+ if(accountGroup() == MyMoneyAccount::Asset)
+ icon = "account-types_asset";
+ else
+ icon = "account-types_liability";
+ break;
+
+ case MyMoneyAccount::Investment:
+ case MyMoneyAccount::Stock:
+ case MyMoneyAccount::MoneyMarket:
+ case MyMoneyAccount::CertificateDep:
+ icon = "account-types_investments";
+ break;
+
+ case MyMoneyAccount::Checkings:
+ icon = "account-types_checking";
+ break;
+ case MyMoneyAccount::Savings:
+ icon = "account-types_savings";
+ break;
+
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Loan:
+ icon = "account-types_loan";
+ break;
+
+ case MyMoneyAccount::CreditCard:
+ icon = "account-types_credit-card";
+ break;
+
+ case MyMoneyAccount::Asset:
+ icon = "account-types_asset";
+ break;
+
+ case MyMoneyAccount::Cash:
+ icon = "account-types_cash";
+ break;
+
+ case MyMoneyAccount::Income:
+ icon = "account-types_income";
+ break;
+
+ case MyMoneyAccount::Expense:
+ icon = "account-types_expense";
+ break;
+
+ case MyMoneyAccount::Equity:
+ icon = "account";
+ break;
+ }
+
+ QPixmap result = DesktopIcon(icon, size);
+ if(isClosed()) {
+ QPixmap ovly = DesktopIcon("account-types_closed", size);
+ bitBlt(&result, 0, 0, &ovly, 0, 0, ovly.width(), ovly.height(), Qt::CopyROP, false);
+ } else if(reconcileFlag) {
+ QPixmap ovly = DesktopIcon("account-types_reconcile.png", size);
+ bitBlt(&result, 0, 0, &ovly, 0, 0, ovly.width(), ovly.height(), Qt::CopyROP, false);
+ } else if(!onlineBankingSettings().value("provider").isEmpty()) {
+ QPixmap ovly = DesktopIcon("account-types_online.png", size);
+ bitBlt(&result, 0, 0, &ovly, 0, 0, ovly.width(), ovly.height(), Qt::CopyROP, false);
+ }
+ return result;
+}
+
+QString MyMoneyAccount::accountTypeToString(const MyMoneyAccount::accountTypeE accountType)
+{
+ QString returnString;
+
+ switch (accountType) {
+ case MyMoneyAccount::Checkings:
+ returnString = i18n("Checking");
+ break;
+ case MyMoneyAccount::Savings:
+ returnString = i18n("Savings");
+ break;
+ case MyMoneyAccount::CreditCard:
+ returnString = i18n("Credit Card");
+ break;
+ case MyMoneyAccount::Cash:
+ returnString = i18n("Cash");
+ break;
+ case MyMoneyAccount::Loan:
+ returnString = i18n("Loan");
+ break;
+ case MyMoneyAccount::CertificateDep:
+ returnString = i18n("Certificate of Deposit");
+ break;
+ case MyMoneyAccount::Investment:
+ returnString = i18n("Investment");
+ break;
+ case MyMoneyAccount::MoneyMarket:
+ returnString = i18n("Money Market");
+ break;
+ case MyMoneyAccount::Asset:
+ returnString = i18n("Asset");
+ break;
+ case MyMoneyAccount::Liability:
+ returnString = i18n("Liability");
+ break;
+ case MyMoneyAccount::Currency:
+ returnString = i18n("Currency");
+ break;
+ case MyMoneyAccount::Income:
+ returnString = i18n("Income");
+ break;
+ case MyMoneyAccount::Expense:
+ returnString = i18n("Expense");
+ break;
+ case MyMoneyAccount::AssetLoan:
+ returnString = i18n("Investment Loan");
+ break;
+ case MyMoneyAccount::Stock:
+ returnString = i18n("Stock");
+ break;
+ case MyMoneyAccount::Equity:
+ returnString = i18n("Equity");
+ break;
+ default:
+ returnString = i18n("Unknown");
+ }
+
+ return returnString;
+}
diff --git a/kmymoney2/mymoney/mymoneyaccount.h b/kmymoney2/mymoney/mymoneyaccount.h
new file mode 100644
index 0000000..333c500
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyaccount.h
@@ -0,0 +1,692 @@
+/***************************************************************************
+ mymoneyaccount.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYACCOUNT_H
+#define MYMONEYACCOUNT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <qdom.h>
+#include <qpixmap.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/export.h>
+#include "mymoneyutils.h"
+class MyMoneyTransaction;
+class MyMoneyInstitution;
+class MyMoneySplit;
+class MyMoneyObjectContainer;
+
+/**
+ * A representation of an account.
+ * This object represents any type of account, those held at an
+ * institution as well as the accounts used for double entry
+ * accounting.
+ *
+ * Currently, the following account types are known:
+ *
+ * @li UnknownAccountType
+ * @li Checkings
+ * @li Savings
+ * @li Cash
+ * @li CreditCard
+ * @li Loan (collected)
+ * @li CertificateDep
+ * @li Investment
+ * @li MoneyMarket
+ * @li Currency
+ * @li Asset
+ * @li Liability
+ * @li Income
+ * @li Expense
+ * @li Loan (given)
+ * @li Equity
+ *
+ * @see MyMoneyInstitution
+ * @see MyMoneyFile
+ *
+ * @author Michael Edwardes 2000-2001
+ * @author Thomas Baumgart 2002
+ *
+**/
+class KMYMONEY_EXPORT MyMoneyAccount : public MyMoneyObject, public MyMoneyKeyValueContainer
+{
+ friend class MyMoneyObjectContainer;
+public:
+
+ /**
+ * Account types currently supported.
+ */
+ typedef enum _accountTypeE {
+ UnknownAccountType=0, /**< For error handling */
+ Checkings, /**< Standard checking account */
+ Savings, /**< Typical savings account */
+ Cash, /**< Denotes a shoe-box or pillowcase stuffed
+ with cash */
+ CreditCard, /**< Credit card accounts */
+ Loan, /**< Loan and mortgage accounts (liability) */
+ CertificateDep, /**< Certificates of Deposit */
+ Investment, /**< Investment account */
+ MoneyMarket, /**< Money Market Account */
+ Asset, /**< Denotes a generic asset account.*/
+ Liability, /**< Denotes a generic liability account.*/
+ Currency, /**< Denotes a currency trading account. */
+ Income, /**< Denotes an income account */
+ Expense, /**< Denotes an expense account */
+ AssetLoan, /**< Denotes a loan (asset of the owner of this object) */
+ Stock, /**< Denotes an security account as sub-account for an investment */
+ Equity, /**< Denotes an equity account e.g. opening/closeing balance */
+
+ /* insert new account types above this line */
+ MaxAccountTypes /**< Denotes the number of different account types */
+ }accountTypeE;
+
+ /**
+ * This is the constructor for a new empty account
+ */
+ MyMoneyAccount();
+
+ /**
+ * This is the constructor for a new account known to the current file
+ * This is the only constructor that will set the attribute m_openingDate
+ * to a correct value.
+ *
+ * @param id id assigned to the account
+ * @param right account definition
+ */
+ MyMoneyAccount(const QString& id, const MyMoneyAccount& right);
+
+ /**
+ * This is the constructor for an account that is described by a
+ * QDomElement (e.g. from a file).
+ *
+ * @param el const reference to the QDomElement from which to
+ * create the object
+ */
+ MyMoneyAccount(const QDomElement& el);
+
+ /**
+ * This is the destructor for any MyMoneyAccount object
+ */
+ ~MyMoneyAccount();
+
+ /**
+ * This operator tests for equality of two MyMoneyAccount objects
+ */
+ bool operator == (const MyMoneyAccount &) const;
+
+ /**
+ * This converts the account type into one of the four
+ * major account types liability, asset, expense or income.
+ *
+ * The current assignment is as follows:
+ *
+ * - Asset
+ * - Asset
+ * - Checkings
+ * - Savings
+ * - Cash
+ * - Currency
+ * - Investment
+ * - MoneyMarket
+ * - CertificateDep
+ * - AssetLoan
+ * - Stock
+ *
+ * - Liability
+ * - Liability
+ * - CreditCard
+ * - Loan
+ *
+ * - Income
+ * - Income
+ *
+ * - Expense
+ * - Expense
+ *
+ * @param type actual account type
+ * @return accountTypeE of major account type
+ */
+ static MyMoneyAccount::accountTypeE accountGroup(MyMoneyAccount::accountTypeE type);
+
+ MyMoneyAccount::accountTypeE accountGroup(void) const;
+
+ /**
+ * This method returns the id of the MyMoneyInstitution object this account
+ * belongs to.
+ * @return id of MyMoneyInstitution object. QString() if it is
+ * an internal account
+ * @see setInstitution
+ */
+ const QString& institutionId(void) const { return m_institution; }
+
+ /**
+ * This method returns the name of the account
+ * @return name of account
+ * @see setName()
+ */
+ const QString& name(void) const { return m_name; }
+
+ /**
+ * This method returns the number of the account at the institution
+ * @return number of account at the institution
+ * @see setNumber
+ */
+ const QString& number(void) const { return m_number; }
+
+ /**
+ * This method returns the descriptive text of the account.
+ * @return description of account
+ * @see setDescription
+ */
+ const QString& description(void) const { return m_description; }
+
+ /**
+ * This method returns the opening date of this account
+ * @return date of opening of this account as const QDate value
+ * @see setOpeningDate()
+ */
+ const QDate& openingDate(void) const { return m_openingDate; }
+
+ /**
+ * This method returns the date of the last reconciliation of this account
+ * @return date of last reconciliation as const QDate value
+ * @see setLastReconciliationDate
+ */
+ const QDate& lastReconciliationDate(void) const { return m_lastReconciliationDate; }
+
+ /**
+ * This method returns the date the account was last modified
+ * @return date of last modification as const QDate value
+ * @see setLastModified
+ */
+ const QDate& lastModified(void) const { return m_lastModified; }
+
+ /**
+ * This method is used to return the ID of the parent account
+ * @return QString with the ID of the parent of this account
+ */
+ const QString& parentAccountId(void) const { return m_parentAccount; };
+
+ /**
+ * This method returns the list of the account id's of
+ * subordinate accounts
+ * @return QStringList account ids
+ */
+ const QStringList& accountList(void) const { return m_accountList; };
+
+ /**
+ * This method returns the number of entries in the m_accountList
+ * @return number of entries in the accountList
+ */
+ int accountCount(void) const { return m_accountList.count(); };
+
+ /**
+ * This method is used to add an account id as sub-ordinate account
+ * @param account const QString reference to account ID
+ */
+ void addAccountId(const QString& account);
+
+ /**
+ * This method is used to remove an account from the list of
+ * sub-ordinate accounts.
+ * @param account const QString reference to account ID to be removed
+ */
+ void removeAccountId(const QString& account);
+
+ /**
+ * This method is used to remove all accounts from the list of
+ * sub-ordinate accounts.
+ */
+ void removeAccountIds(void);
+
+ /**
+ * This method is used to modify the date of the last
+ * modification access.
+ * @param date date of last modification
+ * @see lastModified
+ */
+ void setLastModified(const QDate& date);
+
+ /**
+ * This method is used to set the name of the account
+ * @param name name of the account
+ * @see name
+ */
+ void setName(const QString& name);
+
+ /**
+ * This method is used to set the number of the account at the institution
+ * @param number number of the account
+ * @see number
+ */
+ void setNumber(const QString& number);
+
+ /**
+ * This method is used to set the descriptive text of the account
+ *
+ * @param desc text that serves as description
+ * @see setDescription
+ */
+ void setDescription(const QString& desc);
+
+ /**
+ * This method is used to set the id of the institution this account
+ * belongs to.
+ *
+ * @param id id of the institution this account belongs to
+ * @see institution
+ */
+ void setInstitutionId(const QString& id);
+
+ /**
+ * This method is used to set the opening date information of an
+ * account.
+ *
+ * @param date QDate of opening date
+ * @see openingDate
+ */
+ void setOpeningDate(const QDate& date);
+
+ /**
+ * This method is used to set the date of the last reconciliation
+ * of an account.
+ * @param date QDate of last reconciliation
+ * @see lastReconciliationDate
+ */
+ void setLastReconciliationDate(const QDate& date);
+
+ /**
+ * This method is used to change the account type
+ *
+ * @param type account type
+ */
+ void setAccountType(const accountTypeE type);
+
+ /**
+ * This method is used to set a new parent account id
+ * @param parent QString reference to new parent account
+ */
+ void setParentAccountId(const QString& parent);
+
+ /**
+ * This method is used to update m_lastModified to the current date
+ */
+ void touch(void) { setLastModified(QDate::currentDate()); }
+
+ /**
+ * This method returns the type of the account.
+ */
+ accountTypeE accountType(void) const { return m_accountType; }
+
+ /**
+ * This method retrieves the id of the currency used with this account.
+ * If the return value is empty, the base currency should be used.
+ *
+ * @return id of currency
+ */
+ const QString& currencyId(void) const { return m_currencyId; };
+
+ /**
+ * This method sets the id of the currency used with this account.
+ *
+ * @param id ID of currency to be associated with this account.
+ */
+ void setCurrencyId(const QString& id);
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ /**
+ * This member returns the balance of this account based on
+ * all transactions stored in the journal.
+ */
+ const MyMoneyMoney& balance(void) const { return m_balance; }
+
+ /**
+ * This method adjusts the balance of this account
+ * according to the difference contained in the split @p s.
+ * If the s.action() is MyMoneySplit::ActionSplitShares then
+ * the balance will be adjusted accordingly.
+ *
+ * @param s const reference to MyMoneySplit object containing the
+ * value to be added/subtracted to/from the balance
+ * @param reverse add (false) or subtract (true) the shares contained in the split.
+ * It also affects the balance for share splits in the opposite direction.
+ */
+ void adjustBalance(const MyMoneySplit& s, bool reverse = false);
+
+ /**
+ * This method sets the balance of this account
+ * according to the value provided by @p val.
+ *
+ * @param val const reference to MyMoneyMoney object containing the
+ * value to be assigned to the balance
+ */
+ void setBalance(const MyMoneyMoney& val) { m_balance = val; }
+
+ /**
+ * This method sets the kvp's for online banking with this account
+ *
+ * @param values The container of kvp's needed when connecting to this account
+ */
+ void setOnlineBankingSettings(const MyMoneyKeyValueContainer& values);
+
+ /**
+ * This method retrieves the kvp's for online banking with this account
+ *
+ * @return The container of kvp's needed when connecting to this account
+ */
+ const MyMoneyKeyValueContainer& onlineBankingSettings(void) const;
+
+ /**
+ * This method sets the closed flag for the account. This is just
+ * an informational flag for the application. It has no other influence
+ * on the behaviour of the account object. The default for
+ * new objects @p open.
+ *
+ * @param isClosed mark the account closed (@p true) or open (@p false).
+ */
+ void setClosed(bool isClosed);
+
+ /**
+ * Return the closed flag for the account.
+ *
+ * @retval false account is marked open (the default for new accounts)
+ * @retval true account is marked closed
+ */
+ bool isClosed(void) const;
+
+ /**
+ * returns the applicable smallest fraction for this account
+ * for the given security based on the account type. At the same
+ * time, m_fraction is updated to the value returned.
+ *
+ * @param sec const reference to currency (security)
+ *
+ * @retval sec.smallestCashFraction() for account type Cash
+ * @retval sec.smallestAccountFraction() for all other account types
+ */
+ int fraction(const MyMoneySecurity& sec);
+
+ /**
+ * Same as the above method, but does not modify m_fraction.
+ */
+ int fraction(const MyMoneySecurity& sec) const;
+
+ /**
+ * This method returns the stored value for the fraction of this
+ * account or -1 if not initialized. It can be initialized by
+ * calling fraction(const MyMoneySecurity& sec) once.
+ *
+ * @note Don't use this method outside of KMyMoney application context (eg. testcases).
+ * Use the above method instead.
+ */
+ int fraction(void) const;
+
+ /**
+ * This method returns @a true if the account type is
+ * either Income or Expense
+ *
+ * @retval true account is of type income or expense
+ * @retval false for all other account types
+ *
+ * @deprecated use isIncomeExpense() instead
+ */
+ bool isCategory(void) const __attribute__ ((deprecated));
+
+ /**
+ * This method returns @a true if the account type is
+ * either Income or Expense
+ *
+ * @retval true account is of type income or expense
+ * @retval false for all other account types
+ */
+ bool isIncomeExpense(void) const;
+
+ /**
+ * This method returns @a true if the account type is
+ * either Asset or Liability
+ *
+ * @retval true account is of type asset or liability
+ * @retval false for all other account types
+ */
+ bool isAssetLiability(void) const;
+
+ /**
+ * This method returns @a true if the account type is
+ * either AssetLoan or Loan
+ *
+ * @retval true account is of type Loan or AssetLoan
+ * @retval false for all other account types
+ */
+ bool isLoan(void) const;
+
+ /**
+ * This method returns @a true if the account type is
+ * Stock
+ *
+ * @retval true account is of type Stock
+ * @retval false for all other account types
+ */
+ bool isInvest(void) const;
+
+ /**
+ * This method returns a name that has a brokerage suffix of
+ * the current name. It only works on investment accounts and
+ * returns the name for all other cases.
+ */
+ QString brokerageName(void) const;
+
+ /**
+ * @param size is a hint for the size of the icon
+ * @return a pixmap using DesktopIcon for the account type
+ */
+ QPixmap accountPixmap(bool reconcileFlag = false, int size = 0) const;
+
+ /**
+ * This method is used to convert the internal representation of
+ * an account type into a human readable format
+ *
+ * @param accountType numerical representation of the account type.
+ * For possible values, see MyMoneyAccount::accountTypeE
+ * @return QString representing the human readable form
+ */
+ static QString accountTypeToString(const MyMoneyAccount::accountTypeE accountType);
+
+ KMYMONEY_EXPORT QDataStream &operator<<( const MyMoneyAccount & );
+ KMYMONEY_EXPORT QDataStream &operator>>( MyMoneyAccount & );
+
+private:
+ /**
+ * This member variable identifies the type of account
+ */
+ accountTypeE m_accountType;
+
+ /**
+ * This member variable keeps the ID of the MyMoneyInstitution object
+ * that this object belongs to.
+ */
+ QString m_institution;
+
+ /**
+ * This member variable keeps the name of the account
+ * It is solely for documentation purposes and it's contents is not
+ * used otherwise by the mymoney-engine.
+ */
+ QString m_name;
+
+ /**
+ * This member variable keeps the account number at the institution
+ * It is solely for documentation purposes and it's contents is not
+ * used otherwise by the mymoney-engine.
+ */
+ QString m_number;
+
+ /**
+ * This member variable is a description of the account.
+ * It is solely for documentation purposes and it's contents is not
+ * used otherwise by the mymoney-engine.
+ */
+ QString m_description;
+
+ /**
+ * This member variable keeps the date when the account
+ * was last modified.
+ */
+ QDate m_lastModified;
+
+ /**
+ * This member variable keeps the date when the
+ * account was created as an object in a MyMoneyFile
+ */
+ QDate m_openingDate;
+
+ /**
+ * This member variable keeps the date of the last
+ * reconciliation of this account
+ */
+ QDate m_lastReconciliationDate;
+
+ /**
+ * This member holds the ID's of all sub-ordinate accounts
+ */
+ QStringList m_accountList;
+
+ /**
+ * This member contains the ID of the parent account
+ */
+ QString m_parentAccount;
+
+ /**
+ * This member contains the ID of the currency associated with this account
+ */
+ QString m_currencyId;
+
+ /**
+ * This member holds the balance of all transactions stored in the journal
+ * for this account.
+ */
+ MyMoneyMoney m_balance;
+
+ /**
+ * This member variable keeps the set of kvp's needed to establish
+ * online banking sessions to this account.
+ */
+ MyMoneyKeyValueContainer m_onlineBankingSettings;
+
+ /**
+ * This member keeps the fraction for the account. It is filled by MyMoneyFile
+ * when set to -1. See also @sa fraction(const MyMoneySecurity&).
+ */
+ int m_fraction;
+
+};
+
+/**
+ * This class is a convenience class to access data for loan accounts.
+ * It does contain the same member variables as a MyMoneyAccount object,
+ * but serves a set of getter/setter methods to ease the access to
+ * laon relevant data stored in the key value container of the MyMoneyAccount
+ * object.
+ */
+class KMYMONEY_EXPORT MyMoneyAccountLoan : public MyMoneyAccount
+{
+public:
+ enum interestDueE {
+ paymentDue = 0,
+ paymentReceived
+ };
+
+ enum interestChangeUnitE {
+ changeDaily = 0,
+ changeWeekly,
+ changeMonthly,
+ changeYearly
+ };
+
+ MyMoneyAccountLoan() {}
+ MyMoneyAccountLoan(const MyMoneyAccount&);
+ ~MyMoneyAccountLoan() {}
+
+ const MyMoneyMoney loanAmount(void) const;
+ void setLoanAmount(const MyMoneyMoney& amount);
+ const MyMoneyMoney interestRate(const QDate& date) const;
+ void setInterestRate(const QDate& date, const MyMoneyMoney& rate);
+ interestDueE interestCalculation(void) const;
+ void setInterestCalculation(const interestDueE onReception);
+ const QDate nextInterestChange(void) const;
+ void setNextInterestChange(const QDate& date);
+ const QString schedule(void) const;
+ void setSchedule(const QString& sched);
+ bool fixedInterestRate(void) const;
+ void setFixedInterestRate(const bool fixed);
+ const MyMoneyMoney finalPayment(void) const;
+ void setFinalPayment(const MyMoneyMoney& finalPayment);
+ unsigned int term(void) const;
+ void setTerm(const unsigned int payments);
+ int interestChangeFrequency(int* unit = 0) const;
+ void setInterestChangeFrequency(const int amount, const int unit);
+ const MyMoneyMoney periodicPayment(void) const;
+ void setPeriodicPayment(const MyMoneyMoney& payment);
+ int interestCompounding(void) const;
+ void setInterestCompounding(int frequency);
+ const QString payee(void) const;
+ void setPayee(const QString& payee);
+ const QString interestAccountId(void) const;
+ void setInterestAccountId(const QString& id);
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+};
+
+#endif
+
+
diff --git a/kmymoney2/mymoney/mymoneyaccounttest.cpp b/kmymoney2/mymoney/mymoneyaccounttest.cpp
new file mode 100644
index 0000000..1384c5c
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyaccounttest.cpp
@@ -0,0 +1,589 @@
+/***************************************************************************
+ mymoneyaccounttest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyaccounttest.h"
+#include <kmymoney/mymoneyexception.h>
+#include <kmymoney/mymoneysplit.h>
+
+MyMoneyAccountTest::MyMoneyAccountTest()
+{
+}
+
+
+void MyMoneyAccountTest::setUp () {
+}
+
+void MyMoneyAccountTest::tearDown () {
+}
+
+void MyMoneyAccountTest::testEmptyConstructor() {
+ MyMoneyAccount a;
+
+ CPPUNIT_ASSERT(a.id().isEmpty());
+ CPPUNIT_ASSERT(a.name().isEmpty());
+ CPPUNIT_ASSERT(a.accountType() == MyMoneyAccount::UnknownAccountType);
+ CPPUNIT_ASSERT(a.openingDate() == QDate());
+ CPPUNIT_ASSERT(a.lastModified() == QDate());
+ CPPUNIT_ASSERT(a.lastReconciliationDate() == QDate());
+ CPPUNIT_ASSERT(a.accountList().count() == 0);
+ CPPUNIT_ASSERT(a.balance().isZero());
+}
+
+void MyMoneyAccountTest::testConstructor() {
+ QString id = "A000001";
+ QString institutionid = "B000001";
+ QString parent = "Parent";
+ MyMoneyAccount r;
+ MyMoneySplit s;
+ r.setAccountType(MyMoneyAccount::Asset);
+ r.setOpeningDate(QDate::currentDate());
+ r.setLastModified(QDate::currentDate());
+ r.setDescription("Desc");
+ r.setNumber("465500");
+ r.setParentAccountId(parent);
+ r.setValue(QString("key"), "value");
+ s.setShares(MyMoneyMoney(1,1));
+ r.adjustBalance(s);
+ CPPUNIT_ASSERT(r.m_kvp.count() == 1);
+ CPPUNIT_ASSERT(r.value("key") == "value");
+
+ MyMoneyAccount a(id, r);
+
+ CPPUNIT_ASSERT(a.id() == id);
+ CPPUNIT_ASSERT(a.institutionId().isEmpty());
+ CPPUNIT_ASSERT(a.accountType() == MyMoneyAccount::Asset);
+ CPPUNIT_ASSERT(a.openingDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(a.lastModified() == QDate::currentDate());
+ CPPUNIT_ASSERT(a.number() == "465500");
+ CPPUNIT_ASSERT(a.description() == "Desc");
+ CPPUNIT_ASSERT(a.accountList().count() == 0);
+ CPPUNIT_ASSERT(a.parentAccountId() == "Parent");
+ CPPUNIT_ASSERT(a.balance() == MyMoneyMoney(1,1));
+
+ QMap<QString, QString> copy;
+ copy = r.pairs();
+ CPPUNIT_ASSERT(copy.count() == 1);
+ CPPUNIT_ASSERT(copy[QString("key")] == "value");
+}
+
+void MyMoneyAccountTest::testSetFunctions() {
+ MyMoneyAccount a;
+
+ QDate today(QDate::currentDate());
+ CPPUNIT_ASSERT(a.name().isEmpty());
+ CPPUNIT_ASSERT(a.lastModified() == QDate());
+ CPPUNIT_ASSERT(a.description().isEmpty());
+
+ a.setName("Account");
+ a.setInstitutionId("Institution1");
+ a.setLastModified(today);
+ a.setDescription("Desc");
+ a.setNumber("123456");
+ a.setAccountType(MyMoneyAccount::MoneyMarket);
+
+ CPPUNIT_ASSERT(a.name() == "Account");
+ CPPUNIT_ASSERT(a.institutionId() == "Institution1");
+ CPPUNIT_ASSERT(a.lastModified() == today);
+ CPPUNIT_ASSERT(a.description() == "Desc");
+ CPPUNIT_ASSERT(a.number() == "123456");
+ CPPUNIT_ASSERT(a.accountType() == MyMoneyAccount::MoneyMarket);
+}
+
+void MyMoneyAccountTest::testCopyConstructor() {
+ QString id = "A000001";
+ QString institutionid = "B000001";
+ QString parent = "ParentAccount";
+ MyMoneyAccount r;
+ r.setAccountType(MyMoneyAccount::Expense);
+ r.setOpeningDate(QDate::currentDate());
+ r.setLastModified(QDate::currentDate());
+ r.setName("Account");
+ r.setInstitutionId("Inst1");
+ r.setDescription("Desc1");
+ r.setNumber("Number");
+ r.setParentAccountId(parent);
+ r.setValue("Key", "Value");
+
+ MyMoneyAccount a(id, r);
+ a.setInstitutionId(institutionid);
+
+ MyMoneyAccount b(a);
+
+ CPPUNIT_ASSERT(b.name() == "Account");
+ CPPUNIT_ASSERT(b.institutionId() == institutionid);
+ CPPUNIT_ASSERT(b.accountType() == MyMoneyAccount::Expense);
+ CPPUNIT_ASSERT(b.lastModified() == QDate::currentDate());
+ CPPUNIT_ASSERT(b.openingDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(b.description() == "Desc1");
+ CPPUNIT_ASSERT(b.number() == "Number");
+ CPPUNIT_ASSERT(b.parentAccountId() == "ParentAccount");
+
+ CPPUNIT_ASSERT(b.value("Key") == "Value");
+}
+
+void MyMoneyAccountTest::testAssignmentConstructor() {
+ MyMoneyAccount a;
+ a.setAccountType(MyMoneyAccount::Checkings);
+ a.setName("Account");
+ a.setInstitutionId("Inst1");
+ a.setDescription("Bla");
+ a.setNumber("assigned Number");
+ a.setValue("Key", "Value");
+ a.addAccountId("ChildAccount");
+
+ MyMoneyAccount b;
+
+ b.setLastModified(QDate::currentDate());
+
+ b = a;
+
+ CPPUNIT_ASSERT(b.name() == "Account");
+ CPPUNIT_ASSERT(b.institutionId() == "Inst1");
+ CPPUNIT_ASSERT(b.accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(b.lastModified() == QDate());
+ CPPUNIT_ASSERT(b.openingDate() == a.openingDate());
+ CPPUNIT_ASSERT(b.description() == "Bla");
+ CPPUNIT_ASSERT(b.number() == "assigned Number");
+ CPPUNIT_ASSERT(b.value("Key") == "Value");
+ CPPUNIT_ASSERT(b.accountList().count() == 1);
+ CPPUNIT_ASSERT(b.accountList()[0] == "ChildAccount");
+}
+
+void MyMoneyAccountTest::testAdjustBalance() {
+ MyMoneyAccount a;
+ MyMoneySplit s;
+ s.setShares(MyMoneyMoney(3,1));
+ a.adjustBalance(s);
+ CPPUNIT_ASSERT(a.balance() == MyMoneyMoney(3,1));
+ s.setShares(MyMoneyMoney(5,1));
+ a.adjustBalance(s, true);
+ CPPUNIT_ASSERT(a.balance() == MyMoneyMoney(-2,1));
+ s.setShares(MyMoneyMoney(2,1));
+ s.setAction(MyMoneySplit::ActionSplitShares);
+ a.adjustBalance(s);
+ CPPUNIT_ASSERT(a.balance() == MyMoneyMoney(-4,1));
+ s.setShares(MyMoneyMoney(4,1));
+ s.setAction(QString());
+ a.adjustBalance(s);
+ CPPUNIT_ASSERT(a.balance().isZero());
+}
+
+void MyMoneyAccountTest::testSubAccounts()
+{
+ MyMoneyAccount a;
+ a.setAccountType(MyMoneyAccount::Checkings);
+
+ a.addAccountId("Subaccount1");
+ CPPUNIT_ASSERT(a.accountList().count() == 1);
+ a.addAccountId("Subaccount1");
+ CPPUNIT_ASSERT(a.accountList().count() == 1);
+ a.addAccountId("Subaccount2");
+ CPPUNIT_ASSERT(a.accountList().count() == 2);
+
+}
+
+void MyMoneyAccountTest::testEquality()
+{
+ MyMoneyAccount a;
+
+ a.setLastModified(QDate::currentDate());
+ a.setName("Name");
+ a.setNumber("Number");
+ a.setDescription("Desc");
+ a.setInstitutionId("I-ID");
+ a.setOpeningDate(QDate::currentDate());
+ a.setLastReconciliationDate(QDate::currentDate());
+ a.setAccountType(MyMoneyAccount::Asset);
+ a.setParentAccountId("P-ID");
+ a.setId("A-ID");
+ a.setCurrencyId("C-ID");
+ a.setValue("Key", "Value");
+
+ MyMoneyAccount b;
+
+ b = a;
+ CPPUNIT_ASSERT(b == a);
+
+ a.setName("Noname");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setLastModified(QDate::currentDate().addDays(-1));
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setNumber("Nonumber");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setDescription("NoDesc");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setInstitutionId("I-noID");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setOpeningDate(QDate::currentDate().addDays(-1));
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setLastReconciliationDate(QDate::currentDate().addDays(-1));
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setAccountType(MyMoneyAccount::Liability);
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setParentAccountId("P-noID");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setId("A-noID");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setCurrencyId("C-noID");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setValue("Key", "noValue");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+ a.setValue("noKey", "Value");
+ CPPUNIT_ASSERT(!(b == a));
+ b = a;
+
+}
+
+void MyMoneyAccountTest::testWriteXML() {
+ QString id = "A000001";
+ QString institutionid = "B000001";
+ QString parent = "Parent";
+
+ MyMoneyAccount r;
+ r.setAccountType(MyMoneyAccount::Asset);
+ r.setOpeningDate(QDate::currentDate());
+ r.setLastModified(QDate::currentDate());
+ r.setDescription("Desc");
+ r.setName("AccountName");
+ r.setNumber("465500");
+ r.setParentAccountId(parent);
+ r.setInstitutionId(institutionid);
+ r.setValue(QString("key"), "value");
+ r.addAccountId("A000002");
+ // CPPUNIT_ASSERT(r.m_kvp.count() == 1);
+ // CPPUNIT_ASSERT(r.value("key") == "value");
+
+ MyMoneyAccount a(id, r);
+
+ QDomDocument doc("TEST");
+ QDomElement el = doc.createElement("ACCOUNT-CONTAINER");
+ doc.appendChild(el);
+ a.writeXML(doc, el);
+
+ QString ref = QString(
+ "<!DOCTYPE TEST>\n"
+ "<ACCOUNT-CONTAINER>\n"
+ " <ACCOUNT parentaccount=\"Parent\" lastmodified=\"%1\" lastreconciled=\"\" institution=\"B000001\" number=\"465500\" opened=\"%2\" type=\"9\" id=\"A000001\" name=\"AccountName\" description=\"Desc\" >\n"
+ " <SUBACCOUNTS>\n"
+ " <SUBACCOUNT id=\"A000002\" />\n"
+ " </SUBACCOUNTS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </ACCOUNT>\n"
+ "</ACCOUNT-CONTAINER>\n").
+ arg(QDate::currentDate().toString(Qt::ISODate)).arg(QDate::currentDate().toString(Qt::ISODate));
+
+ CPPUNIT_ASSERT(doc.toString() == ref);
+}
+
+void MyMoneyAccountTest::testReadXML() {
+ MyMoneyAccount a;
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<ACCOUNT-CONTAINER>\n"
+ " <ACCOUNT parentaccount=\"Parent\" lastmodified=\"%1\" lastreconciled=\"\" institution=\"B000001\" number=\"465500\" opened=\"%2\" type=\"9\" id=\"A000001\" name=\"AccountName\" description=\"Desc\" >\n"
+ " <SUBACCOUNTS>\n"
+ " <SUBACCOUNT id=\"A000002\" />\n"
+ " <SUBACCOUNT id=\"A000003\" />\n"
+ " </SUBACCOUNTS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " <PAIR key=\"Key\" value=\"Value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </ACCOUNT>\n"
+ "</ACCOUNT-CONTAINER>\n").
+ arg(QDate::currentDate().toString(Qt::ISODate)).arg(QDate::currentDate().toString(Qt::ISODate));
+
+ QString ref_false = QString(
+ "<!DOCTYPE TEST>\n"
+ "<ACCOUNT-CONTAINER>\n"
+ " <KACCOUNT parentaccount=\"Parent\" lastmodified=\"%1\" lastreconciled=\"\" institution=\"B000001\" number=\"465500\" opened=\"%2\" type=\"9\" id=\"A000001\" name=\"AccountName\" description=\"Desc\" >\n"
+ " <SUBACCOUNTS>\n"
+ " <SUBACCOUNT id=\"A000002\" />\n"
+ " <SUBACCOUNT id=\"A000003\" />\n"
+ " </SUBACCOUNTS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " <PAIR key=\"Key\" value=\"Value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </KACCOUNT>\n"
+ "</ACCOUNT-CONTAINER>\n").
+ arg(QDate::currentDate().toString(Qt::ISODate)).arg(QDate::currentDate().toString(Qt::ISODate));
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_false);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ a = MyMoneyAccount(node);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ a.addAccountId("TEST");
+ a.setValue("KEY", "VALUE");
+
+ try {
+ a = MyMoneyAccount(node);
+ CPPUNIT_ASSERT(a.id() == "A000001");
+ CPPUNIT_ASSERT(a.m_name == "AccountName");
+ CPPUNIT_ASSERT(a.m_parentAccount == "Parent");
+ CPPUNIT_ASSERT(a.m_lastModified == QDate::currentDate());
+ CPPUNIT_ASSERT(a.m_lastReconciliationDate == QDate());
+ CPPUNIT_ASSERT(a.m_institution == "B000001");
+ CPPUNIT_ASSERT(a.m_number == "465500");
+ CPPUNIT_ASSERT(a.m_openingDate == QDate::currentDate());
+ CPPUNIT_ASSERT(a.m_accountType == MyMoneyAccount::Asset);
+ CPPUNIT_ASSERT(a.m_description == "Desc");
+ CPPUNIT_ASSERT(a.accountList().count() == 2);
+ CPPUNIT_ASSERT(a.accountList()[0] == "A000002");
+ CPPUNIT_ASSERT(a.accountList()[1] == "A000003");
+ CPPUNIT_ASSERT(a.pairs().count() == 3);
+ CPPUNIT_ASSERT(a.value("key") == "value");
+ CPPUNIT_ASSERT(a.value("Key") == "Value");
+ CPPUNIT_ASSERT(a.value("lastStatementDate").isEmpty());
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyAccountTest::testHasReferenceTo(void)
+{
+ MyMoneyAccount a;
+
+ a.setInstitutionId("I0001");
+ a.addAccountId("A_001");
+ a.addAccountId("A_002");
+ a.setParentAccountId("A_Parent");
+ a.setCurrencyId("Currency");
+
+ CPPUNIT_ASSERT(a.hasReferenceTo("I0001") == true);
+ CPPUNIT_ASSERT(a.hasReferenceTo("I0002") == false);
+ CPPUNIT_ASSERT(a.hasReferenceTo("A_001") == false);
+ CPPUNIT_ASSERT(a.hasReferenceTo("A_Parent") == true);
+ CPPUNIT_ASSERT(a.hasReferenceTo("Currency") == true);
+}
+
+void MyMoneyAccountTest::testSetClosed(void)
+{
+ MyMoneyAccount a;
+
+ CPPUNIT_ASSERT(a.isClosed() == false);
+ a.setClosed(true);
+ CPPUNIT_ASSERT(a.isClosed() == true);
+ a.setClosed(false);
+ CPPUNIT_ASSERT(a.isClosed() == false);
+}
+
+void MyMoneyAccountTest::testIsIncomeExpense(void)
+{
+ MyMoneyAccount a;
+
+ a.setAccountType(MyMoneyAccount::UnknownAccountType);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Savings);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Cash);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::CreditCard);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Loan);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::CertificateDep);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Investment);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::MoneyMarket);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Asset);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Liability);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Currency);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Income);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == true);
+
+ a.setAccountType(MyMoneyAccount::Expense);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == true);
+
+ a.setAccountType(MyMoneyAccount::AssetLoan);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Stock);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+
+ a.setAccountType(MyMoneyAccount::Equity);
+ CPPUNIT_ASSERT(a.isIncomeExpense() == false);
+}
+
+void MyMoneyAccountTest::testIsAssetLiability(void)
+{
+ MyMoneyAccount a;
+
+ a.setAccountType(MyMoneyAccount::UnknownAccountType);
+ CPPUNIT_ASSERT(a.isAssetLiability() == false);
+
+ a.setAccountType(MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Savings);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Cash);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::CreditCard);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Loan);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::CertificateDep);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Investment);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::MoneyMarket);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Asset);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Liability);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Currency);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Income);
+ CPPUNIT_ASSERT(a.isAssetLiability() == false);
+
+ a.setAccountType(MyMoneyAccount::Expense);
+ CPPUNIT_ASSERT(a.isAssetLiability() == false);
+
+ a.setAccountType(MyMoneyAccount::AssetLoan);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Stock);
+ CPPUNIT_ASSERT(a.isAssetLiability() == true);
+
+ a.setAccountType(MyMoneyAccount::Equity);
+ CPPUNIT_ASSERT(a.isAssetLiability() == false);
+}
+
+void MyMoneyAccountTest::testIsLoan(void)
+{
+ MyMoneyAccount a;
+
+ a.setAccountType(MyMoneyAccount::UnknownAccountType);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Savings);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Cash);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::CreditCard);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Loan);
+ CPPUNIT_ASSERT(a.isLoan() == true);
+
+ a.setAccountType(MyMoneyAccount::CertificateDep);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Investment);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::MoneyMarket);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Asset);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Liability);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Currency);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Income);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Expense);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::AssetLoan);
+ CPPUNIT_ASSERT(a.isLoan() == true);
+
+ a.setAccountType(MyMoneyAccount::Stock);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+
+ a.setAccountType(MyMoneyAccount::Equity);
+ CPPUNIT_ASSERT(a.isLoan() == false);
+}
+
diff --git a/kmymoney2/mymoney/mymoneyaccounttest.h b/kmymoney2/mymoney/mymoneyaccounttest.h
new file mode 100644
index 0000000..c2af080
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyaccounttest.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ mymoneyaccounttest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYACCOUNTTEST_H__
+#define __MYMONEYACCOUNTTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#define protected public
+#include "mymoneyaccount.h"
+#undef private
+
+class MyMoneyAccountTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyAccountTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testAssignmentConstructor);
+ CPPUNIT_TEST(testSubAccounts);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST(testWriteXML);
+ CPPUNIT_TEST(testReadXML);
+ CPPUNIT_TEST(testHasReferenceTo);
+ CPPUNIT_TEST(testAdjustBalance);
+ CPPUNIT_TEST(testSetClosed);
+ CPPUNIT_TEST(testIsIncomeExpense);
+ CPPUNIT_TEST(testIsAssetLiability);
+ CPPUNIT_TEST(testIsLoan);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyAccount *m;
+
+public:
+ MyMoneyAccountTest();
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testConstructor();
+ void testSetFunctions();
+ void testCopyConstructor();
+ void testAssignmentConstructor();
+ void testSubAccounts();
+ void testEquality();
+ void testWriteXML();
+ void testReadXML();
+ void testHasReferenceTo();
+ void testAdjustBalance();
+ void testSetClosed();
+ void testIsIncomeExpense();
+ void testIsAssetLiability();
+ void testIsLoan();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneybudget.cpp b/kmymoney2/mymoney/mymoneybudget.cpp
new file mode 100644
index 0000000..46b8ca8
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneybudget.cpp
@@ -0,0 +1,354 @@
+/***************************************************************************
+ mymoneybudget.cpp
+ -------------------
+ begin : Sun July 4 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdom.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneybudget.h"
+
+const QStringList MyMoneyBudget::AccountGroup::kBudgetLevelText = QStringList::split(",","none,monthly,monthbymonth,yearly,invalid",true);
+const int BUDGET_VERSION = 2;
+
+bool MyMoneyBudget::AccountGroup::isZero(void) const
+{
+ return (!m_budgetsubaccounts && m_budgetlevel == eMonthly && balance().isZero());
+}
+
+void MyMoneyBudget::AccountGroup::convertToMonthly(void)
+{
+ MyMoneyBudget::PeriodGroup period;
+
+ switch(m_budgetlevel) {
+ case eYearly:
+ case eMonthByMonth:
+ period = *(m_periods.begin()); // make him monthly
+ period.setAmount(balance() / MyMoneyMoney(12,1));
+ clearPeriods();
+ addPeriod(period.startDate(), period);
+ break;
+ default:
+ break;
+ }
+ m_budgetlevel = eMonthly;
+}
+
+void MyMoneyBudget::AccountGroup::convertToYearly(void)
+{
+ MyMoneyBudget::PeriodGroup period;
+
+ switch(m_budgetlevel) {
+ case eMonthByMonth:
+ case eMonthly:
+ period = *(m_periods.begin()); // make him monthly
+ period.setAmount(totalBalance());
+ clearPeriods();
+ addPeriod(period.startDate(), period);
+ break;
+ default:
+ break;
+ }
+ m_budgetlevel = eYearly;
+}
+
+void MyMoneyBudget::AccountGroup::convertToMonthByMonth(void)
+{
+ MyMoneyBudget::PeriodGroup period;
+ QDate date;
+
+ switch(m_budgetlevel) {
+ case eMonthByMonth:
+ case eMonthly:
+ period = *(m_periods.begin());
+ period.setAmount(totalBalance() / MyMoneyMoney(12,1));
+ clearPeriods();
+ date = period.startDate();
+ for(int i = 0; i < 12; ++i) {
+ addPeriod(date, period);
+ date = date.addMonths(1);
+ period.setStartDate(date);
+ }
+ break;
+ default:
+ break;
+ }
+ m_budgetlevel = eYearly;
+}
+
+MyMoneyBudget::AccountGroup MyMoneyBudget::AccountGroup::operator += (const MyMoneyBudget::AccountGroup& _r)
+{
+ MyMoneyBudget::AccountGroup r(_r);
+
+ // make both operands based on the same budget level
+ if(m_budgetlevel != r.m_budgetlevel) {
+ if(m_budgetlevel == eMonthly) { // my budget is monthly
+ if(r.m_budgetlevel == eYearly) { // his his yearly
+ r.convertToMonthly();
+ } else if(r.m_budgetlevel == eMonthByMonth) { // his is month by month
+ convertToMonthByMonth();
+ }
+ } else if(m_budgetlevel == eYearly) { // my budget is yearly
+ if(r.m_budgetlevel == eMonthly) { // his is monthly
+ r.convertToYearly();
+ } else if(r.m_budgetlevel == eMonthByMonth) { // his is month by month
+ convertToMonthByMonth();
+ }
+ } else if(m_budgetlevel == eMonthByMonth) { // my budget is month by month
+ r.convertToMonthByMonth();
+ }
+ }
+
+ // now both budgets should be of the same type and we simply need
+ // to iterate over the period list and add the values
+ QMap<QDate, MyMoneyBudget::PeriodGroup> periods = m_periods;
+ QMap<QDate, MyMoneyBudget::PeriodGroup> rPeriods = r.m_periods;
+ QMap<QDate, MyMoneyBudget::PeriodGroup>::const_iterator it_p;
+ QMap<QDate, MyMoneyBudget::PeriodGroup>::const_iterator it_pr;
+ m_periods.clear();
+ it_p = periods.begin();
+ it_pr = rPeriods.begin();
+ QDate date = (*it_p).startDate();
+ while(it_p != periods.end()) {
+ MyMoneyBudget::PeriodGroup period = *it_p;
+ if(it_pr != rPeriods.end()) {
+ period.setAmount(period.amount() + (*it_pr).amount());
+ ++it_pr;
+ }
+ addPeriod(date, period);
+ date = date.addMonths(1);
+ ++it_p;
+ }
+ return *this;
+}
+
+bool MyMoneyBudget::AccountGroup::operator == (const AccountGroup &r) const
+{
+ return (m_id == r.m_id
+ && m_budgetlevel == r.m_budgetlevel
+ && m_budgetsubaccounts == r.m_budgetsubaccounts
+ && m_periods.keys() == r.m_periods.keys()
+ && m_periods.values() == r.m_periods.values());
+}
+
+MyMoneyBudget::MyMoneyBudget(void) :
+ m_name("Unconfigured Budget")
+{
+}
+
+MyMoneyBudget::MyMoneyBudget(const QString& _name) :
+ m_name(_name)
+{
+}
+
+MyMoneyBudget::MyMoneyBudget(const QDomElement& node) :
+ MyMoneyObject(node)
+{
+ if(!read(node))
+ clearId();
+}
+
+MyMoneyBudget::MyMoneyBudget(const QString& id, const MyMoneyBudget& budget)
+{
+ *this = budget;
+ m_id = id;
+}
+
+MyMoneyBudget::~MyMoneyBudget()
+{
+}
+
+bool MyMoneyBudget::operator == (const MyMoneyBudget& right) const
+{
+ return (MyMoneyObject::operator==(right) &&
+ (m_accounts.count() == right.m_accounts.count()) &&
+ (m_accounts.keys() == right.m_accounts.keys()) &&
+ (m_accounts.values() == right.m_accounts.values()) &&
+ (m_name == right.m_name) &&
+ (m_start == right.m_start) );
+}
+
+void MyMoneyBudget::write(QDomElement& e, QDomDocument *doc) const
+{
+ writeBaseXML(*doc, e);
+
+ e.setAttribute("name", m_name);
+ e.setAttribute("start", m_start.toString(Qt::ISODate) );
+ e.setAttribute("version", BUDGET_VERSION);
+
+ QMap<QString, AccountGroup>::const_iterator it;
+ for(it = m_accounts.begin(); it != m_accounts.end(); ++it) {
+ // only add the account if there is a budget entered
+ if(!(*it).balance().isZero()) {
+ QDomElement domAccount = doc->createElement("ACCOUNT");
+ domAccount.setAttribute("id", it.key());
+ domAccount.setAttribute("budgetlevel", AccountGroup::kBudgetLevelText[it.data().budgetLevel()]);
+ domAccount.setAttribute("budgetsubaccounts", it.data().budgetSubaccounts());
+
+ const QMap<QDate, PeriodGroup> periods = it.data().getPeriods();
+ QMap<QDate, PeriodGroup>::const_iterator it_per;
+ for(it_per = periods.begin(); it_per != periods.end(); ++it_per) {
+ if(!(*it_per).amount().isZero()) {
+ QDomElement domPeriod = doc->createElement("PERIOD");
+
+ domPeriod.setAttribute("amount", (*it_per).amount().toString());
+ domPeriod.setAttribute("start", (*it_per).startDate().toString(Qt::ISODate));
+ domAccount.appendChild(domPeriod);
+ }
+ }
+
+ e.appendChild(domAccount);
+ }
+ }
+}
+
+bool MyMoneyBudget::read(const QDomElement& e)
+{
+ // The goal of this reading method is 100% backward AND 100% forward
+ // compatability. Any Budget ever created with any version of KMyMoney
+ // should be able to be loaded by this method (as long as it's one of the
+ // Budget types supported in this version, of course)
+
+ bool result = false;
+
+ if ("BUDGET" == e.tagName())
+ {
+ result = true;
+ m_name = e.attribute("name");
+ m_start = QDate::fromString(e.attribute("start"), Qt::ISODate);
+ m_id = e.attribute("id");
+
+ QDomNode child = e.firstChild();
+ while(!child.isNull() && child.isElement())
+ {
+ QDomElement c = child.toElement();
+
+ AccountGroup account;
+
+ if("ACCOUNT" == c.tagName()) {
+ if(c.hasAttribute("id"))
+ account.setId(c.attribute("id"));
+
+ if(c.hasAttribute("budgetlevel")) {
+ int i = AccountGroup::kBudgetLevelText.findIndex(c.attribute("budgetlevel"));
+ if ( i != -1 )
+ account.setBudgetLevel(static_cast<AccountGroup::eBudgetLevel>(i));
+ }
+
+ if(c.hasAttribute("budgetsubaccounts"))
+ account.setBudgetSubaccounts(c.attribute("budgetsubaccounts").toUInt());
+ }
+
+ QDomNode period = c.firstChild();
+ while(!period.isNull() && period.isElement())
+ {
+ QDomElement per = period.toElement();
+ PeriodGroup pGroup;
+
+ if("PERIOD" == per.tagName() && per.hasAttribute("amount") && per.hasAttribute("start"))
+ {
+ pGroup.setAmount( MyMoneyMoney(per.attribute("amount")) );
+ pGroup.setStartDate( QDate::fromString(per.attribute("start"), Qt::ISODate) );
+ account.addPeriod(pGroup.startDate(), pGroup);
+ }
+
+ period = period.nextSibling();
+ }
+
+ m_accounts[account.id()] = account;
+
+ child = child.nextSibling();
+ }
+ }
+
+ return result;
+}
+
+void MyMoneyBudget::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("BUDGET");
+ write(el,&document);
+ parent.appendChild(el);
+}
+
+bool MyMoneyBudget::hasReferenceTo(const QString& id) const
+{
+ // return true if we have an assignment for this id
+ return (m_accounts.contains(id));
+}
+
+void MyMoneyBudget::removeReference(const QString& id)
+{
+ if(m_accounts.contains(id)) {
+ m_accounts.remove(id);
+ }
+}
+
+void MyMoneyBudget::setAccount(const AccountGroup &_account, const QString _id)
+{
+ if(_account.isZero()) {
+ m_accounts.remove(_id);
+ } else {
+ // make sure we store a correct id
+ AccountGroup account(_account);
+ if(account.id() != _id)
+ account.setId(_id);
+ m_accounts[_id] = account;
+ }
+}
+
+const MyMoneyBudget::AccountGroup& MyMoneyBudget::account(const QString _id) const
+{
+ static AccountGroup empty;
+
+ if ( m_accounts.contains(_id) )
+ return m_accounts[_id];
+ return empty;
+}
+
+void MyMoneyBudget::setBudgetStart(const QDate& _start)
+{
+ QDate oldDate = QDate(m_start.year(), m_start.month(), 1);
+ m_start = QDate(_start.year(), _start.month(), 1);
+ if(oldDate.isValid()) {
+ int adjust = ((m_start.year() - oldDate.year())*12) + (m_start.month() - oldDate.month());
+ QMap<QString, AccountGroup>::iterator it;
+ for(it = m_accounts.begin(); it != m_accounts.end(); ++it) {
+ const QMap<QDate, PeriodGroup> periods = (*it).getPeriods();
+ QMap<QDate, PeriodGroup>::const_iterator it_per;
+ (*it).clearPeriods();
+ for(it_per = periods.begin(); it_per != periods.end(); ++it_per) {
+ PeriodGroup pgroup = (*it_per);
+ pgroup.setStartDate(pgroup.startDate().addMonths(adjust));
+ (*it).addPeriod(pgroup.startDate(), pgroup);
+ }
+ }
+ }
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneybudget.h b/kmymoney2/mymoney/mymoneybudget.h
new file mode 100644
index 0000000..a2eea02
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneybudget.h
@@ -0,0 +1,269 @@
+/***************************************************************************
+ mymoneybudget.h
+ -------------------
+ begin : Sun Jan 22 2006
+ copyright : (C) 2006 by Darren Gould
+ email : darren_gould@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYBUDGET_H
+#define MYMONEYBUDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qmap.h>
+#include <qvaluelist.h>
+#include <qstring.h>
+class QDomElement;
+class QDomDocument;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/export.h>
+
+/**
+ * This class defines a Budget within the MyMoneyEngine. The Budget class
+ * contains all the configuration parameters needed to run a Budget, plus
+ * XML serialization.
+ *
+ * As noted above, this class only provides a Budget DEFINITION. The
+ * generation and presentation of the Budget itself are left to higher
+ * level classes.
+ *
+ * @author Darren Gould <darren_gould@gmx.de>
+ */
+class KMYMONEY_EXPORT MyMoneyBudget: public MyMoneyObject
+{
+public:
+ MyMoneyBudget(void);
+ ~MyMoneyBudget();
+ MyMoneyBudget(const QString& _name);
+ /**
+ * This constructor creates an object based on the data found in the
+ * QDomElement referenced by @p node. If problems arise, the @p id of
+ * the object is cleared (see MyMoneyObject::clearId()).
+ */
+ MyMoneyBudget(const QDomElement& node);
+
+ /**
+ * This constructor creates an object based on the data found in the
+ * MyMoneyBudget budget object.
+ */
+ MyMoneyBudget(const QString& id, const MyMoneyBudget& budget);
+
+ /**
+ * Helper class for MyMoneyBudget
+ *
+ * This is an abstraction of the PERIOD stored in the BUDGET/ACCOUNT tag in XML
+ *
+ * @author Darren Gould
+ */
+ class PeriodGroup
+ {
+ public:
+ // get functions
+ const QDate& startDate ( void ) const { return m_start; }
+ const MyMoneyMoney& amount( void ) const { return m_amount; }
+
+ // set functions
+ void setStartDate ( const QDate& _start ) { m_start = _start; }
+ void setAmount( const MyMoneyMoney& _amount ) { m_amount = _amount;}
+
+ bool operator == (const PeriodGroup &r) const { return (m_start == r.m_start && m_amount == r.m_amount); }
+
+ private:
+ QDate m_start;
+ MyMoneyMoney m_amount;
+ };
+
+ /**
+ * Helper class for MyMoneyBudget
+ *
+ * This is an abstraction of the Account Data stored in the BUDGET tag in XML
+ *
+ * @author Darren Gould
+ */
+ class AccountGroup
+ {
+ public:
+ typedef enum
+ {
+ eNone = 0,
+ eMonthly,
+ eMonthByMonth,
+ eYearly,
+ eMax
+ } eBudgetLevel;
+
+ static const QStringList kBudgetLevelText;
+
+ public:
+ AccountGroup() : m_budgetlevel(eNone), m_budgetsubaccounts(false) {}
+
+ // get functions
+ const QString& id( void ) const { return m_id; }
+ bool budgetSubaccounts( void ) const { return m_budgetsubaccounts; }
+ eBudgetLevel budgetLevel( void ) const { return m_budgetlevel; }
+ const PeriodGroup& period( const QDate &_date ) const { return m_periods[_date]; }
+ const QMap<QDate, PeriodGroup>& getPeriods( void ) const { return m_periods; }
+ void clearPeriods(void) { m_periods.clear(); }
+ const MyMoneyMoney balance( void ) const
+ {
+ MyMoneyMoney balance;
+
+ QMap<QDate, PeriodGroup>::const_iterator it;
+ for(it = m_periods.begin(); it != m_periods.end(); ++it)
+ {
+ balance += (*it).amount();
+ }
+ return balance;
+ };
+
+ const MyMoneyMoney totalBalance(void) const
+ {
+ MyMoneyMoney bal = balance();
+ switch(m_budgetlevel) {
+ default:
+ break;
+ case eMonthly:
+ bal = bal * 12;
+ break;
+ }
+ return bal;
+ }
+
+ // set functions
+ void setId( QString _id ) { m_id = _id; }
+ void setBudgetLevel( eBudgetLevel _level ) { m_budgetlevel = _level; }
+ void setBudgetSubaccounts( bool _b ) { m_budgetsubaccounts = _b; }
+ void addPeriod( const QDate& _date, PeriodGroup &period ) { m_periods[_date] = period; }
+
+ // This member adds the value of another account group
+ // m_budgetlevel is adjusted to the larger one of both
+ // m_budgetsubaccounts remains unaffected
+ AccountGroup operator += (const AccountGroup& r);
+
+ bool operator == (const AccountGroup &r) const;
+
+ bool isZero(void) const;
+
+ protected:
+ void convertToMonthly(void);
+ void convertToYearly(void);
+ void convertToMonthByMonth(void);
+
+ private:
+ QString m_id;
+
+ eBudgetLevel m_budgetlevel;
+ bool m_budgetsubaccounts;
+ QMap<QDate, PeriodGroup> m_periods;
+ };
+
+ /**
+ * This operator tests for equality of two MyMoneyBudget objects
+ */
+ bool operator == (const MyMoneyBudget &) const;
+
+ // Simple get operations
+ const QString& name(void) const { return m_name; }
+ const QDate& budgetStart(void) const { return m_start; }
+ QString id(void) const { return m_id; }
+ const AccountGroup & account(const QString _id) const;
+ bool contains(const QString _id) const { return m_accounts.contains(_id); }
+ QValueList<AccountGroup> getaccounts(void) const { return m_accounts.values(); }
+
+ // Simple set operations
+ void setName(const QString& _name) { m_name = _name; }
+ void setBudgetStart(const QDate& _start);
+ void setAccount(const AccountGroup &_account, const QString _id);
+
+ /**
+ * This method writes this Budget to the DOM element @p e,
+ * within the DOM document @p doc.
+ *
+ * @param e The element which should be populated with info from this Budget
+ * @param doc The document which we can use to create new sub-elements
+ * if needed
+ */
+ void write(QDomElement& e, QDomDocument *doc) const;
+
+ /**
+ * This method reads a Budget from the DOM element @p e, and
+ * populates this Budget with the results.
+ *
+ * @param e The element from which the Budget should be read
+ *
+ * @return bool True if a Budget was successfully loaded from the
+ * element @p e. If false is returned, the contents of this Budget
+ * object are undefined.
+ */
+ bool read(const QDomElement& e);
+
+ /**
+ * This method creates a QDomElement for the @p document
+ * under the parent node @p parent. (This version overwrites the
+ * MMObject base class.)
+ *
+ * @param document reference to QDomDocument
+ * @param parent reference to QDomElement parent node
+ */
+ virtual void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id and the balance() returned is zero.
+ * If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ /**
+ * This member removes all references to object identified by @p id. Used
+ * to remove objects which are about to be removed from the engine.
+ */
+ void removeReference(const QString& id);
+
+private:
+ /**
+ * The user-assigned name of the Budget
+ */
+ QString m_name;
+
+ /**
+ * The user-assigned year of the Budget
+ */
+ QDate m_start;
+
+ /**
+ * Map the budgeted accounts
+ *
+ * Each account Id is stored against the AccountGroup information
+ */
+ QMap<QString, AccountGroup> m_accounts;
+};
+
+#endif // MYMONEYBudget_H
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneycategory.cpp b/kmymoney2/mymoney/mymoneycategory.cpp
new file mode 100644
index 0000000..5bf55ab
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneycategory.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ mymoneycategory.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneycategory.h"
+
+MyMoneyCategory::MyMoneyCategory()
+{
+ m_income = true;
+}
+
+MyMoneyCategory::MyMoneyCategory(const bool income, const QString name)
+{
+ m_income = income;
+ m_name = name;
+}
+
+MyMoneyCategory::MyMoneyCategory(const bool income, const QString name, QStringList minors)
+{
+ m_income = income;
+ m_name = name;
+ m_minorCategories = minors;
+}
+
+MyMoneyCategory::~MyMoneyCategory()
+{
+}
+
+// Functions use the find method to search the list
+bool MyMoneyCategory::addMinorCategory(const QString val)
+{
+ if (val.isEmpty() || val.isNull())
+ return false;
+
+ if (m_minorCategories.find(val) == m_minorCategories.end()) {
+ m_minorCategories.append(val);
+ return true;
+ }
+
+ return false;
+}
+
+bool MyMoneyCategory::removeMinorCategory(const QString val)
+{
+ if (val.isEmpty() || val.isNull())
+ return false;
+
+ if (m_minorCategories.find(val) != m_minorCategories.end()) {
+ m_minorCategories.remove(val);
+ return true;
+ }
+
+ return false;
+}
+
+bool MyMoneyCategory::renameMinorCategory(const QString oldVal, const QString newVal)
+{
+ if (oldVal.isEmpty() || oldVal.isNull() || newVal.isEmpty() || newVal.isNull())
+ return false;
+
+ if (m_minorCategories.find(oldVal) != m_minorCategories.end() &&
+ m_minorCategories.find(newVal) == m_minorCategories.end() ) {
+
+ m_minorCategories.remove(oldVal);
+ return addMinorCategory(newVal);
+ }
+
+ return false;
+}
+
+bool MyMoneyCategory::addMinorCategory(QStringList values)
+{
+ for (QStringList::Iterator it = values.begin(); it!=values.end(); ++it) {
+ addMinorCategory(*it);
+ }
+
+ return true;
+}
+
+bool MyMoneyCategory::setMinorCategories(QStringList values)
+{
+ m_minorCategories.clear();
+ return addMinorCategory(values);
+}
+
+bool MyMoneyCategory::removeAllMinors(void)
+{
+ m_minorCategories.clear();
+ return true;
+}
+
+QString MyMoneyCategory::firstMinor(void)
+{
+ return m_minorCategories.first();
+}
+
+MyMoneyCategory::MyMoneyCategory(const MyMoneyCategory& right)
+{
+ m_income = right.m_income;
+ m_name = right.m_name;
+ m_minorCategories.clear();
+ m_minorCategories = right.m_minorCategories;
+}
+
+MyMoneyCategory& MyMoneyCategory::operator = (const MyMoneyCategory& right)
+{
+ m_income = right.m_income;
+ m_name = right.m_name;
+ m_minorCategories.clear();
+ m_minorCategories = right.m_minorCategories;
+ return *this;
+}
+
+QDataStream &operator<<(QDataStream &s, MyMoneyCategory &category)
+{
+ if (category.m_income)
+ s << (Q_INT32)1;
+ else
+ s << (Q_INT32)0;
+
+ s << category.m_name;
+
+ s << (Q_UINT32)category.m_minorCategories.count();
+ for (QStringList::Iterator it = category.m_minorCategories.begin(); it!=category.m_minorCategories.end(); ++it) {
+ s << (*it);
+ }
+
+ return s;
+}
+
+QDataStream &operator>>(QDataStream &s, MyMoneyCategory &category)
+{
+ Q_INT32 inc;
+ s >> inc;
+ if (inc==0)
+ category.m_income = false;
+ else
+ category.m_income = true;
+
+ s >> category.m_name;
+
+ Q_UINT32 minorCount;
+ QString buffer;
+
+ s >> minorCount;
+ category.m_minorCategories.clear();
+ for (unsigned int i=0; i<minorCount; i++) {
+ s >> buffer;
+ category.m_minorCategories.append(buffer);
+ }
+
+ return s;
+}
+
+void MyMoneyCategory::clear(void)
+{
+ m_minorCategories.clear();
+}
diff --git a/kmymoney2/mymoney/mymoneycategory.h b/kmymoney2/mymoney/mymoneycategory.h
new file mode 100644
index 0000000..3f4babc
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneycategory.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ mymoneycategory.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYCATEGORY_H
+#define MYMONEYCATEGORY_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+/**
+ * @deprecated This class represents an Income or Expense category. Please don't
+ * use it anymore, as it will be removed sooner or later.
+ */
+class MyMoneyCategory {
+ bool m_income; // if false, m_income == expense
+ QString m_name;
+ QStringList m_minorCategories;
+
+ friend QDataStream &operator<<(QDataStream &, MyMoneyCategory &);
+ friend QDataStream &operator>>(QDataStream &, MyMoneyCategory &);
+
+public:
+ MyMoneyCategory();
+ MyMoneyCategory(const bool income, const QString name);
+ MyMoneyCategory(const bool income, const QString name, QStringList minors);
+ ~MyMoneyCategory();
+
+ // Simple get operations
+ QString name(void) { return m_name; }
+ QStringList& minorCategories(void) { return m_minorCategories; }
+
+ // Simple set operations
+ bool isIncome(void) { return m_income; }
+ void setIncome(const bool val) { m_income = val; }
+ void setName(const QString val) { m_name = val; }
+
+ bool setMinorCategories(QStringList values);
+ bool addMinorCategory(const QString val);
+ bool removeMinorCategory(const QString val);
+ bool renameMinorCategory(const QString oldVal, const QString newVal);
+ bool addMinorCategory(QStringList values);
+ bool removeAllMinors(void);
+ QString firstMinor(void);
+
+ void clear(void);
+
+ // Copy constructors
+ MyMoneyCategory(const MyMoneyCategory&);
+ MyMoneyCategory& operator = (const MyMoneyCategory&);
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyexception.cpp b/kmymoney2/mymoney/mymoneyexception.cpp
new file mode 100644
index 0000000..6b61e67
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyexception.cpp
@@ -0,0 +1,35 @@
+/***************************************************************************
+ mymoneyexception.cpp - description
+ -------------------
+ begin : Sun Apr 28 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyexception.h"
+
+MyMoneyException::MyMoneyException(const QString& msg, const QString& file, const unsigned long line)
+{
+ // qDebug("MyMoneyException(%s,%s,%d)", msg.data(), file.data(), line);
+ m_msg = msg;
+ m_file = file;
+ m_line = line;
+}
+
+MyMoneyException::~MyMoneyException()
+{
+}
diff --git a/kmymoney2/mymoney/mymoneyexception.h b/kmymoney2/mymoney/mymoneyexception.h
new file mode 100644
index 0000000..68cf2af
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyexception.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ mymoneyexception.h - description
+ -------------------
+ begin : Sun Apr 28 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYEXCEPTION_H
+#define MYMONEYEXCEPTION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <kmymoney/export.h>
+/**
+ * @file
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class describes an exception that is thrown by the engine
+ * in case of a failure.
+ */
+class KMYMONEY_EXPORT MyMoneyException {
+public:
+
+/**
+ * @def MYMONEYEXCEPTION(text)
+ * This is the preferred constructor to create a new exception
+ * object. It automatically inserts the filename and the source
+ * code line into the object upon creation.
+ *
+ * It is equivilant to MyMoneyException(text, __FILE__, __LINE__)
+ */
+#define MYMONEYEXCEPTION(a) MyMoneyException(a, __FILE__, __LINE__)
+
+ /**
+ * The constructor to create a new MyMoneyException object.
+ *
+ * @param msg reference to QString containing the message
+ * @param file reference to QString containing the name of the sourcefile where
+ * the exception was thrown
+ * @param line unsigned long containing the line number of the line where
+ * the exception was thrown in the file.
+ *
+ * An easier way to use this constructor is to use the macro
+ * MYMONEYEXCEPTION(text) instead. It automatically assigns the file
+ * and line parameter to the correct values.
+ */
+ MyMoneyException(const QString& msg, const QString& file, const unsigned long line);
+
+ ~MyMoneyException();
+
+ /**
+ * This method is used to return the message that was passed
+ * during the creation of the exception object.
+ *
+ * @return reference to QString containing the message
+ */
+ const QString& what(void) const { return m_msg; };
+
+ /**
+ * This method is used to return the filename that was passed
+ * during the creation of the exception object.
+ *
+ * @return reference to QString containing the filename
+ */
+ const QString& file(void) const { return m_file; };
+
+ /**
+ * This method is used to return the linenumber that was passed
+ * during the creation of the exception object.
+ *
+ * @return long integer containing the line number
+ */
+ unsigned long line(void) const { return m_line; };
+
+private:
+ /**
+ * This member variable holds the message
+ */
+ QString m_msg;
+
+ /**
+ * This member variable holds the filename
+ */
+ QString m_file;
+
+ /**
+ * This member variable holds the line number
+ */
+ unsigned long m_line;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyexceptiontest.cpp b/kmymoney2/mymoney/mymoneyexceptiontest.cpp
new file mode 100644
index 0000000..9d036ff
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyexceptiontest.cpp
@@ -0,0 +1,51 @@
+
+/***************************************************************************
+ mymoneyexceptiontest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyexceptiontest.h"
+
+MyMoneyExceptionTest::MyMoneyExceptionTest()
+{
+}
+
+
+void MyMoneyExceptionTest::setUp()
+{
+}
+
+void MyMoneyExceptionTest::tearDown()
+{
+}
+
+void MyMoneyExceptionTest::testDefaultConstructor()
+{
+ MyMoneyException *e = new MYMONEYEXCEPTION("Message");
+ CPPUNIT_ASSERT(e->what() == "Message");
+ CPPUNIT_ASSERT(e->line() == __LINE__-2);
+ CPPUNIT_ASSERT(e->file() == __FILE__);
+ delete e;
+}
+
+void MyMoneyExceptionTest::testConstructor()
+{
+ MyMoneyException *e = new MyMoneyException("New message",
+ "Joe's file", 1234);
+ CPPUNIT_ASSERT(e->what() == "New message");
+ CPPUNIT_ASSERT(e->line() == 1234);
+ CPPUNIT_ASSERT(e->file() == "Joe's file");
+ delete e;
+}
+
diff --git a/kmymoney2/mymoney/mymoneyexceptiontest.h b/kmymoney2/mymoney/mymoneyexceptiontest.h
new file mode 100644
index 0000000..95dbe48
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyexceptiontest.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ mymoneyexceptiontest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYEXCEPTIONTEST_H__
+#define __MYMONEYEXCEPTIONTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneyutils.h"
+#include "mymoneyexception.h"
+#undef private
+
+class MyMoneyExceptionTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyExceptionTest);
+ CPPUNIT_TEST(testDefaultConstructor);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+public:
+ MyMoneyExceptionTest();
+
+
+ void setUp();
+
+ void tearDown();
+
+ void testDefaultConstructor();
+
+ void testConstructor();
+
+};
+#endif
diff --git a/kmymoney2/mymoney/mymoneyfile.cpp b/kmymoney2/mymoney/mymoneyfile.cpp
new file mode 100644
index 0000000..3245746
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfile.cpp
@@ -0,0 +1,2332 @@
+/***************************************************************************
+ mymoneyfile.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ (C) 2002, 2007-2008 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "storage/mymoneyseqaccessmgr.h"
+#include "mymoneyfile.h"
+#include "mymoneyreport.h"
+#include "mymoneybudget.h"
+#include "mymoneyprice.h"
+#include "mymoneyobjectcontainer.h"
+
+#ifndef HAVE_CONFIG_H
+#define VERSION "UNKNOWN"
+#else
+#include "config.h"
+#endif
+
+const QString MyMoneyFile::OpeningBalancesPrefix = I18N_NOOP("Opening Balances");
+const QString MyMoneyFile::AccountSeperator = ":";
+
+// include the following line to get a 'cout' for debug purposes
+// #include <iostream>
+MyMoneyFile* MyMoneyFile::_instance = 0;
+
+class MyMoneyFile::Private
+{
+public:
+ Private() :
+ m_inTransaction(false)
+ {}
+
+ bool m_inTransaction;
+ MyMoneySecurity m_baseCurrency;
+ MyMoneyObjectContainer m_cache;
+ MyMoneyPriceList m_priceCache;
+
+ /**
+ * This member keeps a list of ids to notify after an
+ * operation is completed. The boolean is used as follows
+ * during processing of the list:
+ *
+ * false - don't reload the object immediately
+ * true - reload the object immediately
+ */
+ QMap<QString, bool> m_notificationList;
+
+};
+
+MyMoneyFile MyMoneyFile::file;
+
+MyMoneyFile::MyMoneyFile() :
+ d(new Private)
+{
+ m_storage = 0;
+}
+
+MyMoneyFile::~MyMoneyFile()
+{
+ _instance = 0;
+ delete m_storage;
+ delete d;
+}
+
+MyMoneyFile::MyMoneyFile(IMyMoneyStorage *storage) :
+ d(new Private)
+{
+ m_storage = 0;
+ attachStorage(storage);
+}
+
+void MyMoneyFile::attachStorage(IMyMoneyStorage* const storage)
+{
+ if(m_storage != 0)
+ throw new MYMONEYEXCEPTION("Storage already attached");
+
+ if(storage == 0)
+ throw new MYMONEYEXCEPTION("Storage must not be 0");
+
+ m_storage = storage;
+
+ // force reload of base currency
+ d->m_baseCurrency = MyMoneySecurity();
+
+ // and the whole cache
+ d->m_cache.clear(storage);
+ d->m_priceCache.clear();
+ preloadCache();
+
+ // notify application about new data availability
+ emit dataChanged();
+}
+
+void MyMoneyFile::detachStorage(IMyMoneyStorage* const /* storage */)
+{
+ d->m_cache.clear();
+ d->m_priceCache.clear();
+ m_storage = 0;
+}
+
+void MyMoneyFile::startTransaction(void)
+{
+ checkStorage();
+ if(d->m_inTransaction) {
+ throw new MYMONEYEXCEPTION("Already started a transaction!");
+ }
+
+ m_storage->startTransaction();
+ d->m_inTransaction = true;
+}
+
+bool MyMoneyFile::hasTransaction(void) const
+{
+ return d->m_inTransaction;
+}
+
+void MyMoneyFile::checkTransaction(const char* txt) const
+{
+ checkStorage();
+ if(!d->m_inTransaction) {
+ throw new MYMONEYEXCEPTION(QString("No transaction started for %1").arg(txt));
+ }
+}
+
+void MyMoneyFile::commitTransaction(void)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ bool changed = m_storage->commitTransaction();
+ d->m_inTransaction = false;
+ preloadCache();
+ if(changed) {
+ emit dataChanged();
+ }
+}
+
+void MyMoneyFile::rollbackTransaction(void)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ m_storage->rollbackTransaction();
+ d->m_inTransaction = false;
+ preloadCache();
+}
+
+void MyMoneyFile::addInstitution(MyMoneyInstitution& institution)
+{
+ // perform some checks to see that the institution stuff is OK. For
+ // now we assume that the institution must have a name, the ID is not set
+ // and it does not have a parent (MyMoneyFile).
+
+ if(institution.name().length() == 0
+ || institution.id().length() != 0)
+ throw new MYMONEYEXCEPTION("Not a new institution");
+
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addInstitution(institution);
+
+ d->m_cache.preloadInstitution(institution);
+}
+
+void MyMoneyFile::modifyInstitution(const MyMoneyInstitution& institution)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->modifyInstitution(institution);
+
+ addNotification(institution.id());
+}
+
+void MyMoneyFile::modifyTransaction(const MyMoneyTransaction& transaction)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ const MyMoneyTransaction* t = &transaction;
+ MyMoneyTransaction tCopy;
+
+ // now check the splits
+ bool loanAccountAffected = false;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following line will throw an exception if the
+ // account does not exist
+ MyMoneyAccount acc = MyMoneyFile::account((*it_s).accountId());
+ if(acc.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot store split with no account assigned");
+ if(isStandardAccount((*it_s).accountId()))
+ throw new MYMONEYEXCEPTION("Cannot store split referencing standard account");
+ if(acc.isLoan() && ((*it_s).action() == MyMoneySplit::ActionTransfer))
+ loanAccountAffected = true;
+ }
+
+ // change transfer splits between asset/liability and loan accounts
+ // into amortization splits
+ if(loanAccountAffected) {
+ tCopy = transaction;
+ QValueList<MyMoneySplit> list = transaction.splits();
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if((*it_s).action() == MyMoneySplit::ActionTransfer) {
+ MyMoneyAccount acc = MyMoneyFile::account((*it_s).accountId());
+
+ if(acc.isAssetLiability()) {
+ MyMoneySplit s = (*it_s);
+ s.setAction(MyMoneySplit::ActionAmortization);
+ tCopy.modifySplit(s);
+ t = &tCopy;
+ }
+ }
+ }
+ }
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // get the current setting of this transaction
+ MyMoneyTransaction tr = MyMoneyFile::transaction(transaction.id());
+
+ // scan the splits again to update notification list
+ // and mark all accounts that are referenced
+ for(it_s = tr.splits().begin(); it_s != tr.splits().end(); ++it_s) {
+ addNotification((*it_s).accountId());
+ addNotification((*it_s).payeeId());
+ }
+
+ // perform modification
+ m_storage->modifyTransaction(*t);
+
+ // and mark all accounts that are referenced
+ for(it_s = t->splits().begin(); it_s != t->splits().end(); ++it_s) {
+ addNotification((*it_s).accountId());
+ addNotification((*it_s).payeeId());
+ }
+}
+
+void MyMoneyFile::modifyAccount(const MyMoneyAccount& _account)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyAccount account(_account);
+
+ MyMoneyAccount acc = MyMoneyFile::account(account.id());
+
+ // check that for standard accounts only specific parameters are changed
+ if(isStandardAccount(account.id())) {
+ // make sure to use the stuff we found on file
+ account = acc;
+
+ // and only use the changes that are allowed
+ account.setName(_account.name());
+ account.setCurrencyId(_account.currencyId());
+
+ // now check that it is the same
+ if(!(account == _account))
+ throw new MYMONEYEXCEPTION("Unable to modify the standard account groups");
+ }
+
+ if(account.accountType() != acc.accountType())
+ throw new MYMONEYEXCEPTION("Unable to change account type");
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // if the account was moved to another insitution, we notify
+ // the old one as well as the new one and the structure change
+ if(acc.institutionId() != account.institutionId()) {
+ MyMoneyInstitution inst;
+ if(!acc.institutionId().isEmpty()) {
+ inst = institution(acc.institutionId());
+ inst.removeAccountId(acc.id());
+ modifyInstitution(inst);
+ }
+ if(!account.institutionId().isEmpty()) {
+ inst = institution(account.institutionId());
+ inst.addAccountId(acc.id());
+ modifyInstitution(inst);
+ }
+ addNotification(acc.institutionId());
+ addNotification(account.institutionId());
+ }
+
+ m_storage->modifyAccount(account);
+
+ addNotification(account.id());
+}
+
+void MyMoneyFile::reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // check that it's not one of the standard account groups
+ if(isStandardAccount(account.id()))
+ throw new MYMONEYEXCEPTION("Unable to reparent the standard account groups");
+
+ if(account.accountGroup() == parent.accountGroup()
+ || (account.accountType() == MyMoneyAccount::Income && parent.accountType() == MyMoneyAccount::Expense)
+ || (account.accountType() == MyMoneyAccount::Expense && parent.accountType() == MyMoneyAccount::Income)) {
+
+ if(account.isInvest() && parent.accountType() != MyMoneyAccount::Investment)
+ throw new MYMONEYEXCEPTION("Unable to reparent Stock to non-investment account");
+
+ if(parent.accountType() == MyMoneyAccount::Investment && !account.isInvest())
+ throw new MYMONEYEXCEPTION("Unable to reparent non-stock to investment account");
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // keep a notification of the current parent
+ addNotification(account.parentAccountId());
+
+ m_storage->reparentAccount(account, parent);
+
+ // and also keep one for the account itself and the new parent
+ addNotification(account.id());
+ addNotification(parent.id());
+
+ } else
+ throw new MYMONEYEXCEPTION("Unable to reparent to different account type");
+}
+
+const MyMoneyInstitution& MyMoneyFile::institution(const QString& id) const
+{
+ return d->m_cache.institution(id);
+}
+
+const MyMoneyAccount& MyMoneyFile::account(const QString& id) const
+{
+ return d->m_cache.account(id);
+}
+
+const MyMoneyAccount& MyMoneyFile::subAccountByName(const MyMoneyAccount& acc, const QString& name) const
+{
+ static MyMoneyAccount nullAccount;
+
+ QValueList<QString>::const_iterator it_a;
+ for(it_a = acc.accountList().begin(); it_a != acc.accountList().end(); ++it_a) {
+ const MyMoneyAccount& sacc = account(*it_a);
+ if(sacc.name() == name)
+ return sacc;
+ }
+ return nullAccount;
+}
+
+const MyMoneyAccount& MyMoneyFile::accountByName(const QString& name) const
+{
+ return d->m_cache.accountByName(name);
+}
+
+void MyMoneyFile::removeTransaction(const MyMoneyTransaction& transaction)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // get the engine's idea about this transaction
+ MyMoneyTransaction tr = MyMoneyFile::transaction(transaction.id());
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ // scan the splits again to update notification list
+ for(it_s = tr.splits().begin(); it_s != tr.splits().end(); ++it_s) {
+ MyMoneyAccount acc = account((*it_s).accountId());
+ if(acc.isClosed())
+ throw new MYMONEYEXCEPTION(i18n("Cannot remove transaction that references a closed account."));
+ addNotification((*it_s).accountId());
+ addNotification((*it_s).payeeId());
+ }
+
+ m_storage->removeTransaction(transaction);
+}
+
+
+bool MyMoneyFile::hasActiveSplits(const QString& id) const
+{
+ checkStorage();
+
+ return m_storage->hasActiveSplits(id);
+}
+
+bool MyMoneyFile::isStandardAccount(const QString& id) const
+{
+ checkStorage();
+
+ return m_storage->isStandardAccount(id);
+}
+
+void MyMoneyFile::setAccountName(const QString& id, const QString& name) const
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ m_storage->setAccountName(id, name);
+}
+
+void MyMoneyFile::removeAccount(const MyMoneyAccount& account)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyAccount parent;
+ MyMoneyAccount acc;
+ MyMoneyInstitution institution;
+
+ // check that the account and its parent exist
+ // this will throw an exception if the id is unknown
+ acc = MyMoneyFile::account(account.id());
+ parent = MyMoneyFile::account(account.parentAccountId());
+ if(!acc.institutionId().isEmpty())
+ institution = MyMoneyFile::institution(acc.institutionId());
+
+ // check that it's not one of the standard account groups
+ if(isStandardAccount(account.id()))
+ throw new MYMONEYEXCEPTION("Unable to remove the standard account groups");
+
+ if(hasActiveSplits(account.id())) {
+ throw new MYMONEYEXCEPTION("Unable to remove account with active splits");
+ }
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // collect all sub-ordinate accounts for notification
+ QStringList::ConstIterator it;
+ for(it = acc.accountList().begin(); it != acc.accountList().end(); ++it)
+ addNotification(*it);
+ // don't forget the parent and a possible institution
+ addNotification(parent.id());
+ addNotification(account.institutionId());
+
+ if(!institution.id().isEmpty()) {
+ institution.removeAccountId(account.id());
+ m_storage->modifyInstitution(institution);
+ }
+ acc.setInstitutionId(QString());
+
+ m_storage->removeAccount(acc);
+ addNotification(acc.id(), false);
+ d->m_cache.clear(acc.id());
+}
+
+void MyMoneyFile::removeAccountList(const QStringList& account_list, unsigned int level) {
+ if (level > 100)
+ throw new MYMONEYEXCEPTION("Too deep recursion in [MyMoneyFile::removeAccountList]!");
+
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // upon entry, we check that we could proceed with the operation
+ if(!level) {
+ if(!hasOnlyUnusedAccounts(account_list, 0))
+ throw new MYMONEYEXCEPTION("One or more accounts cannot be removed");
+
+ // NOTE: We don't use a MyMoneyNotifier here, but rather clear the whole cache
+ d->m_cache.clear();
+ }
+
+ // process all accounts in the list and test if they have transactions assigned
+ for (QStringList::const_iterator it = account_list.begin(); it != account_list.end(); ++it) {
+ MyMoneyAccount a = m_storage->account(*it);
+ //kdDebug() << "Deleting account '"<< a.name() << "'" << endl;
+
+ // first remove all sub-accounts
+ if (!a.accountList().isEmpty())
+ removeAccountList(a.accountList(), level+1);
+
+ // then remove account itself, but we first have to get
+ // rid of the account list that is still stored in
+ // the MyMoneyAccount object. Easiest way is to get a fresh copy.
+ a = m_storage->account(*it);
+ //kdDebug() << "Deleting account '"<< a2.name() << "' itself" << endl;
+ m_storage->removeAccount(a);
+ }
+}
+
+bool MyMoneyFile::hasOnlyUnusedAccounts(const QStringList& account_list, unsigned int level)
+{
+ if (level > 100)
+ throw new MYMONEYEXCEPTION("Too deep recursion in [MyMoneyFile::hasOnlyUnusedAccounts]!");
+ // process all accounts in the list and test if they have transactions assigned
+ for (QStringList::const_iterator it = account_list.begin(); it != account_list.end(); ++it) {
+ if (transactionCount(*it) != 0)
+ return false; // the current account has a transaction assigned
+ if (!hasOnlyUnusedAccounts(account(*it).accountList(), level+1))
+ return false; // some sub-account has a transaction assigned
+ }
+ return true; // all subaccounts unused
+}
+
+
+void MyMoneyFile::removeInstitution(const MyMoneyInstitution& institution)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ QValueList<QString>::ConstIterator it_a;
+ MyMoneyInstitution inst = MyMoneyFile::institution(institution.id());
+
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ for(it_a = inst.accountList().begin(); it_a != inst.accountList().end(); ++it_a) {
+ MyMoneyAccount acc = account(*it_a);
+ acc.setInstitutionId(QString());
+ modifyAccount(acc);
+ }
+ blockSignals(blocked);
+
+ m_storage->removeInstitution(institution);
+
+ addNotification(institution.id(), false);
+}
+
+void MyMoneyFile::addAccount(MyMoneyAccount& account, MyMoneyAccount& parent)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyInstitution institution;
+
+ // perform some checks to see that the account stuff is OK. For
+ // now we assume that the account must have a name, has no
+ // transaction and sub-accounts and parent account
+ // it's own ID is not set and it does not have a pointer to (MyMoneyFile)
+
+ if(account.name().length() == 0)
+ throw new MYMONEYEXCEPTION("Account has no name");
+
+ if(account.id().length() != 0)
+ throw new MYMONEYEXCEPTION("New account must have no id");
+
+ if(account.accountList().count() != 0)
+ throw new MYMONEYEXCEPTION("New account must have no sub-accounts");
+
+ if(!account.parentAccountId().isEmpty())
+ throw new MYMONEYEXCEPTION("New account must have no parent-id");
+
+ if(account.accountType() == MyMoneyAccount::UnknownAccountType)
+ throw new MYMONEYEXCEPTION("Account has invalid type");
+
+ // make sure, that the parent account exists
+ // if not, an exception is thrown. If it exists,
+ // get a copy of the current data
+ MyMoneyAccount acc = MyMoneyFile::account(parent.id());
+
+#if 0
+ // TODO: remove the following code as we now can have multiple accounts
+ // with the same name even in the same hierarchy position of the account tree
+ //
+ // check if the selected name is currently not among the child accounts
+ // if we find one, then return it as the new account
+ QStringList::const_iterator it_a;
+ for(it_a = acc.accountList().begin(); it_a != acc.accountList().end(); ++it_a) {
+ MyMoneyAccount a = MyMoneyFile::account(*it_a);
+ if(account.name() == a.name()) {
+ account = a;
+ return;
+ }
+ }
+#endif
+
+ // FIXME: make sure, that the parent has the same type
+ // I left it out here because I don't know, if there is
+ // a tight coupling between e.g. checking accounts and the
+ // class asset. It certainly does not make sense to create an
+ // expense account under an income account. Maybe it does, I don't know.
+
+ // We enforce, that a stock account can never be a parent and
+ // that the parent for a stock account must be an investment. Also,
+ // an investment cannot have another investment account as it's parent
+ if(parent.isInvest())
+ throw new MYMONEYEXCEPTION("Stock account cannot be parent account");
+
+ if(account.isInvest() && parent.accountType() != MyMoneyAccount::Investment)
+ throw new MYMONEYEXCEPTION("Stock account must have investment account as parent ");
+
+ if(!account.isInvest() && parent.accountType() == MyMoneyAccount::Investment)
+ throw new MYMONEYEXCEPTION("Investment account can only have stock accounts as children");
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // if an institution is set, verify that it exists
+ if(account.institutionId().length() != 0) {
+ // check the presence of the institution. if it
+ // does not exist, an exception is thrown
+ institution = MyMoneyFile::institution(account.institutionId());
+ }
+
+
+ if(!account.openingDate().isValid()) {
+ account.setOpeningDate(QDate::currentDate());
+ }
+
+ account.setParentAccountId(parent.id());
+
+ m_storage->addAccount(account);
+ m_storage->addAccount(parent, account);
+
+ if(account.institutionId().length() != 0) {
+ institution.addAccountId(account.id());
+ m_storage->modifyInstitution(institution);
+ addNotification(institution.id());
+ }
+
+ d->m_cache.preloadAccount(account);
+ addNotification(parent.id());
+}
+
+MyMoneyTransaction MyMoneyFile::createOpeningBalanceTransaction(const MyMoneyAccount& acc, const MyMoneyMoney& balance)
+{
+ MyMoneyTransaction t;
+ // if the opening balance is not zero, we need
+ // to create the respective transaction
+ if(!balance.isZero()) {
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneySecurity currency = security(acc.currencyId());
+ MyMoneyAccount openAcc = openingBalanceAccount(currency);
+
+ if(openAcc.openingDate() > acc.openingDate()) {
+ openAcc.setOpeningDate(acc.openingDate());
+ modifyAccount(openAcc);
+ }
+
+ MyMoneySplit s;
+
+ t.setPostDate(acc.openingDate());
+ t.setCommodity(acc.currencyId());
+
+ s.setAccountId(acc.id());
+ s.setShares(balance);
+ s.setValue(balance);
+ t.addSplit(s);
+
+ s.clearId();
+ s.setAccountId(openAcc.id());
+ s.setShares(-balance);
+ s.setValue(-balance);
+ t.addSplit(s);
+
+ addTransaction(t);
+ }
+ return t;
+}
+
+QString MyMoneyFile::openingBalanceTransaction(const MyMoneyAccount& acc) const
+{
+ QString result;
+
+ MyMoneySecurity currency = security(acc.currencyId());
+ MyMoneyAccount openAcc;
+
+ try
+ {
+ openAcc = openingBalanceAccount(currency);
+ }
+ catch(MyMoneyException *e)
+ {
+ delete e;
+ return result;
+ }
+
+ // Iterate over all the opening balance transactions for this currency
+ MyMoneyTransactionFilter filter;
+ filter.addAccount(openAcc.id());
+ QValueList<MyMoneyTransaction> transactions = transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();
+ while ( it_t != transactions.end() )
+ {
+ try
+ {
+ // Test whether the transaction also includes a split into
+ // this account
+ (*it_t).splitByAccount(acc.id(), true /*match*/);
+
+ // If so, we have a winner!
+ result = (*it_t).id();
+ break;
+ }
+ catch(MyMoneyException *e)
+ {
+ // If not, keep searching
+ ++it_t;
+ delete e;
+ }
+ }
+
+ return result;
+}
+
+const MyMoneyAccount MyMoneyFile::openingBalanceAccount(const MyMoneySecurity& security)
+{
+ if(!security.isCurrency())
+ throw new MYMONEYEXCEPTION("Opening balance for non currencies not supported");
+
+ try
+ {
+ return openingBalanceAccount_internal(security);
+ }
+ catch(MyMoneyException *e)
+ {
+ delete e;
+ MyMoneyFileTransaction ft;
+ MyMoneyAccount acc;
+
+ try {
+ acc = createOpeningBalanceAccount(security);
+ ft.commit();
+
+ } catch(MyMoneyException* e) {
+ qDebug("Unable to create opening balance account for security %s", security.id().data());
+ delete e;
+ }
+ return acc;
+ }
+}
+
+const MyMoneyAccount MyMoneyFile::openingBalanceAccount(const MyMoneySecurity& security) const
+{
+ return openingBalanceAccount_internal(security);
+}
+
+const MyMoneyAccount MyMoneyFile::openingBalanceAccount_internal(const MyMoneySecurity& security) const
+{
+ if(!security.isCurrency())
+ throw new MYMONEYEXCEPTION("Opening balance for non currencies not supported");
+
+ MyMoneyAccount acc;
+ QRegExp match(QString("^%1").arg(i18n(MyMoneyFile::OpeningBalancesPrefix)));
+
+ QValueList<MyMoneyAccount> accounts;
+ QValueList<MyMoneyAccount>::Iterator it;
+
+ accountList(accounts, equity().accountList(), true);
+
+ for(it = accounts.begin(); it != accounts.end(); ++it) {
+ if(match.search((*it).name()) != -1) {
+ if((*it).currencyId() == security.id()) {
+ acc = *it;
+ break;
+ }
+ }
+ }
+
+ if(acc.id().isEmpty()) {
+ throw new MYMONEYEXCEPTION(QString("No opening balance account for %1").arg(security.tradingSymbol()));
+ }
+
+ return acc;
+}
+
+const MyMoneyAccount MyMoneyFile::createOpeningBalanceAccount(const MyMoneySecurity& security)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyAccount acc;
+ QString name(i18n(MyMoneyFile::OpeningBalancesPrefix));
+ if(security.id() != baseCurrency().id()) {
+ name += QString(" (%1)").arg(security.id());
+ }
+ acc.setName(name);
+ acc.setAccountType(MyMoneyAccount::Equity);
+ acc.setCurrencyId(security.id());
+
+ MyMoneyAccount parent = equity();
+ this->addAccount(acc, parent);
+ return acc;
+}
+
+void MyMoneyFile::addTransaction(MyMoneyTransaction& transaction)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // perform some checks to see that the transaction stuff is OK. For
+ // now we assume that
+ // * no ids are assigned
+ // * the date valid (must not be empty)
+ // * the referenced accounts in the splits exist
+
+ // first perform all the checks
+ if(!transaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Unable to add transaction with id set");
+ if(!transaction.postDate().isValid())
+ throw new MYMONEYEXCEPTION("Unable to add transaction with invalid postdate");
+
+ // now check the splits
+ bool loanAccountAffected = false;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following line will throw an exception if the
+ // account does not exist or is one of the standard accounts
+ MyMoneyAccount acc = MyMoneyFile::account((*it_s).accountId());
+ if(acc.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot add split with no account assigned");
+ if(acc.isLoan())
+ loanAccountAffected = true;
+ if(isStandardAccount((*it_s).accountId()))
+ throw new MYMONEYEXCEPTION("Cannot add split referencing standard account");
+ }
+
+ // change transfer splits between asset/liability and loan accounts
+ // into amortization splits
+ if(loanAccountAffected) {
+ QValueList<MyMoneySplit> list = transaction.splits();
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if((*it_s).action() == MyMoneySplit::ActionTransfer) {
+ MyMoneyAccount acc = MyMoneyFile::account((*it_s).accountId());
+
+ if(acc.isAssetLiability()) {
+ MyMoneySplit s = (*it_s);
+ s.setAction(MyMoneySplit::ActionAmortization);
+ transaction.modifySplit(s);
+ }
+ }
+ }
+ }
+
+ // check that we have a commodity
+ if(transaction.commodity().isEmpty()) {
+ transaction.setCommodity(baseCurrency().id());
+ }
+
+ // then add the transaction to the file global pool
+ m_storage->addTransaction(transaction);
+
+ // scan the splits again to update notification list
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ addNotification((*it_s).accountId());
+ addNotification((*it_s).payeeId());
+ }
+}
+
+const MyMoneyTransaction MyMoneyFile::transaction(const QString& id) const
+{
+ checkStorage();
+
+ return m_storage->transaction(id);
+}
+
+const MyMoneyTransaction MyMoneyFile::transaction(const QString& account, const int idx) const
+{
+ checkStorage();
+
+ return m_storage->transaction(account, idx);
+}
+
+void MyMoneyFile::addPayee(MyMoneyPayee& payee)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addPayee(payee);
+
+ d->m_cache.preloadPayee(payee);
+}
+
+const MyMoneyPayee& MyMoneyFile::payee(const QString& id) const
+{
+ return d->m_cache.payee(id);
+}
+
+const MyMoneyPayee& MyMoneyFile::payeeByName(const QString& name) const
+{
+ checkStorage();
+
+ return d->m_cache.payee(m_storage->payeeByName(name).id());
+}
+
+void MyMoneyFile::modifyPayee(const MyMoneyPayee& payee)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ addNotification(payee.id());
+
+ m_storage->modifyPayee(payee);
+}
+
+void MyMoneyFile::removePayee(const MyMoneyPayee& payee)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removePayee(payee);
+
+ addNotification(payee.id(), false);
+}
+
+void MyMoneyFile::accountList(QValueList<MyMoneyAccount>& list, const QStringList& idlist, const bool recursive) const
+{
+ if(idlist.isEmpty()) {
+ d->m_cache.account(list);
+
+#if 0
+ // TODO: I have no idea what this was good for, but it caused the networth report
+ // to show double the numbers so I commented it out (ipwizard, 2008-05-24)
+ if (m_storage && (list.isEmpty() || list.size() != m_storage->accountCount())) {
+ m_storage->accountList(list);
+ d->m_cache.preloadAccount(list);
+ }
+#endif
+
+ QValueList<MyMoneyAccount>::Iterator it;
+ QValueList<MyMoneyAccount>::Iterator next;
+ for(it = list.begin(); it != list.end(); ) {
+ if(isStandardAccount( (*it).id() )) {
+ it = list.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ } else {
+ QValueList<MyMoneyAccount>::ConstIterator it;
+ QValueList<MyMoneyAccount> list_a;
+ d->m_cache.account(list_a);
+
+ for(it = list_a.begin(); it != list_a.end(); ++it) {
+ if(!isStandardAccount((*it).id())) {
+ if(idlist.findIndex((*it).id()) != -1) {
+ list.append(*it);
+ if(recursive == true) {
+ accountList(list, (*it).accountList(), true);
+ }
+ }
+ }
+ }
+ }
+}
+
+void MyMoneyFile::institutionList(QValueList<MyMoneyInstitution>& list) const
+{
+ d->m_cache.institution(list);
+}
+
+const QValueList<MyMoneyInstitution> MyMoneyFile::institutionList(void) const
+{
+ QValueList<MyMoneyInstitution> list;
+ institutionList(list);
+ return list;
+}
+
+// general get functions
+const MyMoneyPayee MyMoneyFile::user(void) const { checkStorage(); return m_storage->user(); }
+
+// general set functions
+void MyMoneyFile::setUser(const MyMoneyPayee& user)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->setUser(user);
+}
+
+bool MyMoneyFile::dirty(void) const
+{
+ if(!m_storage)
+ return false;
+
+ return m_storage->dirty();
+}
+
+void MyMoneyFile::setDirty(void) const
+{
+ checkStorage();
+
+ m_storage->setDirty();
+}
+
+unsigned int MyMoneyFile::accountCount(void) const
+{
+ checkStorage();
+
+ return m_storage->accountCount();
+}
+
+void MyMoneyFile::ensureDefaultCurrency(MyMoneyAccount& acc) const
+{
+ if(acc.currencyId().isEmpty()) {
+ if(!baseCurrency().id().isEmpty())
+ acc.setCurrencyId(baseCurrency().id());
+ }
+}
+
+const MyMoneyAccount& MyMoneyFile::liability(void) const
+{
+ checkStorage();
+
+ return d->m_cache.account (STD_ACC_LIABILITY);
+}
+
+const MyMoneyAccount& MyMoneyFile::asset(void) const
+{
+ checkStorage();
+
+ return d->m_cache.account (STD_ACC_ASSET);
+}
+
+const MyMoneyAccount& MyMoneyFile::expense(void) const
+{
+ checkStorage();
+
+ return d->m_cache.account (STD_ACC_EXPENSE);
+}
+
+const MyMoneyAccount& MyMoneyFile::income(void) const
+{
+ checkStorage();
+
+ return d->m_cache.account (STD_ACC_INCOME);
+}
+
+const MyMoneyAccount& MyMoneyFile::equity(void) const
+{
+ checkStorage();
+
+ return d->m_cache.account (STD_ACC_EQUITY);
+}
+
+unsigned int MyMoneyFile::transactionCount(const QString& account) const
+{
+ checkStorage();
+
+ return m_storage->transactionCount(account);
+}
+
+const QMap<QString, unsigned long> MyMoneyFile::transactionCountMap(void) const
+{
+ checkStorage();
+
+ return m_storage->transactionCountMap();
+}
+
+unsigned int MyMoneyFile::institutionCount(void) const
+{
+ checkStorage();
+
+ return m_storage->institutionCount();
+}
+
+const MyMoneyMoney MyMoneyFile::balance(const QString& id, const QDate& date) const
+{
+ checkStorage();
+
+ return m_storage->balance(id, date);
+}
+
+const MyMoneyMoney MyMoneyFile::totalBalance(const QString& id, const QDate& date) const
+{
+ checkStorage();
+
+ return m_storage->totalBalance(id, date);
+}
+
+void MyMoneyFile::warningMissingRate(const QString& fromId, const QString& toId) const
+{
+ MyMoneySecurity from, to;
+ try {
+ from = security(fromId);
+ to = security(toId);
+ qWarning("Missing price info for conversion from %s to %s", from.name().latin1(), to.name().latin1());
+
+ } catch(MyMoneyException *e) {
+ qFatal("Missing security caught in MyMoneyFile::warningMissingRate(): %s(%ld) %s", e->file().data(), e->line(), e->what().data());
+ delete e;
+ }
+}
+
+void MyMoneyFile::notify(void)
+{
+ QMap<QString, bool>::ConstIterator it;
+ for(it = d->m_notificationList.begin(); it != d->m_notificationList.end(); ++it) {
+ if(*it)
+ d->m_cache.refresh(it.key());
+ else
+ d->m_cache.clear(it.key());
+ }
+ clearNotification();
+}
+
+void MyMoneyFile::addNotification(const QString& id, bool reload)
+{
+ if(!id.isEmpty())
+ d->m_notificationList[id] = reload;
+}
+
+void MyMoneyFile::clearNotification()
+{
+ // reset list to be empty
+ d->m_notificationList.clear();
+}
+
+void MyMoneyFile::transactionList(QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const
+{
+ checkStorage();
+ m_storage->transactionList(list, filter);
+}
+
+void MyMoneyFile::transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const
+{
+ checkStorage();
+ m_storage->transactionList(list, filter);
+}
+
+const QValueList<MyMoneyTransaction> MyMoneyFile::transactionList(MyMoneyTransactionFilter& filter) const
+{
+ QValueList<MyMoneyTransaction> list;
+ transactionList(list, filter);
+ return list;
+}
+
+const QValueList<MyMoneyPayee> MyMoneyFile::payeeList(void) const
+{
+ QValueList<MyMoneyPayee> list;
+ d->m_cache.payee(list);
+ return list;
+}
+
+QString MyMoneyFile::accountToCategory(const QString& accountId, bool includeStandardAccounts) const
+{
+ MyMoneyAccount acc;
+ QString rc;
+
+ if(!accountId.isEmpty()) {
+ acc = account(accountId);
+ do {
+ if(!rc.isEmpty())
+ rc = AccountSeperator + rc;
+ rc = acc.name() + rc;
+ acc = account(acc.parentAccountId());
+ } while(!acc.id().isEmpty() && (includeStandardAccounts || !isStandardAccount(acc.id())));
+ }
+ return rc;
+}
+
+QString MyMoneyFile::categoryToAccount(const QString& category, MyMoneyAccount::accountTypeE type) const
+{
+ QString id;
+
+ // search the category in the expense accounts and if it is not found, try
+ // to locate it in the income accounts
+ if(type == MyMoneyAccount::UnknownAccountType
+ || type == MyMoneyAccount::Expense) {
+ id = locateSubAccount(MyMoneyFile::instance()->expense(), category);
+ }
+
+ if((id.isEmpty() && type == MyMoneyAccount::UnknownAccountType)
+ || type == MyMoneyAccount::Income) {
+ id = locateSubAccount(MyMoneyFile::instance()->income(), category);
+ }
+
+ return id;
+}
+
+QString MyMoneyFile::nameToAccount(const QString& name) const
+{
+ QString id;
+
+ // search the category in the asset accounts and if it is not found, try
+ // to locate it in the liability accounts
+ id = locateSubAccount(MyMoneyFile::instance()->asset(), name);
+ if(id.isEmpty())
+ id = locateSubAccount(MyMoneyFile::instance()->liability(), name);
+
+ return id;
+}
+
+QString MyMoneyFile::parentName(const QString& name) const
+{
+ return name.section(AccountSeperator, 0, -2);
+}
+
+QString MyMoneyFile::locateSubAccount(const MyMoneyAccount& base, const QString& category) const
+{
+ MyMoneyAccount nextBase;
+ QString level, remainder;
+ level = category.section(AccountSeperator, 0, 0);
+ remainder = category.section(AccountSeperator, 1);
+
+ QStringList list = base.accountList();
+ QStringList::ConstIterator it_a;
+
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ nextBase = account(*it_a);
+ if(nextBase.name() == level) {
+ if(remainder.isEmpty()) {
+ return nextBase.id();
+ }
+ return locateSubAccount(nextBase, remainder);
+ }
+ }
+ return QString();
+}
+
+QString MyMoneyFile::value(const QString& key) const
+{
+ checkStorage();
+
+ return m_storage->value(key);
+}
+
+void MyMoneyFile::setValue(const QString& key, const QString& val)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->setValue(key, val);
+}
+
+void MyMoneyFile::deletePair(const QString& key)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->deletePair(key);
+}
+
+void MyMoneyFile::addSchedule(MyMoneySchedule& sched)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyTransaction transaction = sched.transaction();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following line will throw an exception if the
+ // account does not exist or is one of the standard accounts
+ MyMoneyAccount acc = MyMoneyFile::account((*it_s).accountId());
+ if(acc.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot add split with no account assigned");
+ if(isStandardAccount((*it_s).accountId()))
+ throw new MYMONEYEXCEPTION("Cannot add split referencing standard account");
+ }
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addSchedule(sched);
+}
+
+void MyMoneyFile::modifySchedule(const MyMoneySchedule& sched)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyTransaction transaction = sched.transaction();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following line will throw an exception if the
+ // account does not exist or is one of the standard accounts
+ MyMoneyAccount acc = MyMoneyFile::account((*it_s).accountId());
+ if(acc.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot store split with no account assigned");
+ if(isStandardAccount((*it_s).accountId()))
+ throw new MYMONEYEXCEPTION("Cannot store split referencing standard account");
+ }
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->modifySchedule(sched);
+
+ addNotification(sched.id());
+}
+
+void MyMoneyFile::removeSchedule(const MyMoneySchedule& sched)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removeSchedule(sched);
+
+ addNotification(sched.id(), false);
+}
+
+const MyMoneySchedule MyMoneyFile::schedule(const QString& id) const
+{
+ return d->m_cache.schedule(id);
+}
+
+const QValueList<MyMoneySchedule> MyMoneyFile::scheduleList(
+ const QString& accountId,
+ const MyMoneySchedule::typeE type,
+ const MyMoneySchedule::occurenceE occurence,
+ const MyMoneySchedule::paymentTypeE paymentType,
+ const QDate& startDate,
+ const QDate& endDate,
+ const bool overdue) const
+{
+ checkStorage();
+
+ return m_storage->scheduleList(accountId, type, occurence, paymentType, startDate, endDate, overdue);
+}
+
+
+const QStringList MyMoneyFile::consistencyCheck(void)
+{
+ QValueList<MyMoneyAccount> list;
+ QValueList<MyMoneyAccount>::Iterator it_a;
+ QValueList<MyMoneySchedule>::Iterator it_sch;
+ QValueList<MyMoneyPayee>::Iterator it_p;
+ QValueList<MyMoneyTransaction>::Iterator it_t;
+ QValueList<MyMoneyReport>::Iterator it_r;
+ QStringList accountRebuild;
+ QStringList::ConstIterator it_c;
+
+ QMap<QString, bool> interestAccounts;
+
+ MyMoneyAccount parent;
+ MyMoneyAccount child;
+ MyMoneyAccount toplevel;
+
+ QString parentId;
+ QStringList rc;
+
+ int problemCount = 0;
+ int unfixedCount = 0;
+ QString problemAccount;
+
+ // check that we have a storage object
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // get the current list of accounts
+ accountList(list);
+ // add the standard accounts
+ list << MyMoneyFile::instance()->asset();
+ list << MyMoneyFile::instance()->liability();
+ list << MyMoneyFile::instance()->income();
+ list << MyMoneyFile::instance()->expense();
+
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ // no more checks for standard accounts
+ if(isStandardAccount((*it_a).id())) {
+ continue;
+ }
+
+ switch((*it_a).accountGroup()) {
+ case MyMoneyAccount::Asset:
+ toplevel = asset();
+ break;
+ case MyMoneyAccount::Liability:
+ toplevel = liability();
+ break;
+ case MyMoneyAccount::Expense:
+ toplevel = expense();
+ break;
+ case MyMoneyAccount::Income:
+ toplevel = income();
+ break;
+ case MyMoneyAccount::Equity:
+ toplevel = equity();
+ break;
+ default:
+ qWarning("%s:%d This should never happen!", __FILE__ , __LINE__);
+ break;
+ }
+
+ // check for loops in the hierarchy
+ parentId = (*it_a).parentAccountId();
+ try {
+ bool dropOut = false;
+ while(!isStandardAccount(parentId) && !dropOut) {
+ parent = account(parentId);
+ if(parent.id() == (*it_a).id()) {
+ // parent loops, so we need to re-parent to toplevel account
+ // find parent account in our list
+ problemCount++;
+ QValueList<MyMoneyAccount>::Iterator it_b;
+ for(it_b = list.begin(); it_b != list.end(); ++it_b) {
+ if((*it_b).id() == parent.id()) {
+ if(problemAccount != (*it_a).name()) {
+ problemAccount = (*it_a).name();
+ rc << i18n("* Problem with account '%1'").arg(problemAccount);
+ rc << i18n(" * Loop detected between this account and account '%2'.").arg((*it_b).name());
+ rc << i18n(" Reparenting account '%2' to top level account '%1'.").arg(toplevel.name(), (*it_a).name());
+ (*it_a).setParentAccountId(toplevel.id());
+ if(accountRebuild.contains(toplevel.id()) == 0)
+ accountRebuild << toplevel.id();
+ if(accountRebuild.contains((*it_a).id()) == 0)
+ accountRebuild << (*it_a).id();
+ dropOut = true;
+ break;
+ }
+ }
+ }
+ }
+ parentId = parent.parentAccountId();
+ }
+
+ } catch(MyMoneyException *e) {
+ // if we don't know about a parent, we catch it later
+ delete e;
+ }
+
+ // check that the parent exists
+ parentId = (*it_a).parentAccountId();
+ try {
+ parent = account(parentId);
+ if((*it_a).accountGroup() != parent.accountGroup()) {
+ problemCount++;
+ if(problemAccount != (*it_a).name()) {
+ problemAccount = (*it_a).name();
+ rc << i18n("* Problem with account '%1'").arg(problemAccount);
+ }
+ // the parent belongs to a different group, so we reconnect to the
+ // master group account (asset, liability, etc) to which this account
+ // should belong and update it in the engine.
+ rc << i18n(" * Parent account '%1' belongs to a different group.").arg(parent.name());
+ rc << i18n(" New parent account is the top level account '%1'.").arg(toplevel.name());
+ (*it_a).setParentAccountId(toplevel.id());
+
+ // make sure to rebuild the sub-accounts of the top account
+ // and the one we removed this account from
+ if(accountRebuild.contains(toplevel.id()) == 0)
+ accountRebuild << toplevel.id();
+ if(accountRebuild.contains(parent.id()) == 0)
+ accountRebuild << parent.id();
+ } else if(!parent.accountList().contains((*it_a).id())) {
+ problemCount++;
+ if(problemAccount != (*it_a).name()) {
+ problemAccount = (*it_a).name();
+ rc << i18n("* Problem with account '%1'").arg(problemAccount);
+ }
+ // parent exists, but does not have a reference to the account
+ rc << i18n(" * Parent account '%1' does not contain '%2' as sub-account.").arg(parent.name(), problemAccount);
+ if(accountRebuild.contains(parent.id()) == 0)
+ accountRebuild << parent.id();
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ // apparently, the parent does not exist anymore. we reconnect to the
+ // master group account (asset, liability, etc) to which this account
+ // should belong and update it in the engine.
+ problemCount++;
+ if(problemAccount != (*it_a).name()) {
+ problemAccount = (*it_a).name();
+ rc << i18n("* Problem with account '%1'").arg(problemAccount);
+ }
+ rc << i18n(" * The parent with id %1 does not exist anymore.").arg(parentId);
+ rc << i18n(" New parent account is the top level account '%1'.").arg(toplevel.name());
+ (*it_a).setParentAccountId(toplevel.id());
+
+ addNotification((*it_a).id());
+
+ // make sure to rebuild the sub-accounts of the top account
+ if(accountRebuild.contains(toplevel.id()) == 0)
+ accountRebuild << toplevel.id();
+ }
+
+ // now check that all the children exist and have the correct type
+ for(it_c = (*it_a).accountList().begin(); it_c != (*it_a).accountList().end(); ++it_c) {
+ // check that the child exists
+ try {
+ child = account(*it_c);
+ } catch(MyMoneyException *e) {
+ problemCount++;
+ if(problemAccount != (*it_a).name()) {
+ problemAccount = (*it_a).name();
+ rc << i18n("* Problem with account '%1'").arg(problemAccount);
+ }
+ rc << i18n(" * Child account with id %1 does not exist anymore.").arg(*it_c);
+ rc << i18n(" The child account list will be reconstructed.");
+ if(accountRebuild.contains((*it_a).id()) == 0)
+ accountRebuild << (*it_a).id();
+ }
+ }
+
+ // see if it is a loan account. if so, remember the assigned interest account
+ if((*it_a).isLoan()) {
+ const MyMoneyAccountLoan* loan = dynamic_cast<MyMoneyAccountLoan*>(&(*it_a));
+ if(!loan->interestAccountId().isEmpty())
+ interestAccounts[loan->interestAccountId()] = true;
+ }
+
+ // if the account was modified, we need to update it in the engine
+ if(!(m_storage->account((*it_a).id()) == (*it_a))) {
+ try {
+ m_storage->modifyAccount(*it_a, true);
+ addNotification((*it_a).id());
+ } catch (MyMoneyException *e) {
+ delete e;
+ rc << i18n(" * Unable to update account data in engine.");
+ return rc;
+ }
+ }
+ }
+
+ if(accountRebuild.count() != 0) {
+ rc << i18n("* Reconstructing the child lists for");
+ }
+
+ // clear the affected lists
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ if(accountRebuild.contains((*it_a).id())) {
+ rc << QString(" %1").arg((*it_a).name());
+ // clear the account list
+ for(it_c = (*it_a).accountList().begin(); it_c != (*it_a).accountList().end();) {
+ (*it_a).removeAccountId(*it_c);
+ it_c = (*it_a).accountList().begin();
+ }
+ }
+ }
+
+ // reconstruct the lists
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ QValueList<MyMoneyAccount>::Iterator it;
+ parentId = (*it_a).parentAccountId();
+ if(accountRebuild.contains(parentId)) {
+ for(it = list.begin(); it != list.end(); ++it) {
+ if((*it).id() == parentId) {
+ (*it).addAccountId((*it_a).id());
+ break;
+ }
+ }
+ }
+ }
+
+ // update the engine objects
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ if(accountRebuild.contains((*it_a).id())) {
+ try {
+ m_storage->modifyAccount(*it_a, true);
+ addNotification((*it_a).id());
+ } catch (MyMoneyException *e) {
+ delete e;
+ rc << i18n(" * Unable to update account data for account %1 in engine").arg((*it_a).name());
+ }
+ }
+ }
+
+ // For some reason, files exist with invalid ids. This has been found in the payee id
+ // so we fix them here
+ QValueList<MyMoneyPayee> pList = payeeList();
+ QMap<QString, QString>payeeConversionMap;
+
+ for(it_p = pList.begin(); it_p != pList.end(); ++it_p) {
+ if((*it_p).id().length() > 7) {
+ // found one of those with an invalid ids
+ // create a new one and store it in the map.
+ MyMoneyPayee payee = (*it_p);
+ payee.clearId();
+ m_storage->addPayee(payee);
+ payeeConversionMap[(*it_p).id()] = payee.id();
+ rc << i18n(" * Payee %1 recreated with fixed id").arg(payee.name());
+ ++problemCount;
+ }
+ }
+
+ // Fix the transactions
+ QValueList<MyMoneyTransaction> tList;
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits(false);
+ m_storage->transactionList(tList, filter);
+ // Generate the list of interest accounts
+ for(it_t = tList.begin(); it_t != tList.end(); ++it_t) {
+ const MyMoneyTransaction& t = (*it_t);
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).action() == MyMoneySplit::ActionInterest)
+ interestAccounts[(*it_s).accountId()] = true;
+ }
+ }
+ for(it_t = tList.begin(); it_t != tList.end(); ++it_t) {
+ MyMoneyTransaction t = (*it_t);
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ bool tChanged = false;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ bool sChanged = false;
+ MyMoneySplit s = (*it_s);
+ if(payeeConversionMap.find((*it_s).payeeId()) != payeeConversionMap.end()) {
+ s.setPayeeId(payeeConversionMap[s.payeeId()]);
+ sChanged = true;
+ rc << i18n(" * Payee id updated in split of transaction '%1'.").arg(t.id());
+ ++problemCount;
+ }
+
+ // make sure, that shares and value have the same number if they
+ // represent the same currency.
+ try {
+ const MyMoneyAccount& acc = this->account(s.accountId());
+ if(t.commodity() == acc.currencyId()
+ && s.shares().reduce() != s.value().reduce()) {
+ // use the value as master if the transaction is balanced
+ if(t.splitSum().isZero()) {
+ s.setShares(s.value());
+ rc << i18n(" * shares set to value in split of transaction '%1'.").arg(t.id());
+ } else {
+ s.setValue(s.shares());
+ rc << i18n(" * value set to shares in split of transaction '%1'.").arg(t.id());
+ }
+ sChanged = true;
+ ++problemCount;
+ }
+ } catch(MyMoneyException *e) {
+ rc << i18n(" * Split %2 in transaction '%1' contains a reference to invalid account %3. Please fix manually.").arg(t.id(), (*it_s).id(), (*it_s).accountId());
+ ++problemCount;
+ ++unfixedCount;
+ delete e;
+ }
+
+ // make sure the interest splits are marked correct as such
+ if(interestAccounts.find(s.accountId()) != interestAccounts.end()
+ && s.action() != MyMoneySplit::ActionInterest) {
+ s.setAction(MyMoneySplit::ActionInterest);
+ sChanged = true;
+ rc << i18n(" * action marked as interest in split of transaction '%1'.").arg(t.id());
+ ++problemCount;
+ }
+
+ if(sChanged) {
+ tChanged = true;
+ t.modifySplit(s);
+ }
+ }
+ if(tChanged) {
+ m_storage->modifyTransaction(t);
+ }
+ }
+
+ // Fix the schedules
+ QValueList<MyMoneySchedule> schList = scheduleList();
+ for(it_sch = schList.begin(); it_sch != schList.end(); ++it_sch) {
+ MyMoneySchedule sch = (*it_sch);
+ MyMoneyTransaction t = sch.transaction();
+ bool tChanged = false;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ MyMoneySplit s = (*it_s);
+ bool sChanged = false;
+ if(payeeConversionMap.find((*it_s).payeeId()) != payeeConversionMap.end()) {
+ s.setPayeeId(payeeConversionMap[s.payeeId()]);
+ sChanged = true;
+ rc << i18n(" * Payee id updated in split of schedule '%1'.").arg((*it_sch).name());
+ ++problemCount;
+ }
+ if(!(*it_s).value().isZero() && (*it_s).shares().isZero()) {
+ s.setShares(s.value());
+ sChanged = true;
+ rc << i18n(" * Split in scheduled transaction '%1' contained value != 0 and shares == 0.").arg((*it_sch).name());
+ rc << i18n(" Shares set to value.");
+ ++problemCount;
+ }
+
+ // make sure, we don't have a bankid stored with a split in a schedule
+ if(!(*it_s).bankID().isEmpty()) {
+ s.setBankID(QString());
+ sChanged = true;
+ rc << i18n(" * Removed bankid from split in scheduled transaction '%1'.").arg((*it_sch).name());
+ ++problemCount;
+ }
+
+ // make sure, that shares and value have the same number if they
+ // represent the same currency.
+ try {
+ const MyMoneyAccount& acc = this->account(s.accountId());
+ if(t.commodity() == acc.currencyId()
+ && s.shares().reduce() != s.value().reduce()) {
+ // use the value as master if the transaction is balanced
+ if(t.splitSum().isZero()) {
+ s.setShares(s.value());
+ rc << i18n(" * shares set to value in split in schedule '%1'.").arg((*it_sch).name());
+ } else {
+ s.setValue(s.shares());
+ rc << i18n(" * value set to shares in split in schedule '%1'.").arg((*it_sch).name());
+ }
+ sChanged = true;
+ ++problemCount;
+ }
+ } catch(MyMoneyException *e) {
+ rc << i18n(" * Split %2 in schedule '%1' contains a reference to invalid account %3. Please fix manually.").arg((*it_sch).name(), (*it_s).id(), (*it_s).accountId());
+ ++problemCount;
+ ++unfixedCount;
+ delete e;
+ }
+ if(sChanged) {
+ t.modifySplit(s);
+ tChanged = true;
+ }
+ }
+ if(tChanged) {
+ sch.setTransaction(t);
+ m_storage->modifySchedule(sch);
+ }
+ }
+
+ // Fix the reports
+ QValueList<MyMoneyReport> rList = reportList();
+ for(it_r = rList.begin(); it_r != rList.end(); ++it_r) {
+ MyMoneyReport r = *it_r;
+ QStringList pList;
+ QStringList::Iterator it_p;
+ (*it_r).payees(pList);
+ bool rChanged = false;
+ for(it_p = pList.begin(); it_p != pList.end(); ++it_p) {
+ if(payeeConversionMap.find(*it_p) != payeeConversionMap.end()) {
+ rc << i18n(" * Payee id updated in report '%1'.").arg((*it_r).name());
+ ++problemCount;
+ r.removeReference(*it_p);
+ r.addPayee(payeeConversionMap[*it_p]);
+ rChanged = true;
+ }
+ }
+ if(rChanged) {
+ m_storage->modifyReport(r);
+ }
+ }
+
+ // erase old payee ids
+ QMap<QString, QString>::Iterator it_m;
+ for(it_m = payeeConversionMap.begin(); it_m != payeeConversionMap.end(); ++it_m) {
+ MyMoneyPayee payee = this->payee(it_m.key());
+ removePayee(payee);
+ rc << i18n(" * Payee '%1' removed.").arg(payee.id());
+ ++problemCount;
+ }
+
+ // add more checks here
+
+ if(problemCount == 0)
+ rc << i18n("Finish! Data is consistent.");
+ else
+ rc << i18n("Finish! %1 problem(s) corrected. %2 problem(s) still present.")
+ .arg(problemCount).arg(unfixedCount);
+
+ return rc;
+}
+
+QString MyMoneyFile::createCategory(const MyMoneyAccount& base, const QString& name)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ MyMoneyAccount parent = base;
+ QString categoryText;
+
+ if(base.id() != expense().id() && base.id() != income().id())
+ throw new MYMONEYEXCEPTION("Invalid base category");
+
+ QStringList subAccounts = QStringList::split(AccountSeperator, name);
+ QStringList::Iterator it;
+ for (it = subAccounts.begin(); it != subAccounts.end(); ++it)
+ {
+ MyMoneyAccount categoryAccount;
+
+ categoryAccount.setName(*it);
+ categoryAccount.setAccountType(base.accountType());
+
+ if (it == subAccounts.begin())
+ categoryText += *it;
+ else
+ categoryText += (AccountSeperator + *it);
+
+ // Only create the account if it doesn't exist
+ try
+ {
+ QString categoryId = categoryToAccount(categoryText);
+ if (categoryId.isEmpty())
+ addAccount(categoryAccount, parent);
+ else
+ {
+ categoryAccount = account(categoryId);
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ qDebug("Unable to add account %s, %s, %s: %s",
+ categoryAccount.name().latin1(),
+ parent.name().latin1(),
+ categoryText.latin1(),
+ e->what().latin1());
+ delete e;
+ }
+
+ parent = categoryAccount;
+ }
+
+ return categoryToAccount(name);
+}
+
+const QValueList<MyMoneySchedule> MyMoneyFile::scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts) const
+{
+ checkStorage();
+
+ return m_storage->scheduleListEx(scheduleTypes, scheduleOcurrences, schedulePaymentTypes, startDate, accounts);
+}
+
+void MyMoneyFile::addSecurity(MyMoneySecurity& security)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addSecurity(security);
+
+ d->m_cache.preloadSecurity(security);
+}
+
+void MyMoneyFile::modifySecurity(const MyMoneySecurity& security)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->modifySecurity(security);
+
+ addNotification(security.id());
+}
+
+void MyMoneyFile::removeSecurity(const MyMoneySecurity& security)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removeSecurity(security);
+
+ addNotification(security.id(), false);
+}
+
+const MyMoneySecurity& MyMoneyFile::security(const QString& id) const
+{
+ if(id.isEmpty())
+ return baseCurrency();
+
+ return d->m_cache.security(id);
+}
+
+const QValueList<MyMoneySecurity> MyMoneyFile::securityList(void) const
+{
+ checkStorage();
+
+ return m_storage->securityList();
+}
+
+void MyMoneyFile::addCurrency(const MyMoneySecurity& currency)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addCurrency(currency);
+
+ // we can't really use addNotification here, because there is
+ // a difference in currency and security handling. So we just
+ // preload the object right here.
+ d->m_cache.preloadSecurity(currency);
+}
+
+void MyMoneyFile::modifyCurrency(const MyMoneySecurity& currency)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ // force reload of base currency object
+ if(currency.id() == d->m_baseCurrency.id())
+ d->m_baseCurrency.clearId();
+
+ m_storage->modifyCurrency(currency);
+
+ addNotification(currency.id());
+}
+
+void MyMoneyFile::removeCurrency(const MyMoneySecurity& currency)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ if(currency.id() == d->m_baseCurrency.id()) {
+ throw new MYMONEYEXCEPTION("Cannot delete base currency.");
+ }
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removeCurrency(currency);
+
+ addNotification(currency.id(), false);
+}
+
+const MyMoneySecurity& MyMoneyFile::currency(const QString& id) const
+{
+ if(id.isEmpty())
+ return baseCurrency();
+
+ const MyMoneySecurity& curr = d->m_cache.security(id);
+ if(curr.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Currency not found.");
+ return curr;
+}
+
+const QValueList<MyMoneySecurity> MyMoneyFile::currencyList(void) const
+{
+ checkStorage();
+
+ return m_storage->currencyList();
+}
+
+const QString& MyMoneyFile::foreignCurrency(const QString& first, const QString& second) const
+{
+ if(baseCurrency().id() == second)
+ return first;
+ return second;
+}
+
+const MyMoneySecurity& MyMoneyFile::baseCurrency(void) const
+{
+ if(d->m_baseCurrency.id().isEmpty()) {
+ QString id = QString(value("kmm-baseCurrency"));
+ if(!id.isEmpty())
+ d->m_baseCurrency = currency(id);
+ }
+
+ return d->m_baseCurrency;
+}
+
+void MyMoneyFile::setBaseCurrency(const MyMoneySecurity& curr)
+{
+ // make sure the currency exists
+ MyMoneySecurity c = currency(curr.id());
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ if(c.id() != d->m_baseCurrency.id()) {
+ setValue("kmm-baseCurrency", curr.id());
+ // force reload of base currency cache
+ d->m_baseCurrency = MyMoneySecurity();
+ }
+}
+
+void MyMoneyFile::addPrice(const MyMoneyPrice& price)
+{
+ if(price.rate(QString()).isZero())
+ return;
+
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addPrice(price);
+}
+
+void MyMoneyFile::removePrice(const MyMoneyPrice& price)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removePrice(price);
+}
+
+const MyMoneyPrice MyMoneyFile::price(const QString& fromId, const QString& toId, const QDate& date, const bool exactDate) const
+{
+ checkStorage();
+
+ QString to(toId);
+ if(to.isEmpty())
+ to = value("kmm-baseCurrency");
+ // if some id is missing, we can return an empty price object
+ if(fromId.isEmpty() || to.isEmpty())
+ return MyMoneyPrice();
+
+ // we don't search our tables if someone asks stupid stuff
+ if(fromId == toId) {
+ return MyMoneyPrice(fromId, toId, date, MyMoneyMoney(1,1), "KMyMoney");
+ }
+
+ // search 'from-to' rate
+ MyMoneyPrice rc = m_storage->price(fromId, to, date, exactDate);
+ if(!rc.isValid()) {
+ // not found, search 'to-fron' rate and use reciprocal value
+ rc = m_storage->price(to, fromId, date, exactDate);
+ }
+ return rc;
+}
+
+const MyMoneyPriceList MyMoneyFile::priceList(void) const
+{
+ checkStorage();
+
+ return m_storage->priceList();
+}
+
+bool MyMoneyFile::hasAccount(const QString& id, const QString& name) const
+{
+ MyMoneyAccount acc = d->m_cache.account(id);
+ QStringList list = acc.accountList();
+ QStringList::ConstIterator it;
+ bool rc = false;
+ for(it = list.begin(); rc == false && it != list.end(); ++it) {
+ MyMoneyAccount a = d->m_cache.account(*it);
+ if(a.name() == name)
+ rc = true;
+ }
+ return rc;
+}
+
+const QValueList<MyMoneyReport> MyMoneyFile::reportList( void ) const
+{
+ checkStorage();
+
+ return m_storage->reportList();
+}
+
+void MyMoneyFile::addReport( MyMoneyReport& report )
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addReport( report );
+}
+
+void MyMoneyFile::modifyReport( const MyMoneyReport& report )
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->modifyReport( report );
+
+ addNotification(report.id());
+}
+
+unsigned MyMoneyFile::countReports(void) const
+{
+ checkStorage();
+
+ return m_storage->countReports();
+}
+
+const MyMoneyReport MyMoneyFile::report( const QString& id ) const
+{
+ checkStorage();
+
+ return m_storage->report(id);
+}
+
+void MyMoneyFile::removeReport(const MyMoneyReport& report)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removeReport(report);
+
+ addNotification(report.id(), false);
+}
+
+
+const QValueList<MyMoneyBudget> MyMoneyFile::budgetList( void ) const
+{
+ checkStorage();
+
+ return m_storage->budgetList();
+}
+
+void MyMoneyFile::addBudget( MyMoneyBudget& budget )
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->addBudget( budget );
+}
+
+const MyMoneyBudget MyMoneyFile::budgetByName(const QString& name) const
+{
+ checkStorage();
+
+ return m_storage->budgetByName(name);
+}
+
+void MyMoneyFile::modifyBudget( const MyMoneyBudget& budget )
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+
+ // clear all changed objects from cache
+ MyMoneyNotifier notifier(this);
+
+ m_storage->modifyBudget( budget );
+
+ addNotification(budget.id());
+}
+
+unsigned MyMoneyFile::countBudgets(void) const
+{
+ checkStorage();
+
+ return m_storage->countBudgets();
+}
+
+const MyMoneyBudget MyMoneyFile::budget( const QString& id ) const
+{
+ checkStorage();
+
+ return m_storage->budget(id);
+}
+
+void MyMoneyFile::removeBudget(const MyMoneyBudget& budget)
+{
+ checkTransaction(__PRETTY_FUNCTION__);
+ MyMoneyNotifier notifier(this);
+
+ m_storage->removeBudget(budget);
+
+ addNotification(budget.id(), false);
+}
+
+
+
+bool MyMoneyFile::isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipChecks) const
+{
+ checkStorage();
+ return m_storage->isReferenced(obj, skipChecks);
+}
+
+bool MyMoneyFile::checkNoUsed(const QString& accId, const QString& no) const
+{
+ // by definition, an empty string or a non-numeric string is not used
+ QRegExp exp(QString("(.*\\D)?(\\d+)(\\D.*)?"));
+ if(no.isEmpty() || exp.search(no) == -1)
+ return false;
+
+ MyMoneyTransactionFilter filter;
+ filter.addAccount(accId);
+ QValueList<MyMoneyTransaction> transactions = transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();
+ while ( it_t != transactions.end() ) {
+ try {
+ MyMoneySplit split;
+ // Test whether the transaction also includes a split into
+ // this account
+ split = (*it_t).splitByAccount(accId, true /*match*/);
+ if(!split.number().isEmpty() && split.number() == no)
+ return true;
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ ++it_t;
+ }
+ return false;
+}
+
+QString MyMoneyFile::highestCheckNo(const QString& accId) const
+{
+ unsigned64 lno = 0, cno;
+ QString no;
+ MyMoneyTransactionFilter filter;
+ filter.addAccount(accId);
+ QValueList<MyMoneyTransaction> transactions = transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();
+ while ( it_t != transactions.end() ) {
+ try {
+ // Test whether the transaction also includes a split into
+ // this account
+ MyMoneySplit split = (*it_t).splitByAccount(accId, true /*match*/);
+ if(!split.number().isEmpty()) {
+ // non-numerical values stored in number will return 0 in the next line
+ cno = split.number().toULongLong();
+ if(cno > lno) {
+ lno = cno;
+ no = split.number();
+ }
+ }
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ ++it_t;
+ }
+ return no;
+}
+
+void MyMoneyFile::clearCache(void)
+{
+ checkStorage();
+ m_storage->clearCache();
+ d->m_cache.clear();
+}
+
+void MyMoneyFile::preloadCache(void)
+{
+ checkStorage();
+
+ d->m_cache.clear();
+ QValueList<MyMoneyAccount> a_list;
+ m_storage->accountList(a_list);
+ d->m_cache.preloadAccount(a_list);
+ d->m_cache.preloadPayee(m_storage->payeeList());
+ d->m_cache.preloadInstitution(m_storage->institutionList());
+ d->m_cache.preloadSecurity(m_storage->securityList() + m_storage->currencyList());
+ d->m_cache.preloadSchedule(m_storage->scheduleList());
+}
+
+bool MyMoneyFile::isTransfer(const MyMoneyTransaction& t) const
+{
+ bool rc = false;
+ if(t.splitCount() == 2) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ MyMoneyAccount acc = account((*it_s).accountId());
+ if(acc.isIncomeExpense())
+ break;
+ }
+ if(it_s == t.splits().end())
+ rc = true;
+ }
+ return rc;
+}
+
+bool MyMoneyFile::referencesClosedAccount(const MyMoneyTransaction& t) const
+{
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ const QValueList<MyMoneySplit>& list = t.splits();
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if(referencesClosedAccount(*it_s))
+ break;
+ }
+ return it_s != list.end();
+}
+
+bool MyMoneyFile::referencesClosedAccount(const MyMoneySplit& s) const
+{
+ if(s.accountId().isEmpty())
+ return false;
+
+ try {
+ return account(s.accountId()).isClosed();
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ return false;
+}
+
+MyMoneyFileTransaction::MyMoneyFileTransaction() :
+ m_isNested(MyMoneyFile::instance()->hasTransaction()),
+ m_needRollback(!m_isNested)
+{
+ if(!m_isNested)
+ MyMoneyFile::instance()->startTransaction();
+}
+
+MyMoneyFileTransaction::~MyMoneyFileTransaction()
+{
+ rollback();
+}
+
+void MyMoneyFileTransaction::restart(void)
+{
+ rollback();
+
+ m_needRollback = !m_isNested;
+ if(!m_isNested)
+ MyMoneyFile::instance()->startTransaction();
+}
+
+void MyMoneyFileTransaction::commit(void)
+{
+ if(!m_isNested)
+ MyMoneyFile::instance()->commitTransaction();
+ m_needRollback = false;
+}
+
+void MyMoneyFileTransaction::rollback(void)
+{
+ if(m_needRollback)
+ MyMoneyFile::instance()->rollbackTransaction();
+ m_needRollback = false;
+}
+
+
+#include "mymoneyfile.moc"
diff --git a/kmymoney2/mymoney/mymoneyfile.h b/kmymoney2/mymoney/mymoneyfile.h
new file mode 100644
index 0000000..39552c9
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfile.h
@@ -0,0 +1,1470 @@
+/***************************************************************************
+ mymoneyfile.h
+ -------------------
+ copyright : (C) 2002, 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYFILE_H
+#define MYMONEYFILE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/imymoneystorage.h>
+#include <kmymoney/mymoneyexception.h>
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/mymoneybudget.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/export.h>
+
+/**
+ * @author Thomas Baumgart, Michael Edwardes, Kevin Tambascio
+ */
+
+class IMyMoneyStorage;
+class MyMoneyTransactionFilter;
+
+/**
+ * This class represents the interface to the MyMoney engine.
+ * For historical reasons it is still called MyMoneyFile.
+ * It is implemented using the singleton pattern and thus only
+ * exists once for each running instance of an application.
+ *
+ * The instance of the MyMoneyFile object is accessed as follows:
+ *
+ * @code
+ * MyMoneyFile *file = MyMoneyFile::instance();
+ * file->anyMemberFunction();
+ * @endcode
+ *
+ * The first line of the above code creates a unique MyMoneyFile
+ * object if it is called for the first time ever. All subsequent
+ * calls to this functions return a pointer to the object created
+ * during the first call.
+ *
+ * As the MyMoneyFile object represents the business logic, a storage
+ * manager must be attached to it. This mechanism allows to use different
+ * access methods to store the objects. The interface to access such an
+ * storage manager is defined in the class IMyMoneyStorage. The methods
+ * attachStorage() and detachStorage() are used to attach/detach a
+ * storage manager object. The following code can be used to create a
+ * functional MyMoneyFile instance:
+ *
+ * @code
+ * IMyMoneyStorage *storage = ....
+ * MyMoneyFile *file = MyMoneyFile::instance();
+ * file->attachStorage(storage);
+ * @endcode
+ *
+ * The methods addAccount(), modifyAccount() and removeAccount() implement the
+ * general account maintenance functions. The method reparentAccount() is
+ * available to move an account from one superordinate account to another.
+ * account() and accountList() are used to retrieve a single instance or a
+ * QValueList of MyMoneyAccount objects.
+ *
+ * The methods addInstitution(), modifyInstitution() and removeInstitution()
+ * implement the general institution maintenance functions. institution() and
+ * institutionList() are used to retrieve a single instance or a
+ * QValueList of MyMoneyInstitution objects.
+ *
+ * The methods addPayee(), modifyPayee() and removePayee()
+ * implement the general institution maintenance functions.
+ * payee() and payeeList() are used to retrieve a single instance or a
+ * QValueList of MyMoneyPayee objects.
+ *
+ * The methods addTransaction(), modifyTransaction() and removeTransaction()
+ * implement the general transaction maintenance functions.
+ * transaction() and transactionList() are used to retrieve
+ * a single instance or a QValueList of MyMoneyTransaction objects.
+ *
+ * The methods addSecurity(), modifySecurity() and removeSecurity()
+ * implement the general access to equities held in the engine.
+ *
+ * The methods addCurrency(), modifyCurrency() and removeCurrency()
+ * implement the general access to multiple currencies held in the engine.
+ * The methods baseCurrency() and setBaseCurrency() allow to retrieve/set
+ * the currency selected by the user as base currency. If a currency
+ * reference is emtpy, it will usually be interpreted as baseCurrency().
+ *
+ * The methods liability(), asset(), expense(), income() and equity() are
+ * used to retrieve the five standard accounts. isStandardAccount()
+ * checks if a given accountId references one of the or not.
+ * setAccountName() is used to specify a name for the standard accounts
+ * from the GUI.
+ *
+ * The MyMoneyFile object emits the dataChanged() signal when data
+ * has been changed.
+ *
+ * For abritrary values that have to be stored with the storage object
+ * but are of importance to the application only, the object is derived
+ * for MyMoneyKeyValueContainer which provides a container to store
+ * these values indexed by an alphanumeric key.
+ *
+ * @exception MyMoneyException is thrown whenever an error occurs
+ * while the engine code is running. The MyMoneyException:: object
+ * describes the problem.
+ */
+class KMYMONEY_EXPORT MyMoneyFile : public QObject
+{
+ Q_OBJECT
+public:
+
+ class MyMoneyNotifier
+ {
+ public:
+ MyMoneyNotifier(MyMoneyFile* file) { m_file = file; m_file->clearNotification(); };
+ ~MyMoneyNotifier() { m_file->notify(); };
+ private:
+ MyMoneyFile* m_file;
+ };
+
+ friend class MyMoneyNotifier;
+
+ /**
+ * This is the function to access the MyMoneyFile object.
+ * It returns a pointer to the single instance of the object.
+ */
+ static inline MyMoneyFile* instance() { return &file; }
+
+ /**
+ * This is the destructor for any MyMoneyFile object
+ */
+ ~MyMoneyFile();
+
+ /**
+ * @deprecated This is a convenience constructor. Do not use it anymore.
+ * It will be deprecated in a future version of the engine.
+ *
+ * @param storage pointer to object that implements the IMyMoneyStorage
+ * interface.
+ */
+ MyMoneyFile(IMyMoneyStorage *storage);
+
+ // general get functions
+ const MyMoneyPayee user(void) const;
+
+ // general set functions
+ void setUser(const MyMoneyPayee& user);
+
+ /**
+ * This method is used to attach a storage object to the MyMoneyFile object
+ * Without an attached storage object, the MyMoneyFile object is
+ * of no use.
+ *
+ * After successful completion, the dataChanged() signal is emitted.
+ *
+ * In case of an error condition, an exception is thrown.
+ * The following error conditions are checked:
+ *
+ * - @a storage is not equal to 0
+ * - there is no other @a storage object attached (use detachStorage()
+ * to revert the attachStorage() operation.
+ *
+ * @param storage pointer to object that implements the IMyMoneyStorage
+ * interface.
+ *
+ * @sa detachStorage()
+ */
+ void attachStorage(IMyMoneyStorage* const storage);
+
+ /**
+ * This method is used to detach a previously attached storage
+ * object from the MyMoneyFile object. If no storage object
+ * is attached to the engine, this is a NOP.
+ *
+ * @param storage pointer to object that implements the IMyMoneyStorage
+ * interface.
+ *
+ * @sa attachStorage()
+ */
+ void detachStorage(IMyMoneyStorage* const storage = 0);
+
+ /**
+ * This method returns whether a storage is currently attached to
+ * the engine or not.
+ *
+ * @return true if storage object is attached, false otherwise
+ */
+ bool storageAttached(void) const { return m_storage != 0; };
+
+ /**
+ * This method returns a pointer to the storage object
+ *
+ * @return const pointer to the current attached storage object.
+ * If no object is attached, returns 0.
+ */
+ IMyMoneyStorage* storage(void) const { return m_storage; };
+
+ /**
+ * This method must be called before any single change or a series of changes
+ * in the underlying storage area is performed.
+ * Once all changes are complete (i.e. the transaction is completed),
+ * commitTransaction() must be called to finalize all changes. If an error occurs
+ * during the processing of the changes call rollbackTransaction() to undo the
+ * changes done so far.
+ */
+ void startTransaction(void);
+
+ /**
+ * This method returns whether a transaction has been started (@a true)
+ * or not (@a false).
+ */
+ bool hasTransaction(void) const;
+
+ /**
+ * @sa startTransaction()
+ */
+ void commitTransaction(void);
+
+ /**
+ * @sa startTransaction()
+ */
+ void rollbackTransaction(void);
+
+ /**
+ * This method is used to return the standard liability account
+ * @return MyMoneyAccount liability account(group)
+ */
+ const MyMoneyAccount& liability(void) const;
+
+ /**
+ * This method is used to return the standard asset account
+ * @return MyMoneyAccount asset account(group)
+ */
+ const MyMoneyAccount& asset(void) const;
+
+ /**
+ * This method is used to return the standard expense account
+ * @return MyMoneyAccount expense account(group)
+ */
+ const MyMoneyAccount& expense(void) const;
+
+ /**
+ * This method is used to return the standard income account
+ * @return MyMoneyAccount income account(group)
+ */
+ const MyMoneyAccount& income(void) const;
+
+ /**
+ * This method is used to return the standard equity account
+ * @return MyMoneyAccount equity account(group)
+ */
+ const MyMoneyAccount& equity(void) const;
+
+ /**
+ * This method returns the account information for the opening
+ * balances account for the given @p security. If the respective
+ * account does not exist, it will be created. The name is constructed
+ * using MyMoneyFile::OpeningBalancesPrefix and appending " (xxx)" in
+ * case the @p security is not the baseCurrency(). The account created
+ * will be a sub-account of the standard equity account provided by equity().
+ *
+ * @param security Security for which the account is searched
+ *
+ * @return The opening balance account
+ *
+ * @note No notifications will be sent!
+ */
+ const MyMoneyAccount openingBalanceAccount(const MyMoneySecurity& security);
+
+ /**
+ * This method is essentially the same as the above, except it works on
+ * const objects. If there is no opening balance account, this method
+ * WILL NOT create one. Instead it will thrown an exception.
+ *
+ * @param security Security for which the account is searched
+ *
+ * @return The opening balance account
+ *
+ * @note No notifications will be sent!
+ */
+ const MyMoneyAccount openingBalanceAccount(const MyMoneySecurity& security) const;
+
+ /**
+ * Create an opening balance transaction for the account @p acc
+ * with a value of @p balance. If the corresponding opening balance account
+ * for the account's currency does not exist it will be created. If it exists
+ * and it's opening date is later than the opening date of @p acc,
+ * the opening date of the opening balances account will be adjusted to the
+ * one of @p acc.
+ *
+ * @param acc reference to account for which the opening balance transaction
+ * should be created
+ * @param balance reference to the value of the opening balance transaction
+ *
+ * @returns The created MyMoneyTransaction object. In case no transaction has been
+ * created, the id of the object is empty.
+ */
+ MyMoneyTransaction createOpeningBalanceTransaction(const MyMoneyAccount& acc, const MyMoneyMoney& balance);
+
+ /**
+ * Retrieve the opening balance transaction for the account @p acc.
+ * If there is no opening balance transaction, QString() will be returned.
+ *
+ * @param acc reference to account for which the opening balance transaction
+ * should be retrieved
+ * @return QString id for the transaction, or QString() if no transaction exists
+ */
+ QString openingBalanceTransaction(const MyMoneyAccount& acc) const;
+
+ /**
+ * This method returns an indicator if the MyMoneyFile object has been
+ * changed after it has last been saved to permanent storage.
+ *
+ * @return true if changed, false if not
+ */
+ bool dirty(void) const;
+
+ /**
+ * This method is used to force the attached storage object to
+ * be dirty. This is used by the application to re-set the dirty
+ * flag after a failed upload to a server when the save operation
+ * to a local temp file was OK.
+ */
+ void setDirty(void) const;
+
+ /**
+ * Adds an institution to the file-global institution pool. A
+ * respective institution-ID will be generated for this object.
+ * The ID is stored as QString in the object passed as argument.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete institution information in a
+ * MyMoneyInstitution object
+ */
+ void addInstitution(MyMoneyInstitution& institution);
+
+ /**
+ * Modifies an already existing institution in the file global
+ * institution pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete new institution information
+ */
+ void modifyInstitution(const MyMoneyInstitution& institution);
+
+ /**
+ * Deletes an existing institution from the file global institution pool
+ * Also modifies the accounts that reference this institution as
+ * their institution.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution institution to be deleted.
+ */
+ void removeInstitution(const MyMoneyInstitution& institution);
+
+ /**
+ * Adds an account to the file-global account pool. A respective
+ * account-ID will be generated within this record. The modified
+ * members of @a account will be updated.
+ *
+ * A few parameters of the account to be added are checked against
+ * the following conditions. If they do not match, an exception is
+ * thrown.
+ *
+ * An account must match the following conditions:
+ *
+ * a) the account must have a name with length > 0
+ * b) the account must not have an id assigned
+ * c) the transaction list must be empty
+ * d) the account must not have any sub-ordinate accounts
+ * e) the account must have no parent account
+ * f) the account must not have any reference to a MyMoneyFile object
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account The complete account information in a MyMoneyAccount object
+ * @param parent The complete account information of the parent account
+ */
+ void addAccount(MyMoneyAccount& account, MyMoneyAccount& parent);
+
+ /**
+ * Modifies an already existing account in the file global account pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account reference to the new account information
+ */
+ void modifyAccount(const MyMoneyAccount& account);
+
+ /**
+ * This method re-parents an existing account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount reference to account to be re-parented
+ * @param parent MyMoneyAccount reference to new parent account
+ */
+ void reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent);
+
+ /**
+ * moves splits from one account to another
+ *
+ * @param oldAccount id of the current account
+ * @param newAccount if of the new account
+ *
+ * @return the number of modified splits
+ */
+ unsigned int moveSplits(const QString& oldAccount, const QString& newAccount);
+
+ /**
+ * This method is used to determince, if the account with the
+ * given ID is referenced by any split in m_transactionList.
+ *
+ * @param id id of the account to be checked for
+ * @return true if account is referenced, false otherwise
+ */
+ bool hasActiveSplits(const QString& id) const;
+
+ /**
+ * This method is used to check whether a given
+ * account id references one of the standard accounts or not.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id account id
+ * @return true if account-id is one of the standards, false otherwise
+ */
+ bool isStandardAccount(const QString& id) const;
+
+ /**
+ * Returns @a true, if transaction @p t is a transfer transaction.
+ * A transfer transaction has two splits, both referencing either
+ * an asset, a liability or an equity account.
+ */
+ bool isTransfer(const MyMoneyTransaction& t) const;
+
+ /**
+ * This method is used to set the name for the specified standard account
+ * within the storage area. An exception will be thrown, if an error
+ * occurs
+ *
+ * @param id QString reference to one of the standard accounts.
+ * @param name QString reference to the name to be set
+ *
+ */
+ void setAccountName(const QString& id, const QString& name) const;
+
+ /**
+ * Deletes an existing account from the file global account pool
+ * This method only allows to remove accounts that are not
+ * referenced by any split. Use moveSplits() to move splits
+ * to another account. An exception is thrown in case of a
+ * problem.
+ *
+ * @param account reference to the account to be deleted.
+ */
+ void removeAccount(const MyMoneyAccount& account);
+
+ /**
+ * Deletes existing accounts and their subaccounts recursivly
+ * from the global account pool.
+ * This method expects that all accounts and their subaccounts
+ * are no longer assigned to any transactions or splits.
+ * An exception is thrown in case of a problem deleting an account.
+ *
+ * The optional parameter level is used to keep track of the recursion level.
+ * If the recursion level exceeds 100 (some arbitrary number which seems a good
+ * maximum), an exception is thrown.
+ *
+ * @param account_list Reference to a list of account IDs to be deleted.
+ * @param level Parameter to keep track of recursion level (do not pass a value here).
+ */
+ void removeAccountList(const QStringList& account_list, unsigned int level = 0);
+
+ /**
+ * This member function checks all accounts identified by account_list
+ * and their subaccounts wether they are assigned to transactions/splits or not.
+ * The function calls itself recursively with the list of sub-accounts of
+ * the currently processed account.
+ *
+ * The optional parameter level is used to keep track of the recursion level.
+ * If the recursion level exceeds 100 (some arbitrary number which seems a good
+ * maximum), an exception is thrown.
+ *
+ * @param account_list A QStringList with account IDs that need to be checked.
+ * @param level (optional) Optional parameter to indicate recursion level.
+ * @return Returns 'false' if at least one account has been found that
+ * is still referenced by a transaction.
+ */
+ bool hasOnlyUnusedAccounts(const QStringList& account_list, unsigned int level = 0);
+
+ /**
+ * Adds a transaction to the file-global transaction pool. A respective
+ * transaction-ID will be generated for this object. The ID is stored
+ * as QString in the object passed as argument.
+ * Splits must reference valid accounts and valid payees. The payee
+ * id can be empty.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to the transaction
+ */
+ void addTransaction(MyMoneyTransaction& transaction);
+
+ /**
+ * This method is used to update a specific transaction in the
+ * transaction pool of the MyMoneyFile object.
+ * Splits must reference valid accounts and valid payees. The payee
+ * id can be empty.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to transaction to be changed
+ */
+ void modifyTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an id. In case of an invalid id, an
+ * exception will be thrown.
+ *
+ * @param id id of transaction as QString.
+ * @return reference to the requested transaction
+ */
+ const MyMoneyTransaction transaction(const QString& id) const;
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an index into an account.
+ *
+ * @param account id of the account as QString
+ * @param idx number of transaction in this account
+ * @return reference to MyMoneyTransaction object
+ */
+ const MyMoneyTransaction transaction(const QString& account, const int idx) const;
+
+ /**
+ * This method is used to pull a list of transactions from the file
+ * global transaction pool. It returns all those transactions
+ * that match the filter passed as argument. If the filter is empty,
+ * the whole journal will be returned.
+ * The list returned is sorted according to the transactions posting date.
+ * If more than one transaction exists for the same date, the order among
+ * them is undefined.
+ *
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ *
+ * @return set of transactions in form of a QValueList<MyMoneyTransaction>
+ */
+ const QValueList<MyMoneyTransaction> transactionList(MyMoneyTransactionFilter& filter) const;
+
+ void transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const;
+
+ void transactionList(QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * This method is used to remove a transaction from the transaction
+ * pool (journal).
+ *
+ * @param transaction const reference to transaction to be deleted
+ */
+ void removeTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * This method is used to return the actual balance of an account
+ * without it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date (default = QDate())
+ * @return balance of the account as MyMoneyMoney object
+ */
+ const MyMoneyMoney balance(const QString& id, const QDate& date = QDate()) const;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * including it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date (default = QDate())
+ * @return balance of the account as MyMoneyMoney object
+ */
+ const MyMoneyMoney totalBalance(const QString& id, const QDate& date = QDate()) const;
+
+ /**
+ * This method returns the number of transactions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @param account QString reference to account id. If account is empty
+ + all transactions (the journal) will be counted. If account
+ * is not empty it returns the number of transactions
+ * that have splits in this account.
+ *
+ * @return number of transactions in journal/account
+ */
+ unsigned int transactionCount(const QString& account = QString()) const;
+
+ /**
+ * This method returns a QMap filled with the number of transactions
+ * per account. The account id serves as index into the map. If one
+ * needs to have all transactionCounts() for many accounts, this method
+ * is faster than calling transactionCount(const QString& account) many
+ * times.
+ *
+ * @return QMap with numbers of transactions per account
+ */
+ const QMap<QString, unsigned long> transactionCountMap(void) const;
+
+ /**
+ * This method returns the number of institutions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of institutions known to file
+ */
+ unsigned int institutionCount(void) const;
+
+ /**
+ * This method returns the number of accounts currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of accounts currently known inside a MyMoneyFile object
+ */
+ unsigned int accountCount(void) const;
+
+ /**
+ * Returns the institution of a given ID
+ *
+ * @param id id of the institution to locate
+ * @return MyMoneyInstitution object filled with data. If the institution
+ * could not be found, an exception will be thrown
+ */
+ const MyMoneyInstitution& institution(const QString& id) const;
+
+ /**
+ * This method returns a list of the institutions
+ * inside a MyMoneyFile object
+ *
+ * @param list reference to the list. It will be cleared by this method first
+ */
+ void institutionList(QValueList<MyMoneyInstitution>& list) const;
+
+ /**
+ * This method returns a list of the institutions
+ * inside a MyMoneyFile object. This is a convenience method
+ * to the one above
+ *
+ * @return QValueList containing the institution objects
+ */
+ const QValueList<MyMoneyInstitution> institutionList(void) const;
+
+ /**
+ * Returns the account addressed by its id.
+ *
+ * @param id id of the account to locate.
+ * @return MyMoneyAccount object carrying the @p id. An exception is thrown
+ * if the id is unknown
+ */
+ const MyMoneyAccount& account(const QString& id) const;
+
+ /**
+ * Returns the account addressed by its name.
+ *
+ * @param name name of the account to locate.
+ * @return First MyMoneyAccount object found carrying the @p name.
+ * An empty MyMoneyAccount object will be returned if the name is not found.
+ */
+ const MyMoneyAccount& accountByName(const QString& name) const;
+
+ /**
+ * Returns the sub-account addressed by its name.
+ *
+ * @param acc account to search in
+ * @param name name of the account to locate.
+ * @return First MyMoneyAccount object found carrying the @p name.
+ * An empty MyMoneyAccount object will be returned if the name is not found.
+ */
+ const MyMoneyAccount& subAccountByName(const MyMoneyAccount& acc, const QString& name) const;
+
+ /**
+ * This method returns a list of accounts inside a MyMoneyFile object.
+ * An optional parameter is a list of id's. If this list is emtpy (the default)
+ * the returned list contains all accounts, otherwise only those referenced
+ * in the id-list.
+ *
+ * @param list reference to QValueList receiving the account objects
+ * @param idlist QStringList of account ids of those accounts that
+ * should be returned. If this list is empty, all accounts
+ * currently known will be returned.
+ *
+ * @param recursive if @p true, then recurse in all found accounts. The default is @p false
+ */
+ void accountList(QValueList<MyMoneyAccount>& list, const QStringList& idlist = QStringList(), const bool recursive = false) const;
+
+ /**
+ * This method is used to convert an account id to a string representation
+ * of the names which can be used as a category description. If the account
+ * is part of a hierarchy, the category name will be the concatenation of
+ * the single account names seperated by MyMoneyAccount::AccountSeperator.
+ *
+ * @param accountId QString reference of the account's id
+ * @param includeStandardAccounts if true, the standard top account will be part
+ * of the name, otherwise it will not be included (default is @c false)
+ *
+ * @return QString of the constructed name.
+ */
+ QString accountToCategory(const QString& accountId, bool includeStandardAccounts = false) const;
+
+ /**
+ * This method is used to convert a string representing a category to
+ * an account id. A category can be the concatenation of multiple accounts
+ * representing a hierarchy of accounts. They have to be seperated by
+ * MyMoneyAccount::AccountSeperator.
+ *
+ * @param category const reference to QString containing the category
+ * @param type account type if a specific type is required (defaults to UnknownAccountType)
+ *
+ * @return QString of the corresponding account. If account was not found
+ * the return value will be an empty string.
+ */
+ QString categoryToAccount(const QString& category, MyMoneyAccount::accountTypeE type = MyMoneyAccount::UnknownAccountType) const;
+
+ /**
+ * This method is used to convert a string representing an asset or
+ * liability account to an account id. An account name can be the
+ * concatenation of multiple accounts representing a hierarchy of
+ * accounts. They have to be seperated by MyMoneyAccount::AccountSeperator.
+ *
+ * @param name const reference to QString containing the account name
+ *
+ * @return QString of the corresponding account. If account was not found
+ * the return value will be an empty string.
+ */
+ QString nameToAccount(const QString& name) const;
+
+ /**
+ * This method is used to extract the parent part of an account hierarchy
+ * name who's parts are seperated by MyMoneyAccount::AccountSeperator.
+ *
+ * @param name full account name
+ * @return parent name (full account name excluding the last part)
+ */
+ QString parentName(const QString& name) const;
+
+ /**
+ * This method is used to create a new payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ void addPayee(MyMoneyPayee& payee);
+
+ /**
+ * This method is used to retrieve information about a payee
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id QString reference to id of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ const MyMoneyPayee& payee(const QString& id) const;
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a payee/receiver.
+ * An exception will be thrown upon error conditions.
+ *
+ * @param payee QString reference to name of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ const MyMoneyPayee& payeeByName(const QString& payee) const;
+
+ /**
+ * This method is used to modify an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ void modifyPayee(const MyMoneyPayee& payee);
+
+ /**
+ * This method is used to remove an existing payee.
+ * An error condition occurs, if the payee is still referenced
+ * by a split.
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ void removePayee(const MyMoneyPayee& payee);
+
+ /**
+ * This method returns a list of the payees
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyPayee> containing the payee information
+ */
+ const QValueList<MyMoneyPayee> payeeList(void) const;
+
+ /**
+ * This method is used to extract a value from the storage's
+ * KeyValueContainer. For details see MyMoneyKeyValueContainer::value().
+ *
+ * @param key const reference to QString containing the key
+ * @return QString containing the value
+ */
+ QString value(const QString& key) const;
+
+ /**
+ * This method is used to set a value in the storage's
+ * KeyValueContainer. For details see MyMoneyKeyValueContainer::setValue().
+ *
+ * @param key const reference to QString containing the key
+ * @param val const reference to QString containing the value
+ *
+ * @note Keys starting with the leadin @p kmm- are reserved for internal use
+ * by the MyMoneyFile object.
+ */
+ void setValue(const QString& key, const QString& val);
+
+ /**
+ * This method is used to delete a key-value-pair from the
+ * storage's KeyValueContainer identified by the parameter
+ * @p key. For details see MyMoneyKeyValueContainer::deletePair().
+ *
+ * @param key const reference to QString containing the key
+ */
+ void deletePair(const QString& key);
+
+ /**
+ * This method is used to add a scheduled transaction to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched reference to the MyMoneySchedule object
+ */
+ void addSchedule(MyMoneySchedule& sched);
+
+ /**
+ * This method is used to modify an existing MyMoneySchedule
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ void modifySchedule(const MyMoneySchedule& sched);
+
+ /**
+ * This method is used to remove an existing MyMoneySchedule object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ void removeSchedule(const MyMoneySchedule& sched);
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ const MyMoneySchedule schedule(const QString& id) const;
+
+ /**
+ * This method is used to extract a list of scheduled transactions
+ * according to the filter criteria passed as arguments.
+ *
+ * @param accountId only search for scheduled transactions that reference
+ * account @p accountId. If accountId is the empty string,
+ * this filter is off. Default is @p QString().
+ * @param type only schedules of type @p type are searched for.
+ * See MyMoneySchedule::typeE for details.
+ * Default is MyMoneySchedule::TYPE_ANY
+ * @param occurence only schedules of occurence type @p occurence are searched for.
+ * See MyMoneySchedule::occurenceE for details.
+ * Default is MyMoneySchedule::OCCUR_ANY
+ * @param paymentType only schedules of payment method @p paymentType
+ * are searched for.
+ * See MyMoneySchedule::paymentTypeE for details.
+ * Default is MyMoneySchedule::STYPE_ANY
+ * @param startDate only schedules with payment dates after @p startDate
+ * are searched for. Default is all dates (QDate()).
+ * @param endDate only schedules with payment dates ending prior to @p endDate
+ * are searched for. Default is all dates (QDate()).
+ * @param overdue if true, only those schedules that are overdue are
+ * searched for. Default is false (all schedules will be returned).
+ *
+ * @return const QValueList<MyMoneySchedule> list of schedule objects.
+ */
+ const QValueList<MyMoneySchedule> scheduleList(const QString& accountId = QString(),
+ const MyMoneySchedule::typeE type = MyMoneySchedule::TYPE_ANY,
+ const MyMoneySchedule::occurenceE occurence = MyMoneySchedule::OCCUR_ANY,
+ const MyMoneySchedule::paymentTypeE paymentType = MyMoneySchedule::STYPE_ANY,
+ const QDate& startDate = QDate(),
+ const QDate& endDate = QDate(),
+ const bool overdue = false) const;
+
+ const QStringList consistencyCheck(void);
+
+ /**
+ * MyMoneyFile::OpeningBalancesPrefix is a special string used
+ * to generate the name for opening balances accounts. See openingBalanceAccount()
+ * for details.
+ */
+ static const QString OpeningBalancesPrefix;
+
+ /**
+ * MyMoneyFile::AccountSeperator is used as the seperator
+ * between account names to form a hierarchy.
+ */
+ static const QString AccountSeperator;
+
+ /**
+ * createCategory creates a category from a text name.
+ *
+ * The whole account hierarchy is created if it doesnt
+ * already exist. e.g if name = Bills:Credit Card and
+ * base = expense(), Bills will first be checked to see if
+ * it exists and created if not. Credit Card will then
+ * be created with Bills as it's parent. The Credit Card account
+ * will have it's id returned.
+ *
+ * @param base The base account (expense or income)
+ * @param name The category to create
+ *
+ * @return The category account id or empty on error.
+ *
+ * @exception An exception will be thrown, if @p base is not equal
+ * expense() or income().
+ **/
+ QString createCategory(const MyMoneyAccount& base, const QString& name);
+
+ const QValueList<MyMoneySchedule> scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts=QStringList()) const;
+
+ /**
+ * This method is used to add a new security object to the engine.
+ * The ID of the object is the trading symbol, so there is no need for an additional
+ * ID since the symbol is guaranteed to be unique.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object
+ */
+ void addSecurity(MyMoneySecurity& security);
+
+ /**
+ * This method is used to modify an existing MyMoneySchedule
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be updated
+ */
+ void modifySecurity(const MyMoneySecurity& security);
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be removed
+ */
+ void removeSecurity(const MyMoneySecurity& security);
+
+ /**
+ * This method is used to retrieve a single MyMoneySecurity object.
+ * The id of the object must be supplied in the parameter @p id.
+ * If no security with the given id is found, then a corresponding
+ * currency is searched. If @p id is empty, the baseCurrency() is returned.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySecurity object
+ * @return MyMoneySecurity object
+ */
+ const MyMoneySecurity& security(const QString& id) const;
+
+ /**
+ * This method is used to retrieve a list of all MyMoneySecurity objects.
+ */
+ const QValueList<MyMoneySecurity> securityList(void) const;
+
+ /**
+ * This method is used to add a new currency object to the engine.
+ * The ID of the object is the trading symbol, so there is no need for an additional
+ * ID since the symbol is guaranteed to be unique.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ void addCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to modify an existing MyMoneySecurity
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ void modifyCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ void removeCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ * If @p id is empty, this method returns baseCurrency().
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ const MyMoneySecurity& currency(const QString& id) const;
+
+ /**
+ * This method is used to retrieve the list of all currencies
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneySecurity objects.
+ */
+ const QValueList<MyMoneySecurity> currencyList(void) const;
+
+ /**
+ * This method retrieves a MyMoneySecurity object representing
+ * the selected base currency. If the base currency is not
+ * selected (e.g. due to a previous call to setBaseCurrency())
+ * a standard MyMoneySecurity object will be returned. See
+ * MyMoneySecurity() for details.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return MyMoneySecurity describing base currency
+ */
+ const MyMoneySecurity& baseCurrency(void) const;
+
+ /**
+ * This method returns the foreign currency of the given two
+ * currency ids. If second is the base currency id then @a first
+ * is returned otherwise @a second is returned.
+ */
+ const QString& foreignCurrency(const QString& first, const QString& second) const;
+
+ /**
+ * This method allows to select the base currency. It does
+ * not perform any changes to the data in the engine. It merely
+ * stores a reference to the base currency. The currency
+ * passed as argument must exist in the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency
+ */
+ void setBaseCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method adds/replaces a price to/from the price list
+ */
+ void addPrice(const MyMoneyPrice& price);
+
+ /**
+ * This method removes a price from the price list
+ */
+ void removePrice(const MyMoneyPrice& price);
+
+ /**
+ * This method is used to retrieve a price for a specific security
+ * on a specific date. If there is no price for this date, the last
+ * known price for this currency is used. If no price information
+ * is available, 1.0 will be returned as price.
+ *
+ * @param fromId the id of the currency in question
+ * @param toId the id of the currency to convert to (if emtpy, baseCurrency)
+ * @param date the date for which the price should be returned (default = today)
+ * @param exactDate if true, entry for date must exist, if false any price information
+ * with a date less or equal to @p date will be returned
+ *
+ * @return price found as MyMoneyPrice object
+ * @note This throws an exception when the base currency is not set and toId is empty
+ */
+ const MyMoneyPrice price(const QString& fromId, const QString& toId = QString(), const QDate& date = QDate::currentDate(), const bool exactDate = false) const;
+
+ /**
+ * This method returns a list of all prices.
+ *
+ * @return MyMoneyPriceList of all MyMoneyPrice objects.
+ */
+ const MyMoneyPriceList priceList(void) const;
+
+ /**
+ * This method allows to interrogate the engine, if a known account
+ * with id @p id has a subaccount with the name @p name.
+ *
+ * @param id id of the account to look at
+ * @param name account name that needs to be searched force
+ * @retval true account with name @p name found as subaccounts
+ * @retval false no subaccount present with that name
+ */
+ bool hasAccount(const QString& id, const QString& name) const;
+
+ /**
+ * This method is used to retrieve the list of all reports
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyReport objects.
+ */
+ const QValueList<MyMoneyReport> reportList( void ) const;
+
+ /**
+ * Adds a report to the file-global institution pool. A
+ * respective report-ID will be generated for this object.
+ * The ID is stored as QString in the object passed as argument.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param report The complete report information in a
+ * MyMoneyReport object
+ */
+ void addReport( MyMoneyReport& report );
+
+ /**
+ * Modifies an already existing report in the file global
+ * report pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param report The complete new report information
+ */
+ void modifyReport( const MyMoneyReport& report );
+
+ /**
+ * This method returns the number of reports currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of reports known to file
+ */
+ unsigned countReports( void ) const;
+
+ /**
+ * This method is used to retrieve a single MyMoneyReport object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyReport object
+ * @return MyMoneyReport object
+ */
+ const MyMoneyReport report( const QString& id ) const;
+
+ /**
+ * This method is used to remove an existing MyMoneyReport object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ void removeReport(const MyMoneyReport& report);
+
+ /**
+ * This method is used to retrieve the list of all budgets
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyBudget objects.
+ */
+ const QValueList<MyMoneyBudget> budgetList( void ) const;
+
+ /**
+ * Adds a budget to the file-global institution pool. A
+ * respective budget-ID will be generated for this object.
+ * The ID is stored as QString in the object passed as argument.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param budget The complete budget information in a
+ * MyMoneyBudget object
+ */
+ void addBudget( MyMoneyBudget& budget );
+
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a budget.
+ * An exception will be thrown upon error conditions.
+ *
+ * @param budget QString reference to name of budget
+ *
+ * @return MyMoneyBudget refernce to object of budget
+ */
+ const MyMoneyBudget budgetByName(const QString& budget) const;
+
+
+ /**
+ * Modifies an already existing budget in the file global
+ * budget pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param budget The complete new budget information
+ */
+ void modifyBudget( const MyMoneyBudget& budget );
+
+ /**
+ * This method returns the number of budgets currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of budgets known to file
+ */
+ unsigned countBudgets( void ) const;
+
+ /**
+ * This method is used to retrieve a single MyMoneyBudget object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyBudget object
+ * @return MyMoneyBudget object
+ */
+ const MyMoneyBudget budget( const QString& id ) const;
+
+ /**
+ * This method is used to remove an existing MyMoneyBudget object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ void removeBudget(const MyMoneyBudget& budget);
+
+
+ /**
+ * This method checks, if the given @p object is referenced
+ * by another engine object.
+ *
+ * @param obj const reference to object to be checked
+ * @param skipCheck MyMoneyFileBitArray with ReferenceCheckBits set for which
+ * the check should be skipped
+ *
+ * @retval false @p object is not referenced
+ * @retval true @p institution is referenced
+ */
+ bool isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipCheck = MyMoneyFileBitArray()) const;
+
+ /**
+ * Returns true if any of the accounts referenced by the splits
+ * of transaction @a t is closed.
+ */
+ bool referencesClosedAccount(const MyMoneyTransaction& t) const;
+
+ /**
+ * Returns true if the accounts referenced by the split @a s is closed.
+ */
+ bool referencesClosedAccount(const MyMoneySplit& s) const;
+
+ /**
+ * This method checks if the given check no &p no is used in
+ * a transaction referencing account &p accId. If @p accId is empty,
+ * @p false is returned.
+ *
+ * @param accId id of account to checked
+ * @param no check number to be verified if used or not
+ * @retval false @p no is not in use
+ * @retval true @p no is already assigned
+ */
+ bool checkNoUsed(const QString& accId, const QString& no) const;
+
+ /**
+ * This method returns the highest assigned check no for
+ * account @p accId.
+ *
+ * @param accId id of account to be scanned
+ * @return highest check no. used
+ */
+ QString highestCheckNo(const QString& accId) const;
+
+ /**
+ * Clear all internal caches (used internally for performance measurements)
+ */
+ void clearCache(void);
+
+ void forceDataChanged(void) { emit dataChanged(); }
+
+ void preloadCache(void);
+
+protected:
+ /**
+ * This is the constructor for a new empty file description
+ */
+ MyMoneyFile();
+
+signals:
+ /**
+ * This signal is emitted whenever any data has been changed in the engine
+ * via any of the methods of this object
+ */
+ void dataChanged(void);
+
+private:
+ static MyMoneyFile file;
+
+ MyMoneyFile& operator=(MyMoneyFile&); // not allowed for singleton
+ MyMoneyFile(const MyMoneyFile&); // not allowed for singleton
+
+ QString locateSubAccount(const MyMoneyAccount& base, const QString& category) const;
+
+ void ensureDefaultCurrency(MyMoneyAccount& acc) const;
+
+ void warningMissingRate(const QString& fromId, const QString& toId) const;
+
+ /**
+ * This method creates an opening balances account. The name is constructed
+ * using MyMoneyFile::OpeningBalancesPrefix and appending " (xxx)" in
+ * case the @p security is not the baseCurrency(). The account created
+ * will be a sub-account of the standard equity account provided by equity().
+ *
+ * @param security Security for which the account is searched
+ */
+ const MyMoneyAccount createOpeningBalanceAccount(const MyMoneySecurity& security);
+
+ const MyMoneyAccount openingBalanceAccount_internal(const MyMoneySecurity& security) const;
+
+private:
+ /**
+ * This method is used to add an id to the list of objects
+ * to be removed from the cache. If id is empty, then nothing is added to the list.
+ *
+ * @param id id of object to be notified
+ * @param reload reload the object (@c true) or not (@c false). The default is @c true
+ * @see attach, detach
+ */
+ void addNotification(const QString& id, bool reload = true);
+
+ /**
+ * This method is used to clear the notification list
+ */
+ void clearNotification(void);
+
+ /**
+ * This method is used to clear all
+ * objects mentioned in m_notificationList from the cache.
+ */
+ void notify(void);
+
+ /**
+ * This method checks if a storage object is attached and
+ * throws and exception if not.
+ */
+ inline void checkStorage(void) const {
+ if(m_storage == 0)
+ throw new MYMONEYEXCEPTION("No storage object attached to MyMoneyFile");
+ }
+
+ /**
+ * This method checks that a transaction has been started with
+ * startTransaction() and throws an exception otherwise. Calls
+ * checkStorage() to make sure a storage object is present and attached.
+ */
+ void checkTransaction(const char* txt) const;
+
+private:
+ /**
+ * This member points to the storage strategy
+ */
+ IMyMoneyStorage *m_storage;
+
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ static MyMoneyFile* _instance;
+};
+
+class KMYMONEY_EXPORT MyMoneyFileTransaction
+{
+public:
+ MyMoneyFileTransaction();
+ ~MyMoneyFileTransaction();
+
+ /**
+ * Commit the current transaction.
+ *
+ * @warning Make sure not to use any variable that might have been altered by
+ * the transaction. Please keep in mind, that changing transactions
+ * can also affect account objects. If you still need those variables
+ * just reload them from the engine.
+ */
+ void commit(void);
+ void rollback(void);
+ void restart(void);
+
+private:
+ bool m_isNested;
+ bool m_needRollback;
+};
+
+#endif
+
diff --git a/kmymoney2/mymoney/mymoneyfiletest.cpp b/kmymoney2/mymoney/mymoneyfiletest.cpp
new file mode 100644
index 0000000..e081fa0
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfiletest.cpp
@@ -0,0 +1,1550 @@
+/***************************************************************************
+ mymoneyfiletest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyfiletest.h"
+#include <iostream>
+
+#include <memory>
+#include <unistd.h>
+#include <qfile.h>
+#include <qdatastream.h>
+
+MyMoneyFileTest:: MyMoneyFileTest () {}
+
+
+void MyMoneyFileTest::setUp () {
+ storage = new MyMoneySeqAccessMgr;
+ m = MyMoneyFile::instance();
+ m->attachStorage(storage);
+}
+
+void MyMoneyFileTest::tearDown () {
+ m->detachStorage(storage);
+ delete storage;
+}
+
+void MyMoneyFileTest::testEmptyConstructor() {
+ MyMoneyPayee user = m->user();
+
+ CPPUNIT_ASSERT(user.name().isEmpty());
+ CPPUNIT_ASSERT(user.address().isEmpty());
+ CPPUNIT_ASSERT(user.city().isEmpty());
+ CPPUNIT_ASSERT(user.state().isEmpty());
+ CPPUNIT_ASSERT(user.postcode().isEmpty());
+ CPPUNIT_ASSERT(user.telephone().isEmpty());
+ CPPUNIT_ASSERT(user.email().isEmpty());
+
+ CPPUNIT_ASSERT(m->institutionCount() == 0);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(m->accountCount() == 5);
+}
+
+void MyMoneyFileTest::testAddOneInstitution() {
+ MyMoneyInstitution institution;
+
+ institution.setName("institution1");
+ institution.setTown("town");
+ institution.setStreet("street");
+ institution.setPostcode("postcode");
+ institution.setTelephone("telephone");
+ institution.setManager("manager");
+ institution.setSortcode("sortcode");
+
+ // MyMoneyInstitution institution_file("", institution);
+ MyMoneyInstitution institution_id("I000002", institution);
+ MyMoneyInstitution institution_noname(institution);
+ institution_noname.setName(QString());
+
+ QString id;
+
+ CPPUNIT_ASSERT(m->institutionCount() == 0);
+ storage->m_dirty = false;
+
+ MyMoneyFileTransaction ft;
+ try {
+ m->addInstitution(institution);
+ ft.commit();
+ CPPUNIT_ASSERT(institution.id() == "I000001");
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ ft.restart();
+ try {
+ m->addInstitution(institution_id);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ delete e;
+ }
+
+ ft.restart();
+ try {
+ m->addInstitution(institution_noname);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testAddTwoInstitutions() {
+ testAddOneInstitution();
+ MyMoneyInstitution institution;
+ institution.setName("institution2");
+ institution.setTown("town");
+ institution.setStreet("street");
+ institution.setPostcode("postcode");
+ institution.setTelephone("telephone");
+ institution.setManager("manager");
+ institution.setSortcode("sortcode");
+
+ QString id;
+
+ storage->m_dirty = false;
+ MyMoneyFileTransaction ft;
+ try {
+ m->addInstitution(institution);
+ ft.commit();
+
+ CPPUNIT_ASSERT(institution.id() == "I000002");
+ CPPUNIT_ASSERT(m->institutionCount() == 2);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ storage->m_dirty = false;
+
+ try {
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.id() == "I000001");
+ CPPUNIT_ASSERT(m->institutionCount() == 2);
+ CPPUNIT_ASSERT(m->dirty() == false);
+
+ institution = m->institution("I000002");
+ CPPUNIT_ASSERT(institution.id() == "I000002");
+ CPPUNIT_ASSERT(m->institutionCount() == 2);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ } catch (MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testRemoveInstitution() {
+ testAddTwoInstitutions();
+
+ MyMoneyInstitution i;
+
+ CPPUNIT_ASSERT(m->institutionCount() == 2);
+
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.id() == "I000001");
+ CPPUNIT_ASSERT(i.accountCount() == 0);
+
+ storage->m_dirty = false;
+ MyMoneyFileTransaction ft;
+ try {
+ m->removeInstitution(i);
+ ft.commit();
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch (MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ storage->m_dirty = false;
+
+ try {
+ m->institution("I000001");
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+
+ ft.restart();
+ try {
+ m->removeInstitution(i);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testInstitutionRetrieval () {
+
+ testAddOneInstitution();
+
+ storage->m_dirty = false;
+
+ MyMoneyInstitution institution;
+
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+
+ try {
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.id() == "I000001");
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ } catch (MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ try {
+ institution = m->institution("I000002");
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_ASSERT(m->institutionCount() == 1);
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+}
+
+void MyMoneyFileTest::testInstitutionListRetrieval () {
+ QValueList<MyMoneyInstitution> list;
+
+ storage->m_dirty = false;
+ list = m->institutionList();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(list.count() == 0);
+
+ testAddTwoInstitutions();
+
+ storage->m_dirty = false;
+ list = m->institutionList();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(list.count() == 2);
+
+ QValueList<MyMoneyInstitution>::ConstIterator it;
+ it = list.begin();
+
+ CPPUNIT_ASSERT((*it).name() == "institution1");
+ ++it;
+ CPPUNIT_ASSERT((*it).name() == "institution2");
+ ++it;
+ CPPUNIT_ASSERT(it == list.end());
+}
+
+void MyMoneyFileTest::testInstitutionModify() {
+ testAddTwoInstitutions();
+ MyMoneyInstitution institution;
+
+ institution = m->institution("I000001");
+ institution.setStreet("new street");
+ institution.setTown("new town");
+ institution.setPostcode("new postcode");
+ institution.setTelephone("new telephone");
+ institution.setManager("new manager");
+ institution.setName("new name");
+ institution.setSortcode("new sortcode");
+
+ storage->m_dirty = false;
+
+ MyMoneyFileTransaction ft;
+ try {
+ m->modifyInstitution(institution);
+ ft.commit();
+ CPPUNIT_ASSERT(institution.id() == "I000001");
+ CPPUNIT_ASSERT(m->institutionCount() == 2);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ MyMoneyInstitution newInstitution;
+ newInstitution = m->institution("I000001");
+
+ CPPUNIT_ASSERT(newInstitution.id() == "I000001");
+ CPPUNIT_ASSERT(newInstitution.street() == "new street");
+ CPPUNIT_ASSERT(newInstitution.town() == "new town");
+ CPPUNIT_ASSERT(newInstitution.postcode() == "new postcode");
+ CPPUNIT_ASSERT(newInstitution.telephone() == "new telephone");
+ CPPUNIT_ASSERT(newInstitution.manager() == "new manager");
+ CPPUNIT_ASSERT(newInstitution.name() == "new name");
+ CPPUNIT_ASSERT(newInstitution.sortcode() == "new sortcode");
+
+ storage->m_dirty = false;
+
+ ft.restart();
+ MyMoneyInstitution failInstitution2("I000003", newInstitution);
+ try {
+ m->modifyInstitution(failInstitution2);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ CPPUNIT_ASSERT(failInstitution2.id() == "I000003");
+ CPPUNIT_ASSERT(m->institutionCount() == 2);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ }
+}
+
+void MyMoneyFileTest::testSetFunctions() {
+ MyMoneyPayee user = m->user();
+
+ CPPUNIT_ASSERT(user.name().isEmpty());
+ CPPUNIT_ASSERT(user.address().isEmpty());
+ CPPUNIT_ASSERT(user.city().isEmpty());
+ CPPUNIT_ASSERT(user.state().isEmpty());
+ CPPUNIT_ASSERT(user.postcode().isEmpty());
+ CPPUNIT_ASSERT(user.telephone().isEmpty());
+ CPPUNIT_ASSERT(user.email().isEmpty());
+
+ MyMoneyFileTransaction ft;
+ storage->m_dirty = false;
+ user.setName("Name");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+ user.setAddress("Street");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+ user.setCity("Town");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+ user.setState("County");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+ user.setPostcode("Postcode");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+ user.setTelephone("Telephone");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+ user.setEmail("Email");
+ m->setUser(user);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ storage->m_dirty = false;
+
+ ft.commit();
+ user = m->user();
+ CPPUNIT_ASSERT(user.name() == "Name");
+ CPPUNIT_ASSERT(user.address() == "Street");
+ CPPUNIT_ASSERT(user.city() == "Town");
+ CPPUNIT_ASSERT(user.state() == "County");
+ CPPUNIT_ASSERT(user.postcode() == "Postcode");
+ CPPUNIT_ASSERT(user.telephone() == "Telephone");
+ CPPUNIT_ASSERT(user.email() == "Email");
+}
+
+void MyMoneyFileTest::testAddAccounts() {
+ testAddTwoInstitutions();
+ MyMoneyAccount a, b, c;
+ a.setAccountType(MyMoneyAccount::Checkings);
+ b.setAccountType(MyMoneyAccount::Checkings);
+
+ MyMoneyInstitution institution;
+
+ storage->m_dirty = false;
+
+ CPPUNIT_ASSERT(m->accountCount() == 5);
+
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.id() == "I000001");
+
+ a.setName("Account1");
+ a.setInstitutionId(institution.id());
+
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyAccount parent = m->asset();
+ m->addAccount(a, parent);
+ ft.commit();
+ CPPUNIT_ASSERT(m->accountCount() == 6);
+ CPPUNIT_ASSERT(a.parentAccountId() == "AStd::Asset");
+ CPPUNIT_ASSERT(a.id() == "A000001");
+ CPPUNIT_ASSERT(a.institutionId() == "I000001");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->asset().accountList().count() == 1);
+ CPPUNIT_ASSERT(m->asset().accountList()[0] == "A000001");
+
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.accountCount() == 1);
+ CPPUNIT_ASSERT(institution.accountList()[0] == "A000001");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ // try to add this account again, should not work
+ ft.restart();
+ try {
+ MyMoneyAccount parent = m->asset();
+ m->addAccount(a, parent);
+ CPPUNIT_FAIL("Expecting exception!");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ }
+
+ // check that we can modify the local object and
+ // reload it from the file
+ a.setName("AccountX");
+ a = m->account("A000001");
+ CPPUNIT_ASSERT(a.name() == "Account1");
+
+ storage->m_dirty = false;
+
+ // check if we can get the same info to a different object
+ c = m->account("A000001");
+ CPPUNIT_ASSERT(c.accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(c.id() == "A000001");
+ CPPUNIT_ASSERT(c.name() == "Account1");
+ CPPUNIT_ASSERT(c.institutionId() == "I000001");
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+
+ // add a second account
+ institution = m->institution("I000002");
+ b.setName("Account2");
+ b.setInstitutionId(institution.id());
+ ft.restart();
+ try {
+ MyMoneyAccount parent = m->asset();
+ m->addAccount(b, parent);
+ ft.commit();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(b.id() == "A000002");
+ CPPUNIT_ASSERT(b.parentAccountId() == "AStd::Asset");
+ CPPUNIT_ASSERT(m->accountCount() == 7);
+
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.accountCount() == 1);
+ CPPUNIT_ASSERT(institution.accountList()[0] == "A000001");
+
+ institution = m->institution("I000002");
+ CPPUNIT_ASSERT(institution.accountCount() == 1);
+ CPPUNIT_ASSERT(institution.accountList()[0] == "A000002");
+
+ CPPUNIT_ASSERT(m->asset().accountList().count() == 2);
+ CPPUNIT_ASSERT(m->asset().accountList()[0] == "A000001");
+ CPPUNIT_ASSERT(m->asset().accountList()[1] == "A000002");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ MyMoneyAccount p;
+
+ p = m->account("A000002");
+ CPPUNIT_ASSERT(p.accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(p.id() == "A000002");
+ CPPUNIT_ASSERT(p.name() == "Account2");
+ CPPUNIT_ASSERT(p.institutionId() == "I000002");
+}
+
+void MyMoneyFileTest::testModifyAccount() {
+ testAddAccounts();
+ storage->m_dirty = false;
+
+ MyMoneyAccount p = m->account("A000001");
+ MyMoneyInstitution institution;
+
+ CPPUNIT_ASSERT(p.accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(p.name() == "Account1");
+
+ p.setName("New account name");
+ MyMoneyFileTransaction ft;
+ try {
+ m->modifyAccount(p);
+ ft.commit();
+
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->accountCount() == 7);
+ CPPUNIT_ASSERT(p.accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(p.name() == "New account name");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+ storage->m_dirty = false;
+
+ // try to move account to new institution
+ p.setInstitutionId("I000002");
+ ft.restart();
+ try {
+ m->modifyAccount(p);
+ ft.commit();
+
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->accountCount() == 7);
+ CPPUNIT_ASSERT(p.accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(p.name() == "New account name");
+ CPPUNIT_ASSERT(p.institutionId() == "I000002");
+
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.accountCount() == 0);
+
+ institution = m->institution("I000002");
+ CPPUNIT_ASSERT(institution.accountCount() == 2);
+ CPPUNIT_ASSERT(institution.accountList()[0] == "A000002");
+ CPPUNIT_ASSERT(institution.accountList()[1] == "A000001");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+ storage->m_dirty = false;
+
+ // try to fool engine a bit
+ p.setParentAccountId("A000001");
+ ft.restart();
+ try {
+ m->modifyAccount(p);
+ CPPUNIT_FAIL("Expecting exception!");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testReparentAccount() {
+ testAddAccounts();
+ storage->m_dirty = false;
+
+ MyMoneyAccount p = m->account("A000001");
+ MyMoneyAccount q = m->account("A000002");
+ MyMoneyAccount o = m->account(p.parentAccountId());
+
+ // make A000001 a child of A000002
+ MyMoneyFileTransaction ft;
+ try {
+ CPPUNIT_ASSERT(p.parentAccountId() != q.id());
+ CPPUNIT_ASSERT(o.accountCount() == 2);
+ CPPUNIT_ASSERT(q.accountCount() == 0);
+ m->reparentAccount(p, q);
+ ft.commit();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(p.parentAccountId() == q.id());
+ CPPUNIT_ASSERT(q.accountCount() == 1);
+ CPPUNIT_ASSERT(q.id() == "A000002");
+ CPPUNIT_ASSERT(p.id() == "A000001");
+ CPPUNIT_ASSERT(q.accountList()[0] == p.id());
+
+ o = m->account(o.id());
+ CPPUNIT_ASSERT(o.accountCount() == 1);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+void MyMoneyFileTest::testRemoveStdAccount(const MyMoneyAccount& acc) {
+ QString txt("Exception expected while removing account ");
+ txt += acc.id();
+ MyMoneyFileTransaction ft;
+ try {
+ m->removeAccount(acc);
+ CPPUNIT_FAIL(txt.latin1());
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testRemoveAccount() {
+ MyMoneyInstitution institution;
+
+ testAddAccounts();
+ CPPUNIT_ASSERT(m->accountCount() == 7);
+ storage->m_dirty = false;
+
+ QString id;
+ MyMoneyAccount p = m->account("A000001");
+
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyAccount q("Ainvalid", p);
+ m->removeAccount(q);
+ CPPUNIT_FAIL("Exception expected!");
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ }
+
+ ft.restart();
+ try {
+ m->removeAccount(p);
+ ft.commit();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->accountCount() == 6);
+ institution = m->institution("I000001");
+ CPPUNIT_ASSERT(institution.accountCount() == 0);
+ CPPUNIT_ASSERT(m->asset().accountList().count() == 1);
+
+ institution = m->institution("I000002");
+ CPPUNIT_ASSERT(institution.accountCount() == 1);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ // Check that the standard account-groups cannot be removed
+ testRemoveStdAccount(m->liability());
+ testRemoveStdAccount(m->asset());
+ testRemoveStdAccount(m->expense());
+ testRemoveStdAccount(m->income());
+}
+
+void MyMoneyFileTest::testRemoveAccountTree() {
+ testReparentAccount();
+ MyMoneyAccount a = m->account("A000002");
+
+ MyMoneyFileTransaction ft;
+ // remove the account
+ try {
+ m->removeAccount(a);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+ CPPUNIT_ASSERT(m->accountCount() == 6);
+
+ // make sure it's gone
+ try {
+ m->account("A000002");
+ CPPUNIT_FAIL("Exception expected!");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ // make sure that children are re-parented to parent account
+ try {
+ a = m->account("A000001");
+ CPPUNIT_ASSERT(a.parentAccountId() == m->asset().id());
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+}
+
+void MyMoneyFileTest::testAccountListRetrieval () {
+ QValueList<MyMoneyAccount> list;
+
+ storage->m_dirty = false;
+ m->accountList(list);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(list.count() == 0);
+
+ testAddAccounts();
+
+ storage->m_dirty = false;
+ list.clear();
+ m->accountList(list);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(list.count() == 2);
+
+ CPPUNIT_ASSERT(list[0].accountType() == MyMoneyAccount::Checkings);
+ CPPUNIT_ASSERT(list[1].accountType() == MyMoneyAccount::Checkings);
+}
+
+void MyMoneyFileTest::testAddTransaction () {
+ testAddAccounts();
+ MyMoneyTransaction t, p;
+
+ MyMoneyAccount exp1;
+ exp1.setAccountType(MyMoneyAccount::Expense);
+ exp1.setName("Expense1");
+ MyMoneyAccount exp2;
+ exp2.setAccountType(MyMoneyAccount::Expense);
+ exp2.setName("Expense2");
+
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyAccount parent = m->expense();
+ m->addAccount(exp1, parent);
+ m->addAccount(exp2, parent);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ // fake the last modified flag to check that the
+ // date is updated when we add the transaction
+ MyMoneyAccount a = m->account("A000001");
+ a.setLastModified(QDate(1,2,3));
+ ft.restart();
+ try {
+ m->modifyAccount(a);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+ ft.restart();
+
+ CPPUNIT_ASSERT(m->accountCount() == 9);
+ a = m->account("A000001");
+ CPPUNIT_ASSERT(a.lastModified() == QDate(1,2,3));
+
+ // construct a transaction and add it to the pool
+ t.setPostDate(QDate(2002,2,1));
+ t.setMemo("Memotext");
+
+ MyMoneySplit split1;
+ MyMoneySplit split2;
+
+ split1.setAccountId("A000001");
+ split1.setShares(-1000);
+ split1.setValue(-1000);
+ split2.setAccountId("A000003");
+ split2.setValue(1000);
+ split2.setShares(1000);
+ try {
+ t.addSplit(split1);
+ t.addSplit(split2);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+/*
+ // FIXME: we don't have a payee and a number field right now
+ // guess we should have a number field per split, don't know
+ // about the payee
+ t.setMethod(MyMoneyCheckingTransaction::Withdrawal);
+ t.setPayee("Thomas Baumgart");
+ t.setNumber("1234");
+ t.setState(MyMoneyCheckingTransaction::Cleared);
+*/
+ storage->m_dirty = false;
+
+ ft.restart();
+ try {
+ m->addTransaction(t);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+ ft.restart();
+
+ CPPUNIT_ASSERT(t.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(t.postDate() == QDate(2002,2,1));
+ CPPUNIT_ASSERT(t.entryDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(m->dirty() == true);
+
+ // check the balance of the accounts
+ a = m->account("A000001");
+ CPPUNIT_ASSERT(a.lastModified() == QDate::currentDate());
+ CPPUNIT_ASSERT(a.balance() == MyMoneyMoney(-1000));
+
+ MyMoneyAccount b = m->account("A000003");
+ CPPUNIT_ASSERT(b.lastModified() == QDate::currentDate());
+ CPPUNIT_ASSERT(b.balance() == MyMoneyMoney(1000));
+
+ storage->m_dirty = false;
+
+ // locate transaction in MyMoneyFile via id
+
+ try {
+ p = m->transaction("T000000000000000001");
+ CPPUNIT_ASSERT(p.splitCount() == 2);
+ CPPUNIT_ASSERT(p.memo() == "Memotext");
+ CPPUNIT_ASSERT(p.splits()[0].accountId() == "A000001");
+ CPPUNIT_ASSERT(p.splits()[1].accountId() == "A000003");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ // check if it's in the account(s) as well
+
+ try {
+ p = m->transaction("A000001", 0);
+ CPPUNIT_ASSERT(p.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(p.splitCount() == 2);
+ CPPUNIT_ASSERT(p.memo() == "Memotext");
+ CPPUNIT_ASSERT(p.splits()[0].accountId() == "A000001");
+ CPPUNIT_ASSERT(p.splits()[1].accountId() == "A000003");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ try {
+ p = m->transaction("A000003", 0);
+ CPPUNIT_ASSERT(p.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(p.splitCount() == 2);
+ CPPUNIT_ASSERT(p.memo() == "Memotext");
+ CPPUNIT_ASSERT(p.splits()[0].accountId() == "A000001");
+ CPPUNIT_ASSERT(p.splits()[1].accountId() == "A000003");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+void MyMoneyFileTest::testIsStandardAccount() {
+ CPPUNIT_ASSERT(m->isStandardAccount(m->liability().id()) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(m->asset().id()) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(m->expense().id()) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(m->income().id()) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount("A00001") == false);
+}
+
+void MyMoneyFileTest::testHasActiveSplits() {
+ testAddTransaction();
+
+ CPPUNIT_ASSERT(m->hasActiveSplits("A000001") == true);
+ CPPUNIT_ASSERT(m->hasActiveSplits("A000002") == false);
+}
+
+void MyMoneyFileTest::testModifyTransactionSimple() {
+ // this will test that we can modify the basic attributes
+ // of a transaction
+ testAddTransaction();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000001");
+ t.setMemo("New Memotext");
+ storage->m_dirty = false;
+
+ MyMoneyFileTransaction ft;
+ try {
+ m->modifyTransaction(t);
+ ft.commit();
+ t = m->transaction("T000000000000000001");
+ CPPUNIT_ASSERT(t.memo() == "New Memotext");
+ CPPUNIT_ASSERT(m->dirty() == true);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+void MyMoneyFileTest::testModifyTransactionNewPostDate() {
+ // this will test that we can modify the basic attributes
+ // of a transaction
+ testAddTransaction();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000001");
+ t.setPostDate(QDate(2004,2,1));
+ storage->m_dirty = false;
+
+ MyMoneyFileTransaction ft;
+ try {
+ m->modifyTransaction(t);
+ ft.commit();
+ t = m->transaction("T000000000000000001");
+ CPPUNIT_ASSERT(t.postDate() == QDate(2004,2,1));
+ t = m->transaction("A000001", 0);
+ CPPUNIT_ASSERT(t.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(m->dirty() == true);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+void MyMoneyFileTest::testModifyTransactionNewAccount() {
+ // this will test that we can modify the basic attributes
+ // of a transaction
+ testAddTransaction();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000001");
+ MyMoneySplit s;
+ s = t.splits()[0];
+ s.setAccountId("A000002");
+ t.modifySplit(s);
+
+ storage->m_dirty = false;
+ MyMoneyFileTransaction ft;
+ try {
+/* removed with MyMoneyAccount::Transaction
+ CPPUNIT_ASSERT(m->account("A000001").transactionCount() == 1);
+ CPPUNIT_ASSERT(m->account("A000002").transactionCount() == 0);
+ CPPUNIT_ASSERT(m->account("A000003").transactionCount() == 1);
+*/
+ MyMoneyTransactionFilter f1("A000001");
+ MyMoneyTransactionFilter f2("A000002");
+ MyMoneyTransactionFilter f3("A000003");
+ CPPUNIT_ASSERT(m->transactionList(f1).count() == 1);
+ CPPUNIT_ASSERT(m->transactionList(f2).count() == 0);
+ CPPUNIT_ASSERT(m->transactionList(f3).count() == 1);
+
+ m->modifyTransaction(t);
+ ft.commit();
+ t = m->transaction("T000000000000000001");
+ CPPUNIT_ASSERT(t.postDate() == QDate(2002,2,1));
+ t = m->transaction("A000002", 0);
+ CPPUNIT_ASSERT(m->dirty() == true);
+/* removed with MyMoneyAccount::Transaction
+ CPPUNIT_ASSERT(m->account("A000001").transactionCount() == 0);
+ CPPUNIT_ASSERT(m->account("A000002").transactionCount() == 1);
+ CPPUNIT_ASSERT(m->account("A000003").transactionCount() == 1);
+*/
+ CPPUNIT_ASSERT(m->transactionList(f1).count() == 0);
+ CPPUNIT_ASSERT(m->transactionList(f2).count() == 1);
+ CPPUNIT_ASSERT(m->transactionList(f3).count() == 1);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+void MyMoneyFileTest::testRemoveTransaction () {
+ testModifyTransactionNewPostDate();
+
+ MyMoneyTransaction t;
+ t = m->transaction("T000000000000000001");
+
+ storage->m_dirty = false;
+ MyMoneyFileTransaction ft;
+ try {
+ m->removeTransaction(t);
+ ft.commit();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->transactionCount() == 0);
+/* removed with MyMoneyAccount::Transaction
+ CPPUNIT_ASSERT(m->account("A000001").transactionCount() == 0);
+ CPPUNIT_ASSERT(m->account("A000002").transactionCount() == 0);
+ CPPUNIT_ASSERT(m->account("A000003").transactionCount() == 0);
+*/
+ MyMoneyTransactionFilter f1("A000001");
+ MyMoneyTransactionFilter f2("A000002");
+ MyMoneyTransactionFilter f3("A000003");
+ CPPUNIT_ASSERT(m->transactionList(f1).count() == 0);
+ CPPUNIT_ASSERT(m->transactionList(f2).count() == 0);
+ CPPUNIT_ASSERT(m->transactionList(f3).count() == 0);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+/*
+ * This function is currently not implemented. It's kind of tricky
+ * because it modifies a lot of objects in a single call. This might
+ * be a problem for the undo/redo stuff. That's why I left it out in
+ * the first run. We migh add it, if we need it.
+ * /
+void testMoveSplits() {
+ testModifyTransactionNewPostDate();
+
+ CPPUNIT_ASSERT(m->account("A000001").transactionCount() == 1);
+ CPPUNIT_ASSERT(m->account("A000002").transactionCount() == 0);
+ CPPUNIT_ASSERT(m->account("A000003").transactionCount() == 1);
+
+ try {
+ m->moveSplits("A000001", "A000002");
+ CPPUNIT_ASSERT(m->account("A000001").transactionCount() == 0);
+ CPPUNIT_ASSERT(m->account("A000002").transactionCount() == 1);
+ CPPUNIT_ASSERT(m->account("A000003").transactionCount() == 1);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+*/
+
+void MyMoneyFileTest::testBalanceTotal() {
+ testAddTransaction();
+ MyMoneyTransaction t;
+
+ // construct a transaction and add it to the pool
+ t.setPostDate(QDate(2002,2,1));
+ t.setMemo("Memotext");
+
+ MyMoneySplit split1;
+ MyMoneySplit split2;
+
+ MyMoneyFileTransaction ft;
+ try {
+ split1.setAccountId("A000002");
+ split1.setShares(-1000);
+ split1.setValue(-1000);
+ split2.setAccountId("A000004");
+ split2.setValue(1000);
+ split2.setShares(1000);
+ t.addSplit(split1);
+ t.addSplit(split2);
+ m->addTransaction(t);
+ ft.commit();
+ ft.restart();
+ CPPUNIT_ASSERT(t.id() == "T000000000000000002");
+ CPPUNIT_ASSERT(m->totalBalance("A000001") == MyMoneyMoney(-1000));
+ CPPUNIT_ASSERT(m->totalBalance("A000002") == MyMoneyMoney(-1000));
+
+ MyMoneyAccount p = m->account("A000001");
+ MyMoneyAccount q = m->account("A000002");
+ m->reparentAccount(p, q);
+ ft.commit();
+ CPPUNIT_ASSERT(m->totalBalance("A000001") == MyMoneyMoney(-1000));
+ CPPUNIT_ASSERT(m->totalBalance("A000002") == MyMoneyMoney(-2000));
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+}
+
+void MyMoneyFileTest::testSetAccountName() {
+ MyMoneyFileTransaction ft;
+ try {
+ m->setAccountName(STD_ACC_LIABILITY, "Verbindlichkeiten");
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ ft.restart();
+ try {
+ m->setAccountName(STD_ACC_ASSET, "Vermögen");
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ ft.restart();
+ try {
+ m->setAccountName(STD_ACC_EXPENSE, "Ausgaben");
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ ft.restart();
+ try {
+ m->setAccountName(STD_ACC_INCOME, "Einnahmen");
+ ft.commit();
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ ft.restart();
+
+ CPPUNIT_ASSERT(m->liability().name() == "Verbindlichkeiten");
+ CPPUNIT_ASSERT(m->asset().name() == "Vermögen");
+ CPPUNIT_ASSERT(m->expense().name() == "Ausgaben");
+ CPPUNIT_ASSERT(m->income().name() == "Einnahmen");
+
+ try {
+ m->setAccountName("A000001", "New account name");
+ ft.commit();
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testAddPayee() {
+ MyMoneyPayee p;
+
+ p.setName("THB");
+ CPPUNIT_ASSERT(m->dirty() == false);
+ MyMoneyFileTransaction ft;
+ try {
+ m->addPayee(p);
+ ft.commit();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(p.id() == "P000001");
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyFileTest::testModifyPayee() {
+ MyMoneyPayee p;
+
+ testAddPayee();
+
+ p = m->payee("P000001");
+ p.setName("New name");
+ MyMoneyFileTransaction ft;
+ try {
+ m->modifyPayee(p);
+ ft.commit();
+ p = m->payee("P000001");
+ CPPUNIT_ASSERT(p.name() == "New name");
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyFileTest::testRemovePayee() {
+ MyMoneyPayee p;
+
+ testAddPayee();
+ CPPUNIT_ASSERT(m->payeeList().count() == 1);
+
+ p = m->payee("P000001");
+ MyMoneyFileTransaction ft;
+ try {
+ m->removePayee(p);
+ ft.commit();
+ CPPUNIT_ASSERT(m->payeeList().count() == 0);
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyFileTest::testAddTransactionStd() {
+ testAddAccounts();
+ MyMoneyTransaction t, p;
+ MyMoneyAccount a;
+
+ a = m->account("A000001");
+
+ // construct a transaction and add it to the pool
+ t.setPostDate(QDate(2002,2,1));
+ t.setMemo("Memotext");
+
+ MyMoneySplit split1;
+ MyMoneySplit split2;
+
+ split1.setAccountId("A000001");
+ split1.setShares(-1000);
+ split1.setValue(-1000);
+ split2.setAccountId(STD_ACC_EXPENSE);
+ split2.setValue(1000);
+ split2.setShares(1000);
+ try {
+ t.addSplit(split1);
+ t.addSplit(split2);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+/*
+ // FIXME: we don't have a payee and a number field right now
+ // guess we should have a number field per split, don't know
+ // about the payee
+ t.setMethod(MyMoneyCheckingTransaction::Withdrawal);
+ t.setPayee("Thomas Baumgart");
+ t.setNumber("1234");
+ t.setState(MyMoneyCheckingTransaction::Cleared);
+*/
+ storage->m_dirty = false;
+
+ MyMoneyFileTransaction ft;
+ try {
+ m->addTransaction(t);
+ ft.commit();
+ CPPUNIT_FAIL("Missing expected exception!");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+}
+
+void MyMoneyFileTest::testAttachStorage() {
+ IMyMoneyStorage *store = new MyMoneySeqAccessMgr;
+ MyMoneyFile *file = new MyMoneyFile;
+
+ CPPUNIT_ASSERT(file->storageAttached() == false);
+ try {
+ file->attachStorage(store);
+ CPPUNIT_ASSERT(file->storageAttached() == true);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ try {
+ file->attachStorage(store);
+ CPPUNIT_FAIL("Exception expected!");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ file->attachStorage(0);
+ CPPUNIT_FAIL("Exception expected!");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ file->detachStorage(store);
+ CPPUNIT_ASSERT(file->storageAttached() == false);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+
+ delete store;
+ delete file;
+}
+
+
+void MyMoneyFileTest::testAccount2Category() {
+ testReparentAccount();
+ CPPUNIT_ASSERT(m->accountToCategory("A000001") == "Account2:Account1");
+ CPPUNIT_ASSERT(m->accountToCategory("A000002") == "Account2");
+}
+
+void MyMoneyFileTest::testCategory2Account() {
+ testAddTransaction();
+ MyMoneyAccount a = m->account("A000003");
+ MyMoneyAccount b = m->account("A000004");
+
+ MyMoneyFileTransaction ft;
+ try {
+ m->reparentAccount(b, a);
+ ft.commit();
+ CPPUNIT_ASSERT(m->categoryToAccount("Expense1") == "A000003");
+ CPPUNIT_ASSERT(m->categoryToAccount("Expense1:Expense2") == "A000004");
+ CPPUNIT_ASSERT(m->categoryToAccount("Acc2").isEmpty());
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyFileTest::testAttachedStorage() {
+ CPPUNIT_ASSERT(m->storageAttached() == true);
+ CPPUNIT_ASSERT(m->storage() != 0);
+ IMyMoneyStorage *p = m->storage();
+ m->detachStorage(p);
+ CPPUNIT_ASSERT(m->storageAttached() == false);
+ CPPUNIT_ASSERT(m->storage() == 0);
+ m->attachStorage(p);
+ CPPUNIT_ASSERT(m->storageAttached() == true);
+ CPPUNIT_ASSERT(m->storage() != 0);
+}
+
+void MyMoneyFileTest::testHasAccount() {
+ testAddAccounts();
+
+ MyMoneyAccount a, b;
+ a.setAccountType(MyMoneyAccount::Checkings);
+ a.setName("Account3");
+ b = m->account("A000001");
+ MyMoneyFileTransaction ft;
+ try {
+ m->addAccount(a, b);
+ ft.commit();
+ CPPUNIT_ASSERT(m->accountCount() == 8);
+ CPPUNIT_ASSERT(a.parentAccountId() == "A000001");
+ CPPUNIT_ASSERT(m->hasAccount("A000001", "Account3") == true);
+ CPPUNIT_ASSERT(m->hasAccount("A000001", "Account2") == false);
+ CPPUNIT_ASSERT(m->hasAccount("A000002", "Account3") == false);
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyFileTest::testAddEquityAccount() {
+ MyMoneyAccount i;
+ i.setName("Investment");
+ i.setAccountType(MyMoneyAccount::Investment);
+
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyAccount parent = m->asset();
+ m->addAccount(i, parent);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+ // keep a copy for later use
+ m_inv = i;
+
+ // make sure, that only equity accounts can be children to it
+ MyMoneyAccount a;
+ a.setName("Testaccount");
+ QValueList<MyMoneyAccount::accountTypeE> list;
+ list << MyMoneyAccount::Checkings;
+ list << MyMoneyAccount::Savings;
+ list << MyMoneyAccount::Cash;
+ list << MyMoneyAccount::CreditCard;
+ list << MyMoneyAccount::Loan;
+ list << MyMoneyAccount::CertificateDep;
+ list << MyMoneyAccount::Investment;
+ list << MyMoneyAccount::MoneyMarket;
+ list << MyMoneyAccount::Asset;
+ list << MyMoneyAccount::Liability;
+ list << MyMoneyAccount::Currency;
+ list << MyMoneyAccount::Income;
+ list << MyMoneyAccount::Expense;
+ list << MyMoneyAccount::AssetLoan;
+
+ QValueList<MyMoneyAccount::accountTypeE>::Iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ a.setAccountType(*it);
+ ft.restart();
+ try {
+ char msg[100];
+ m->addAccount(a, i);
+ sprintf(msg, "Can add non-equity type %d to investment", *it);
+ CPPUNIT_FAIL(msg);
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ }
+ }
+ ft.restart();
+ try {
+ a.setName("Teststock");
+ a.setAccountType(MyMoneyAccount::Stock);
+ m->addAccount(a,i);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyFileTest::testReparentEquity() {
+ testAddEquityAccount();
+ testAddEquityAccount();
+ MyMoneyAccount parent;
+
+ // check the bad cases
+ QValueList<MyMoneyAccount::accountTypeE> list;
+ list << MyMoneyAccount::Checkings;
+ list << MyMoneyAccount::Savings;
+ list << MyMoneyAccount::Cash;
+ list << MyMoneyAccount::CertificateDep;
+ list << MyMoneyAccount::MoneyMarket;
+ list << MyMoneyAccount::Asset;
+ list << MyMoneyAccount::AssetLoan;
+ list << MyMoneyAccount::Currency;
+ parent = m->asset();
+ testReparentEquity(list, parent);
+
+ list.clear();
+ list << MyMoneyAccount::CreditCard;
+ list << MyMoneyAccount::Loan;
+ list << MyMoneyAccount::Liability;
+ parent = m->liability();
+ testReparentEquity(list, parent);
+
+ list.clear();
+ list << MyMoneyAccount::Income;
+ parent = m->income();
+ testReparentEquity(list, parent);
+
+ list.clear();
+ list << MyMoneyAccount::Expense;
+ parent = m->expense();
+ testReparentEquity(list, parent);
+
+ // now check the good case
+ MyMoneyAccount stock = m->account("A000002");
+ MyMoneyAccount inv = m->account(m_inv.id());
+ MyMoneyFileTransaction ft;
+ try {
+ m->reparentAccount(stock, inv);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyFileTest::testReparentEquity(QValueList<MyMoneyAccount::accountTypeE>& list, MyMoneyAccount& parent)
+{
+ MyMoneyAccount a;
+ MyMoneyAccount stock = m->account("A000002");
+
+ QValueList<MyMoneyAccount::accountTypeE>::Iterator it;
+ MyMoneyFileTransaction ft;
+ for(it = list.begin(); it != list.end(); ++it) {
+ a.setName(QString("Testaccount %1").arg(*it));
+ a.setAccountType(*it);
+ try {
+ m->addAccount(a, parent);
+ char msg[100];
+ m->reparentAccount(stock, a);
+ sprintf(msg, "Can reparent stock to non-investment type %d account", *it);
+ CPPUNIT_FAIL(msg);
+ } catch(MyMoneyException *e) {
+ ft.commit();
+ delete e;
+ }
+ ft.restart();
+ }
+}
+
+void MyMoneyFileTest::testBaseCurrency(void)
+{
+ MyMoneySecurity base("EUR", "Euro", QChar(0x20ac));
+ MyMoneySecurity ref;
+
+ // make sure, no base currency is set
+ try {
+ ref = m->baseCurrency();
+ CPPUNIT_ASSERT(ref.id().isEmpty());
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ // make sure, we cannot assign an unknown currency
+ try {
+ m->setBaseCurrency(base);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ MyMoneyFileTransaction ft;
+ // add the currency and try again
+ try {
+ m->addCurrency(base);
+ m->setBaseCurrency(base);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+ ft.restart();
+
+ // make sure, the base currency is set
+ try {
+ ref = m->baseCurrency();
+ CPPUNIT_ASSERT(ref.id() == "EUR");
+ CPPUNIT_ASSERT(ref.name() == "Euro");
+ CPPUNIT_ASSERT(ref.tradingSymbol() == QChar(0x20ac));
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ // check if it gets reset when attaching a new storage
+ m->detachStorage(storage);
+
+ MyMoneySeqAccessMgr* newStorage = new MyMoneySeqAccessMgr;
+ m->attachStorage(newStorage);
+
+ ref = m->baseCurrency();
+ CPPUNIT_ASSERT(ref.id().isEmpty());
+
+ m->detachStorage(newStorage);
+ delete newStorage;
+
+ m->attachStorage(storage);
+ ref = m->baseCurrency();
+ CPPUNIT_ASSERT(ref.id() == "EUR");
+ CPPUNIT_ASSERT(ref.name() == "Euro");
+ CPPUNIT_ASSERT(ref.tradingSymbol() == QChar(0x20ac));
+}
+
+void MyMoneyFileTest::testOpeningBalanceNoBase(void)
+{
+ MyMoneyAccount openingAcc;
+ MyMoneySecurity base;
+
+ try {
+ base = m->baseCurrency();
+ openingAcc = m->openingBalanceAccount(base);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyFileTest::testOpeningBalance(void)
+{
+ MyMoneyAccount openingAcc;
+ MyMoneySecurity second("USD", "US Dollar", "$");
+ testBaseCurrency();
+
+ try {
+ openingAcc = m->openingBalanceAccount(m->baseCurrency());
+ CPPUNIT_ASSERT(openingAcc.parentAccountId() == m->equity().id());
+ CPPUNIT_ASSERT(openingAcc.name() == MyMoneyFile::OpeningBalancesPrefix);
+ CPPUNIT_ASSERT(openingAcc.openingDate() == QDate::currentDate());
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ // add a second currency
+ MyMoneyFileTransaction ft;
+ try {
+ m->addCurrency(second);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ QString refName = QString("%1 (%2)").arg(MyMoneyFile::OpeningBalancesPrefix).arg("USD");
+ try {
+ openingAcc = m->openingBalanceAccount(second);
+ CPPUNIT_ASSERT(openingAcc.parentAccountId() == m->equity().id());
+ CPPUNIT_ASSERT(openingAcc.name() == refName);
+ CPPUNIT_ASSERT(openingAcc.openingDate() == QDate::currentDate());
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyFileTest::testModifyStdAccount() {
+ CPPUNIT_ASSERT(m->asset().currencyId().isEmpty());
+ CPPUNIT_ASSERT(m->asset().name() == "Asset");
+ testBaseCurrency();
+ CPPUNIT_ASSERT(m->asset().currencyId().isEmpty());
+ CPPUNIT_ASSERT(!m->baseCurrency().id().isEmpty());
+
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyAccount acc = m->asset();
+ acc.setName("Anlagen");
+ acc.setCurrencyId(m->baseCurrency().id());
+ m->modifyAccount(acc);
+ ft.commit();
+
+ CPPUNIT_ASSERT(m->asset().name() == "Anlagen");
+ CPPUNIT_ASSERT(m->asset().currencyId() == m->baseCurrency().id());
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ ft.restart();
+ try {
+ MyMoneyAccount acc = m->asset();
+ acc.setNumber("Test");
+ m->modifyAccount(acc);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ ft.rollback();
+ delete e;
+ }
+
+}
diff --git a/kmymoney2/mymoney/mymoneyfiletest.h b/kmymoney2/mymoney/mymoneyfiletest.h
new file mode 100644
index 0000000..b54af25
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfiletest.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ mymoneyfiletest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYFILETEST_H__
+#define __MYMONEYFILETEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "autotest.h"
+
+#define private public
+#define protected public
+#include "mymoneyfile.h"
+#include "storage/mymoneyseqaccessmgr.h"
+#undef private
+#undef protected
+
+class MyMoneyFileTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyFileTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testAddOneInstitution);
+ CPPUNIT_TEST(testAddTwoInstitutions);
+ CPPUNIT_TEST(testInstitutionRetrieval);
+ CPPUNIT_TEST(testRemoveInstitution);
+ CPPUNIT_TEST(testInstitutionListRetrieval);
+ CPPUNIT_TEST(testInstitutionModify);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testAddAccounts);
+ CPPUNIT_TEST(testModifyAccount);
+ CPPUNIT_TEST(testModifyStdAccount);
+ CPPUNIT_TEST(testReparentAccount);
+ CPPUNIT_TEST(testRemoveAccount);
+ CPPUNIT_TEST(testRemoveAccountTree);
+ CPPUNIT_TEST(testAccountListRetrieval);
+ CPPUNIT_TEST(testAddTransaction);
+ CPPUNIT_TEST(testHasActiveSplits);
+ CPPUNIT_TEST(testIsStandardAccount);
+ CPPUNIT_TEST(testModifyTransactionSimple);
+ CPPUNIT_TEST(testModifyTransactionNewPostDate);
+ CPPUNIT_TEST(testModifyTransactionNewAccount);
+ CPPUNIT_TEST(testRemoveTransaction);
+ CPPUNIT_TEST(testBalanceTotal);
+ CPPUNIT_TEST(testSetAccountName);
+ CPPUNIT_TEST(testAddPayee);
+ CPPUNIT_TEST(testModifyPayee);
+ CPPUNIT_TEST(testRemovePayee);
+ CPPUNIT_TEST(testAddTransactionStd);
+ CPPUNIT_TEST(testAttachStorage);
+ CPPUNIT_TEST(testAccount2Category);
+ CPPUNIT_TEST(testCategory2Account);
+ CPPUNIT_TEST(testAttachedStorage);
+ CPPUNIT_TEST(testHasAccount);
+ CPPUNIT_TEST(testAddEquityAccount);
+ CPPUNIT_TEST(testReparentEquity);
+ CPPUNIT_TEST(testBaseCurrency);
+ CPPUNIT_TEST(testOpeningBalanceNoBase);
+ CPPUNIT_TEST(testOpeningBalance);
+#if 0
+ CPPUNIT_TEST(testMoveSplits);
+#endif
+ CPPUNIT_TEST_SUITE_END();
+protected:
+ MyMoneyFile *m;
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyAccount m_inv;
+
+public:
+ MyMoneyFileTest ();
+
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testAddOneInstitution();
+ void testAddTwoInstitutions();
+ void testRemoveInstitution();
+ void testInstitutionRetrieval ();
+ void testInstitutionListRetrieval ();
+ void testInstitutionModify();
+ void testSetFunctions();
+ void testAddAccounts();
+ void testModifyAccount();
+ void testModifyStdAccount();
+ void testReparentAccount();
+ void testRemoveAccount();
+ void testRemoveAccountTree();
+ void testAccountListRetrieval ();
+ void testAddTransaction ();
+ void testIsStandardAccount();
+ void testHasActiveSplits();
+ void testModifyTransactionSimple();
+ void testModifyTransactionNewPostDate();
+ void testModifyTransactionNewAccount();
+ void testRemoveTransaction ();
+ void testBalanceTotal();
+ void testSetAccountName();
+ void testAddPayee();
+ void testModifyPayee();
+ void testRemovePayee();
+ void testAddTransactionStd();
+ void testAttachStorage();
+ void testAccount2Category();
+ void testCategory2Account();
+ void testAttachedStorage();
+ void testHasAccount();
+ void testAddEquityAccount();
+ void testReparentEquity();
+ void testReparentEquity(QValueList<MyMoneyAccount::accountTypeE>& list, MyMoneyAccount& parent);
+ void testBaseCurrency();
+ void testOpeningBalanceNoBase();
+ void testOpeningBalance();
+
+private:
+ void testRemoveStdAccount(const MyMoneyAccount& acc);
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp b/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp
new file mode 100644
index 0000000..d6686a6
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfinancialcalculator.cpp
@@ -0,0 +1,348 @@
+/***************************************************************************
+ mymoneyfinancialcalculator.cpp - description
+ -------------------
+ begin : Tue Oct 21 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <math.h>
+#include <stdio.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include "mymoneyfinancialcalculator.h"
+#include "mymoneyexception.h"
+
+// #ifndef HAVE_ROUND
+// #undef roundl
+// #define roundl(a) rnd(a)
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::rnd(const FCALC_DOUBLE x) const
+{
+ FCALC_DOUBLE r,f;
+
+ if(m_prec > 0) {
+#ifdef HAVE_ROUND
+ f = powl(10.0, m_prec);
+ r = roundl(x * f)/f;
+#else
+ char buf[50];
+#if HAVE_LONG_DOUBLE
+ sprintf (buf, "%.*Lf", m_prec, x);
+ sscanf (buf, "%Lf", &r);
+#else
+ sprintf (buf, "%.*f", m_prec, x);
+ sscanf (buf, "%lf", &r);
+#endif
+#endif
+ } else
+ r = roundl(x);
+ return r;
+}
+// #endif
+
+static inline FCALC_DOUBLE dabs(const FCALC_DOUBLE x)
+{
+ return (x >= 0.0) ? x : -x;
+}
+
+MyMoneyFinancialCalculator::MyMoneyFinancialCalculator()
+{
+ setPrec();
+ setPF();
+ setCF();
+ setBep();
+ setDisc();
+
+ setNpp(0.0);
+ setIr(0.0);
+ setPv(0.0);
+ setPmt(0.0);
+ setFv(0.0);
+
+ // clear the mask
+ m_mask = 0;
+}
+
+MyMoneyFinancialCalculator::~MyMoneyFinancialCalculator()
+{
+}
+
+void MyMoneyFinancialCalculator::setPrec(const unsigned short prec)
+{
+ m_prec = prec;
+}
+
+void MyMoneyFinancialCalculator::setPF(const unsigned short PF)
+{
+ m_PF = PF;
+}
+
+void MyMoneyFinancialCalculator::setCF(const unsigned short CF)
+{
+ m_CF = CF;
+}
+
+void MyMoneyFinancialCalculator::setBep(const bool bep)
+{
+ m_bep = bep;
+}
+
+void MyMoneyFinancialCalculator::setDisc(const bool disc)
+{
+ m_disc = disc;
+}
+
+void MyMoneyFinancialCalculator::setIr(const FCALC_DOUBLE ir)
+{
+ m_ir = ir;
+ m_mask |= IR_SET;
+}
+
+void MyMoneyFinancialCalculator::setPv(const FCALC_DOUBLE pv)
+{
+ m_pv = pv;
+ m_mask |= PV_SET;
+}
+
+void MyMoneyFinancialCalculator::setPmt(const FCALC_DOUBLE pmt)
+{
+ m_pmt = pmt;
+ m_mask |= PMT_SET;
+}
+
+void MyMoneyFinancialCalculator::setNpp(const FCALC_DOUBLE npp)
+{
+ m_npp = npp;
+ m_mask |= NPP_SET;
+}
+
+void MyMoneyFinancialCalculator::setFv(const FCALC_DOUBLE fv)
+{
+ m_fv = fv;
+ m_mask |= FV_SET;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::numPayments(void)
+{
+ const unsigned short mask = PV_SET | IR_SET | PMT_SET | FV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of numPayments");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE CC = _Cx(eint);
+
+ CC = (CC - m_fv) / (CC + m_pv);
+ m_npp = (CC > 0.0) ? logl (CC) / logl (eint +1.0) : 0.0;
+
+ m_mask |= NPP_SET;
+ return m_npp;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::payment(void)
+{
+ const unsigned short mask = PV_SET | IR_SET | NPP_SET | FV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of payment");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE AA = _Ax(eint);
+ FCALC_DOUBLE BB = _Bx(eint);
+
+ m_pmt = -rnd((m_fv + m_pv * (AA + 1.0)) / (AA * BB));
+ //m_pmt = -floorl((m_fv + m_pv * (AA + 1.0)) / (AA * BB));
+
+ m_mask |= PMT_SET;
+ return m_pmt;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::presentValue(void)
+{
+ const unsigned short mask = PMT_SET | IR_SET | NPP_SET | FV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of payment");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE AA = _Ax(eint);
+ FCALC_DOUBLE CC = _Cx(eint);
+
+ m_pv = rnd(-(m_fv + (AA * CC)) / (AA + 1.0));
+
+ m_mask |= PV_SET;
+ return m_pv;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::futureValue(void)
+{
+ const unsigned short mask = PMT_SET | IR_SET | NPP_SET | PV_SET;
+
+ if((m_mask & mask) != mask)
+ throw new MYMONEYEXCEPTION("Not all parameters set for calculation of payment");
+
+ FCALC_DOUBLE eint = eff_int();
+ FCALC_DOUBLE AA = _Ax(eint);
+ FCALC_DOUBLE CC = _Cx(eint);
+ m_fv = rnd(-(m_pv + AA * (m_pv + CC)));
+
+ m_mask |= FV_SET;
+ return m_fv;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::interestRate(void)
+{
+ FCALC_DOUBLE eint = 0.0;
+ FCALC_DOUBLE a = 0.0;
+ FCALC_DOUBLE dik = 0.0;
+
+ const FCALC_DOUBLE ratio = 1e4;
+ int ri;
+
+ if (m_pmt == 0.0) {
+ eint = powl ((dabs (m_fv) / dabs (m_pv)), (1.0 / m_npp)) - 1.0;
+ } else {
+ if ((m_pmt * m_fv) < 0.0) {
+ if(m_pv)
+ a = -1.0;
+ else
+ a = 1.0;
+ eint =
+ dabs ((m_fv + a * m_npp * m_pmt) /
+ (3.0 *
+ ((m_npp - 1.0) * (m_npp - 1.0) * m_pmt + m_pv -
+ m_fv)));
+ } else {
+ if ((m_pv * m_pmt) < 0.0) {
+ eint = dabs ((m_npp * m_pmt + m_pv + m_fv) / (m_npp * m_pv));
+ } else {
+ a = dabs (m_pmt / (dabs(m_pv) + dabs(m_fv)));
+ eint = a + 1.0 / (a * m_npp * m_npp * m_npp);
+ }
+ }
+ do {
+ try {
+ dik = _fi(eint) / _fip(eint);
+ eint -= dik;
+ } catch(MyMoneyException *e) {
+ delete e;
+ eint = 0;
+ }
+ (void) modfl(ratio * (dik / eint), &a);
+ ri = static_cast<unsigned> (a);
+ }
+ while (ri);
+ }
+ m_mask |= IR_SET;
+ m_ir = rnd(nom_int(eint) * 100.0);
+ return m_ir;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_fi(const FCALC_DOUBLE eint) const
+{
+ return _Ax(eint) * (m_pv + _Cx(eint)) + m_pv + m_fv;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_fip(const FCALC_DOUBLE eint) const
+{
+ double AA = _Ax(eint);
+ double CC = _Cx(eint);
+ double D = (AA + 1.0) / (eint + 1.0);
+
+ return m_npp *(m_pv + CC) * D - (AA * CC) / eint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_Ax(const FCALC_DOUBLE eint) const
+{
+ return powl ((eint + 1.0), m_npp) - 1.0;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_Bx(const FCALC_DOUBLE eint) const
+{
+ if(eint == 0.0)
+ throw new MYMONEYEXCEPTION("Zero interest");
+
+ if(m_bep == false)
+ return static_cast<FCALC_DOUBLE>(1.0) / eint;
+
+ return (eint + 1.0) / eint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::_Cx(const FCALC_DOUBLE eint) const
+{
+ return m_pmt * _Bx(eint);
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::eff_int(void) const
+{
+ FCALC_DOUBLE nint = m_ir / 100.0;
+ FCALC_DOUBLE eint;
+
+ if(m_disc) { // periodically compound?
+ if(m_CF == m_PF) { // same frequency?
+ eint = nint / static_cast<FCALC_DOUBLE>(m_CF);
+
+ } else {
+ eint = powl((static_cast<FCALC_DOUBLE>(1.0) + (nint / static_cast<FCALC_DOUBLE>(m_CF))),
+ (static_cast<FCALC_DOUBLE>(m_CF) / static_cast<FCALC_DOUBLE>(m_PF))) - 1.0;
+
+ }
+
+ } else {
+ eint = expl(nint / static_cast<FCALC_DOUBLE>(m_PF)) - 1.0;
+ }
+
+ return eint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::nom_int(const FCALC_DOUBLE eint) const
+{
+ FCALC_DOUBLE nint;
+
+ if(m_disc) {
+ if(m_CF == m_PF) {
+ nint = m_CF * eint;
+
+ } else {
+ nint = m_CF * (powl ((eint + 1.0), (static_cast<FCALC_DOUBLE>(m_PF) / static_cast<FCALC_DOUBLE>(m_CF))) - 1.0);
+ }
+ } else
+ nint = logl (powl (eint + 1.0, m_PF));
+
+ return nint;
+}
+
+FCALC_DOUBLE MyMoneyFinancialCalculator::interestDue(void) const
+{
+ FCALC_DOUBLE eint = eff_int();
+
+ return (m_pv + (m_bep ? m_pmt : 0.0)) * eint;
+}
+
diff --git a/kmymoney2/mymoney/mymoneyfinancialcalculator.h b/kmymoney2/mymoney/mymoneyfinancialcalculator.h
new file mode 100644
index 0000000..c603d12
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfinancialcalculator.h
@@ -0,0 +1,317 @@
+/***************************************************************************
+ mymoneyfinancialcalculator.h - description
+ -------------------
+ begin : Tue Oct 21 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYFINANCIALCALCULATOR_H
+#define MYMONEYFINANCIALCALCULATOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cmath>
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+#ifdef _GLIBCPP_HAVE_MODFL
+#define HAVE_LONG_DOUBLE 1
+#endif
+
+#ifndef HAVE_LONG_DOUBLE
+#define HAVE_LONG_DOUBLE 0
+#endif
+
+#if HAVE_LONG_DOUBLE
+#define FCALC_DOUBLE long double
+#else
+#define FCALC_DOUBLE double
+#define modfl(a,b) modf(a,b)
+#define roundl(a) round(a)
+#define powl(a,b) pow(a,b)
+#define expl(a) exp(a)
+#define logl(a) log(a)
+#define floorl(a) floor(a)
+#define fabsl(a) fabs(a)
+#endif
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class implements the financial calculator as found in GNUCash.
+ * For a detailed description of the algorithms see
+ * gnucash-1.8.5/src/doc/finutil.html.
+ */
+class KMYMONEY_EXPORT MyMoneyFinancialCalculator
+{
+public:
+ MyMoneyFinancialCalculator();
+ ~MyMoneyFinancialCalculator();
+
+ /**
+ * This method calculates the number of payments required to amortize
+ * the loan. ir, pv, fv and pmt must be set. It sets the member variable
+ * m_npp with the calculated value.
+ *
+ * @return number of periodic payments
+ *
+ * @exception If one of the required values is not set, a MyMoneyException
+ * will be thrown
+ */
+ FCALC_DOUBLE numPayments();
+
+ /**
+ * This method calculates the amount of the payment (amortization and interest)
+ * for the loan. ir, pv, fv and npp must be set. It sets the member variable
+ * m_pmt with the calculated value.
+ *
+ * @return amount of payment
+ *
+ * @exception If one of the required values is not set, a MyMoneyException
+ * will be thrown
+ */
+ FCALC_DOUBLE payment();
+
+ /**
+ * This method calculates the present value
+ * for the loan. ir, pmt, fv and npp must be set. It sets the member variable
+ * m_pv with the calculated value.
+ *
+ * @return present value of loan
+ *
+ * @exception If one of the required values is not set, a MyMoneyException
+ * will be thrown
+ */
+ FCALC_DOUBLE presentValue();
+
+ /**
+ * This method calculates the future value
+ * for the loan. ir, pmt, pv and npp must be set. It sets the member variable
+ * m_fv with the calculated value.
+ *
+ * @return future value of loan
+ *
+ * @exception If one of the required values is not set, a MyMoneyException
+ * will be thrown
+ */
+ FCALC_DOUBLE futureValue();
+
+ /**
+ * This method calculates the nominal interest rate
+ * for the loan. fv, pmt, pv and npp must be set. It sets the member variable
+ * m_ir with the calculated value.
+ *
+ * @return interest rate of the loan
+ *
+ * @exception If one of the required values is not set, a MyMoneyException
+ * will be thrown
+ */
+ FCALC_DOUBLE interestRate();
+
+ /**
+ * This method calculates the interest due for the next payment according
+ * to the equation
+ *
+ * id[n] = (pv[n-1] + (X * pmt)) * i
+ *
+ * with
+ *
+ * - pv[n-1]\n
+ * the present value at the end of the last period
+ * - X\n
+ * 0 for end of period payments, 1 for beginning of period payments
+ * - pmt\n
+ * the periodic payment amount and
+ * - i\n
+ * the effective interest rate
+ *
+ * pv[n-1] will be the value as set with setPv(), i will be calculated
+ * from the nominal interest rate as set with setIr(), pmt will be the
+ * value as set with setPmt() and X is determined by the argument to
+ * setBep().
+ *
+ * @return the interest amount
+ */
+ FCALC_DOUBLE interestDue(void) const;
+
+ /**
+ * This method sets the rounding precision to @p prec fractional
+ * digits. The default of @p is 2. Rounding is applied to pv, pmt
+ * and fv.
+ *
+ * @param prec Number of fractional digits after rounding.
+ */
+ void setPrec(const unsigned short prec = 2);
+
+ /**
+ * This method sets the number of payment periods to the value
+ * passed in parameter @p npp. The length of a period is controlled
+ * via setPF().
+ *
+ * @param npp number of payment periods
+ */
+ void setNpp(const FCALC_DOUBLE npp);
+
+ FCALC_DOUBLE npp(void) const { return m_npp; };
+
+ /**
+ * This method sets the payment frequency. The parameter @p PF
+ * specifies the payments per year.
+ *
+ * - 1 == annual
+ * - 2 == semi-annual
+ * - 3 == tri-annual
+ * - 4 == quaterly
+ * - 6 == bi-monthly
+ * - 12 == monthly
+ * - 24 == semi-monthly
+ * - 26 == bi-weekly
+ * - 52 == weekly
+ * - 360 == daily
+ * - 365 == daily
+ *
+ * @param PF length of payment period (default is 12 - monthly)
+ */
+ void setPF(const unsigned short PF = 12);
+
+ /**
+ * This method sets the compounding frequency. The parameter @p CF
+ * specifies the compounding period per year.
+ *
+ * - 1 == annual
+ * - 2 == semi-annual
+ * - 3 == tri-annual
+ * - 4 == quaterly
+ * - 6 == bi-monthly
+ * - 12 == monthly
+ * - 24 == semi-monthly
+ * - 26 == bi-weekly
+ * - 52 == weekly
+ * - 360 == daily
+ * - 365 == daily
+ *
+ * @param CF length of compounding period (default is 12 - monthly)
+ */
+ void setCF(const unsigned short CF = 12);
+
+ /**
+ * This method controls whether the interest will be calculated
+ * at the end of the payment period of at it's beginning.
+ *
+ * @param bep if @p false (default) then the interest is due at the
+ * end of the payment period, if @p true at it's beginning.
+ */
+ void setBep(const bool bep = false);
+
+ /**
+ * This method controls whether the interest is compounded in periods
+ * or continously.
+ *
+ * @param disc if @p true (default) then the interest is compounded in
+ * periods, if @p false continously.
+ */
+ void setDisc(const bool disc = true);
+
+ /**
+ * This method sets the nominal interest rate to the value passed
+ * in the argument @p ir.
+ *
+ * @param ir nominal interest rate
+ */
+ void setIr(const FCALC_DOUBLE ir);
+
+ FCALC_DOUBLE ir(void) const { return m_ir; };
+
+ /**
+ * This method sets the present value to the value passed
+ * in the argument @p pv.
+ *
+ * @param pv present value
+ */
+ void setPv(const FCALC_DOUBLE pv);
+
+ FCALC_DOUBLE pv(void) const { return m_pv; };
+
+ /**
+ * This method sets the payment amount to the value passed
+ * in the argument @p pmt.
+ *
+ * @param pmt payment amount
+ */
+ void setPmt(const FCALC_DOUBLE pmt);
+
+ FCALC_DOUBLE pmt(void) const { return m_pmt; };
+
+ /**
+ * This method sets the future value to the value passed
+ * in the argument @p fv.
+ *
+ * @param fv future value
+ */
+ void setFv(const FCALC_DOUBLE fv);
+
+ FCALC_DOUBLE fv(void) const { return m_fv; };
+
+private:
+ FCALC_DOUBLE eff_int(void) const;
+ FCALC_DOUBLE nom_int(const FCALC_DOUBLE eint) const;
+ FCALC_DOUBLE rnd(const FCALC_DOUBLE x) const;
+
+ FCALC_DOUBLE _Ax(const FCALC_DOUBLE eint) const;
+ FCALC_DOUBLE _Bx(const FCALC_DOUBLE eint) const;
+ FCALC_DOUBLE _Cx(const FCALC_DOUBLE eint) const;
+ FCALC_DOUBLE _fi(const FCALC_DOUBLE eint) const;
+ FCALC_DOUBLE _fip(const FCALC_DOUBLE eint) const;
+
+private:
+ FCALC_DOUBLE m_ir; // nominal interest rate
+ FCALC_DOUBLE m_pv; // present value
+ FCALC_DOUBLE m_pmt; // periodic payment
+ FCALC_DOUBLE m_fv; // future value
+ FCALC_DOUBLE m_npp; // number of payment periods
+
+ unsigned short m_CF; // compounding frequency
+ unsigned short m_PF; // payment frequency
+
+ unsigned short m_prec; // precision for roundoff for pv, pmt and fv
+ // i is not rounded, n is integer
+
+ bool m_bep; // beginning/end of period payment flag
+ bool m_disc; // discrete/continous compounding flag
+
+ unsigned short m_mask; // available value mask
+ #define PV_SET 0x0001
+ #define IR_SET 0x0002
+ #define PMT_SET 0x0004
+ #define NPP_SET 0x0008
+ #define FV_SET 0x0010
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyfinancialcalculatortest.cpp b/kmymoney2/mymoney/mymoneyfinancialcalculatortest.cpp
new file mode 100644
index 0000000..fa5b1a3
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfinancialcalculatortest.cpp
@@ -0,0 +1,189 @@
+/***************************************************************************
+ mymoneyfinancialcalculatortest.cpp
+ -------------------
+ copyright : (C) 2003 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include <iostream>
+
+#include <math.h>
+#include "mymoneymoney.h"
+#include "mymoneyfinancialcalculatortest.h"
+
+MyMoneyFinancialCalculatorTest::MyMoneyFinancialCalculatorTest () {}
+
+
+void MyMoneyFinancialCalculatorTest::setUp () {
+ m = new MyMoneyFinancialCalculator;
+}
+
+void MyMoneyFinancialCalculatorTest::tearDown () {
+ delete m;
+}
+
+void MyMoneyFinancialCalculatorTest::testEmptyConstructor() {
+ CPPUNIT_ASSERT(m->m_ir == 0.0);
+ CPPUNIT_ASSERT(m->m_pv == 0.0);
+ CPPUNIT_ASSERT(m->m_pmt == 0.0);
+ CPPUNIT_ASSERT(m->m_fv == 0.0);
+ CPPUNIT_ASSERT(m->m_npp == 0);
+ CPPUNIT_ASSERT(m->m_CF == 12);
+ CPPUNIT_ASSERT(m->m_PF == 12);
+ CPPUNIT_ASSERT(m->m_prec == 2);
+ CPPUNIT_ASSERT(m->m_bep == false);
+ CPPUNIT_ASSERT(m->m_disc == true);
+ CPPUNIT_ASSERT(m->m_mask == 0);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetPrec() {
+ m->setPrec(3);
+ CPPUNIT_ASSERT(m->m_prec == 3);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetNpp() {
+ m->setNpp(20);
+ CPPUNIT_ASSERT(m->m_npp == 20);
+ CPPUNIT_ASSERT(m->m_mask == NPP_SET);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetPF() {
+ m->setPF(1);
+ CPPUNIT_ASSERT(m->m_PF == 1);
+ m->setPF();
+ CPPUNIT_ASSERT(m->m_PF == 12);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetCF() {
+ m->setCF(1);
+ CPPUNIT_ASSERT(m->m_CF == 1);
+ m->setCF();
+ CPPUNIT_ASSERT(m->m_CF == 12);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetBep() {
+ m->setBep(true);
+ CPPUNIT_ASSERT(m->m_bep == true);
+ m->setBep();
+ CPPUNIT_ASSERT(m->m_bep == false);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetDisc() {
+ m->setDisc(false);
+ CPPUNIT_ASSERT(m->m_disc == false);
+ m->setDisc();
+ CPPUNIT_ASSERT(m->m_disc == true);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetIr() {
+ m->setIr(12.3);
+ CPPUNIT_ASSERT(m->m_ir == 12.3);
+ CPPUNIT_ASSERT(m->m_mask == IR_SET);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetPv() {
+ m->setPv(23.4);
+ CPPUNIT_ASSERT(m->m_pv == 23.4);
+ CPPUNIT_ASSERT(m->m_mask == PV_SET);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetPmt() {
+ m->setPmt(34.5);
+ CPPUNIT_ASSERT(m->m_pmt == 34.5);
+ CPPUNIT_ASSERT(m->m_mask == PMT_SET);
+}
+
+void MyMoneyFinancialCalculatorTest::testSetFv() {
+ m->setFv(45.6);
+ CPPUNIT_ASSERT(m->m_fv == 45.6);
+ CPPUNIT_ASSERT(m->m_mask == FV_SET);
+}
+
+void MyMoneyFinancialCalculatorTest::testCombinedSet() {
+ m->setNpp(20);
+ m->setIr(12.3);
+ m->setPv(23.4);
+ m->setPmt(34.5);
+ m->setFv(45.6);
+
+ CPPUNIT_ASSERT(m->m_mask == (NPP_SET | PV_SET | IR_SET | PMT_SET | FV_SET));
+}
+
+void MyMoneyFinancialCalculatorTest::testNumPayments() {
+ m->setPF(12);
+ m->setCF(12);
+ try {
+ m->numPayments();
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->setPv(-80000.0);
+ m->numPayments();
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->setIr(12.0);
+ m->numPayments();
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->setPmt(7108.0);
+ m->numPayments();
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->setFv(0.0);
+ m->numPayments();
+ } catch (MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(roundl(m->m_npp) == 12);
+}
+
+void MyMoneyFinancialCalculatorTest::testUseCase1() {
+ m->setPv(-300000.0);
+ m->setIr(5.0);
+ m->setNpp(360);
+ m->setFv(0.0);
+ m->setPF(12);
+ MyMoneyMoney res(m->payment());
+ CPPUNIT_ASSERT(res == MyMoneyMoney(161046,100));
+
+ res = MyMoneyMoney(m->futureValue());
+ CPPUNIT_ASSERT(res == MyMoneyMoney(405,100));
+}
+
+void MyMoneyFinancialCalculatorTest::testUseCase2() {
+ m->setPv(-320000.0);
+ m->setIr(5.0);
+ m->setNpp(360);
+ m->setFv(0.0);
+ m->setPF(12);
+ MyMoneyMoney res(m->payment());
+ CPPUNIT_ASSERT(res == MyMoneyMoney(171783,100));
+
+ res = MyMoneyMoney(m->futureValue());
+ CPPUNIT_ASSERT(res == MyMoneyMoney(-67,100));
+}
diff --git a/kmymoney2/mymoney/mymoneyfinancialcalculatortest.h b/kmymoney2/mymoney/mymoneyfinancialcalculatortest.h
new file mode 100644
index 0000000..f1d6b3b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyfinancialcalculatortest.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ mymoneyfinancialcalculatortest.h
+ -------------------
+ copyright : (C) 2003 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYFINANCIALCALCULATORTEST_H__
+#define __MYMONEYFINANCIALCALCULATORTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "autotest.h"
+
+#define private public
+#define protected public
+#include "mymoneyfinancialcalculator.h"
+#undef private
+#undef protected
+
+class MyMoneyFinancialCalculatorTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyFinancialCalculatorTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testSetPrec);
+ CPPUNIT_TEST(testSetNpp);
+ CPPUNIT_TEST(testSetPF);
+ CPPUNIT_TEST(testSetCF);
+ CPPUNIT_TEST(testSetBep);
+ CPPUNIT_TEST(testSetDisc);
+ CPPUNIT_TEST(testSetIr);
+ CPPUNIT_TEST(testSetPv);
+ CPPUNIT_TEST(testSetPmt);
+ CPPUNIT_TEST(testSetFv);
+ CPPUNIT_TEST(testCombinedSet);
+ CPPUNIT_TEST(testNumPayments);
+ CPPUNIT_TEST(testUseCase1);
+ CPPUNIT_TEST(testUseCase2);
+ CPPUNIT_TEST_SUITE_END();
+protected:
+ MyMoneyFinancialCalculator *m;
+
+public:
+ MyMoneyFinancialCalculatorTest ();
+
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testSetPrec();
+ void testSetNpp();
+ void testSetPF();
+ void testSetCF();
+ void testSetBep();
+ void testSetDisc();
+ void testSetIr();
+ void testSetPv();
+ void testSetPmt();
+ void testSetFv();
+ void testCombinedSet();
+ void testNumPayments();
+ void testUseCase1();
+ void testUseCase2();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyforecast.cpp b/kmymoney2/mymoney/mymoneyforecast.cpp
new file mode 100644
index 0000000..56125ea
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyforecast.cpp
@@ -0,0 +1,1340 @@
+/***************************************************************************
+ mymoneyforecast.cpp
+ -------------------
+ begin : Wed May 30 2007
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyforecast.h"
+#include "../kmymoneyglobalsettings.h"
+#include "mymoneyfile.h"
+#include "mymoneytransactionfilter.h"
+#include "mymoneyfinancialcalculator.h"
+
+MyMoneyForecast::MyMoneyForecast() :
+ m_forecastMethod(0),
+ m_historyMethod(0),
+ m_skipOpeningDate(true),
+ m_includeUnusedAccounts(false),
+ m_forecastDone(false)
+{
+ setForecastCycles(KMyMoneyGlobalSettings::forecastCycles());
+ setAccountsCycle(KMyMoneyGlobalSettings::forecastAccountCycle());
+ setHistoryStartDate(QDate::currentDate().addDays(-forecastCycles()*accountsCycle()));
+ setHistoryEndDate(QDate::currentDate().addDays(-1));
+ setForecastDays(KMyMoneyGlobalSettings::forecastDays());
+ setBeginForecastDay(KMyMoneyGlobalSettings::beginForecastDay());
+ setForecastMethod(KMyMoneyGlobalSettings::forecastMethod());
+ setHistoryMethod(KMyMoneyGlobalSettings::historyMethod());
+ setIncludeFutureTransactions(KMyMoneyGlobalSettings::includeFutureTransactions());
+ setIncludeScheduledTransactions(KMyMoneyGlobalSettings::includeScheduledTransactions());
+}
+
+
+void MyMoneyForecast::doForecast()
+{
+ int fDays = calculateBeginForecastDay();
+ int fMethod = forecastMethod();
+ int fAccCycle = accountsCycle();
+ int fCycles = forecastCycles();
+
+ //validate settings
+ if(fAccCycle < 1
+ || fCycles < 1
+ || fDays < 1)
+ {
+ throw new MYMONEYEXCEPTION("Illegal settings when calling doForecast. Settings must be higher than 0");
+ }
+
+ //initialize global variables
+ setForecastDays(fDays);
+ setForecastStartDate(QDate::currentDate().addDays(1));
+ setForecastEndDate(QDate::currentDate().addDays(fDays));
+ setAccountsCycle(fAccCycle);
+ setForecastCycles(fCycles);
+ setHistoryStartDate(forecastCycles() * accountsCycle());
+ setHistoryEndDate(QDate::currentDate().addDays(-1)); //yesterday
+
+ //clear all data before calculating
+ m_accountListPast.clear();
+ m_accountList.clear();
+ m_accountTrendList.clear();
+
+ //set forecast accounts
+ setForecastAccountList();
+
+ switch(fMethod)
+ {
+ case eScheduled:
+ doFutureScheduledForecast();
+ calculateScheduledDailyBalances();
+ break;
+ case eHistoric:
+ pastTransactions();
+ calculateHistoricDailyBalances();
+ break;
+ default:
+ break;
+ }
+
+ //flag the forecast as done
+ m_forecastDone = true;
+}
+
+MyMoneyForecast::~MyMoneyForecast()
+{
+}
+
+void MyMoneyForecast::pastTransactions()
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyTransactionFilter filter;
+
+ filter.setDateFilter(historyStartDate(), historyEndDate());
+ filter.setReportAllSplits(false);
+
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();
+
+ //Check past transactions
+ for(; it_t != transactions.end(); ++it_t ) {
+ const QValueList<MyMoneySplit>& splits = (*it_t).splits();
+ QValueList<MyMoneySplit>::const_iterator it_s = splits.begin();
+ for(; it_s != splits.end(); ++it_s ) {
+ if(!(*it_s).shares().isZero()) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+
+ //workaround for stock accounts which have faulty opening dates
+ QDate openingDate;
+ if(acc.accountType() == MyMoneyAccount::Stock) {
+ MyMoneyAccount parentAccount = file->account(acc.parentAccountId());
+ openingDate = parentAccount.openingDate();
+ } else {
+ openingDate = acc.openingDate();
+ }
+
+ if(isForecastAccount(acc) //If it is one of the accounts we are checking, add the amount of the transaction
+ && ( (openingDate < (*it_t).postDate() && skipOpeningDate())
+ || !skipOpeningDate() ) ){ //don't take the opening day of the account to calculate balance
+ dailyBalances balance;
+ //FIXME deal with leap years
+ balance = m_accountListPast[acc.id()];
+ if(acc.accountType() == MyMoneyAccount::Income) {//if it is income, the balance is stored as negative number
+ balance[(*it_t).postDate()] += ((*it_s).shares() * MyMoneyMoney(-1, 1));
+ } else {
+ balance[(*it_t).postDate()] += (*it_s).shares();
+ }
+ // check if this is a new account for us
+ m_accountListPast[acc.id()] = balance;
+ }
+ }
+ }
+ }
+
+ //purge those accounts with no transactions on the period
+ if(isIncludingUnusedAccounts() == false)
+ purgeForecastAccountsList(m_accountListPast);
+
+ //calculate running sum
+ QMap<QString, QString>::Iterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+ m_accountListPast[acc.id()][historyStartDate().addDays(-1)] = file->balance(acc.id(), historyStartDate().addDays(-1));
+ for(QDate it_date = historyStartDate(); it_date <= historyEndDate(); ) {
+ m_accountListPast[acc.id()][it_date] += m_accountListPast[acc.id()][it_date.addDays(-1)]; //Running sum
+ it_date = it_date.addDays(1);
+ }
+ }
+
+ //adjust value of investments to deep currency
+ for ( it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n ) {
+ MyMoneyAccount acc = file->account ( *it_n );
+
+ if ( acc.isInvest() ) {
+ //get the id of the security for that account
+ MyMoneySecurity undersecurity = file->security ( acc.currencyId() );
+ if ( ! undersecurity.isCurrency() ) //only do it if the security is not an actual currency
+ {
+ MyMoneyMoney rate = MyMoneyMoney ( 1, 1 ); //set the default value
+ MyMoneyPrice price;
+
+ for ( QDate it_date = historyStartDate().addDays(-1) ; it_date <= historyEndDate();) {
+ //get the price for the tradingCurrency that day
+ price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), it_date );
+ if ( price.isValid() )
+ {
+ rate = price.rate ( undersecurity.tradingCurrency() );
+ }
+ //value is the amount of shares multiplied by the rate of the deep currency
+ m_accountListPast[acc.id() ][it_date] = m_accountListPast[acc.id() ][it_date] * rate;
+ it_date = it_date.addDays(1);
+ }
+ }
+ }
+ }
+}
+
+bool MyMoneyForecast::isForecastAccount(const MyMoneyAccount& acc)
+{
+ if(m_nameIdx.isEmpty())
+ {
+ setForecastAccountList();
+ }
+ QMap<QString, QString>::Iterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ if(*it_n == acc.id())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void MyMoneyForecast::calculateAccountTrendList()
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ int auxForecastTerms;
+ int totalWeight = 0;
+
+ //Calculate account trends
+ QMap<QString, QString>::Iterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+ m_accountTrendList[acc.id()][0] = MyMoneyMoney(0,1); // for today, the trend is 0
+
+ auxForecastTerms = forecastCycles();
+ if(skipOpeningDate()) {
+
+ QDate openingDate;
+ if(acc.accountType() == MyMoneyAccount::Stock) {
+ MyMoneyAccount parentAccount = file->account(acc.parentAccountId());
+ openingDate = parentAccount.openingDate();
+ } else {
+ openingDate = acc.openingDate();
+ }
+
+ if(openingDate > historyStartDate() ) { //if acc opened after forecast period
+ auxForecastTerms = 1 + ((openingDate.daysTo(historyEndDate()) + 1)/ accountsCycle()); // set forecastTerms to a lower value, to calculate only based on how long this account was opened
+ }
+ }
+
+ switch (historyMethod())
+ {
+ //moving average
+ case 0:
+ {
+ for(int t_day = 1; t_day <= accountsCycle(); t_day++)
+ m_accountTrendList[acc.id()][t_day] = accountMovingAverage(acc, t_day, auxForecastTerms); //moving average
+ break;
+ }
+ //weighted moving average
+ case 1:
+ {
+ //calculate total weight for moving average
+ if(auxForecastTerms == forecastCycles()) {
+ totalWeight = (auxForecastTerms * (auxForecastTerms + 1))/2; //totalWeight is the triangular number of auxForecastTerms
+ } else {
+ //if only taking a few periods, totalWeight is the sum of the weight for most recent periods
+ for(int i = 1, w = forecastCycles(); i <= auxForecastTerms; ++i, --w)
+ totalWeight += w;
+ }
+ for(int t_day = 1; t_day <= accountsCycle(); t_day++)
+ m_accountTrendList[acc.id()][t_day] = accountWeightedMovingAverage(acc, t_day, totalWeight);
+ break;
+ }
+ case 2:
+ {
+ //calculate mean term
+ MyMoneyMoney meanTerms = MyMoneyMoney((auxForecastTerms * (auxForecastTerms + 1))/2, 1) / MyMoneyMoney(auxForecastTerms, 1);
+
+ for(int t_day = 1; t_day <= accountsCycle(); t_day++)
+ m_accountTrendList[acc.id()][t_day] = accountLinearRegression(acc, t_day, auxForecastTerms, meanTerms);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+QValueList<MyMoneyAccount> MyMoneyForecast::forecastAccountList(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> accList;
+ //Get all accounts from the file and check if they are of the right type to calculate forecast
+ file->accountList(accList);
+ QValueList<MyMoneyAccount>::iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ) {
+ MyMoneyAccount acc = *accList_t;
+ if(acc.isClosed() //check the account is not closed
+ || (!acc.isAssetLiability()) ) {
+ //|| (acc.accountType() == MyMoneyAccount::Investment) ) {//check that it is not an Investment account and only include Stock accounts
+ accList.remove(accList_t); //remove the account if it is not of the correct type
+ accList_t = accList.begin();
+ } else {
+ ++accList_t;
+ }
+ }
+ return accList;
+}
+
+QValueList<MyMoneyAccount> MyMoneyForecast::accountList(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> accList;
+ QStringList emptyStringList;
+ //Get all accounts from the file and check if they are present
+ file->accountList(accList, emptyStringList, false);
+ QValueList<MyMoneyAccount>::iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ) {
+ MyMoneyAccount acc = *accList_t;
+ if(!isForecastAccount( acc ) ) {
+ accList.remove(accList_t); //remove the account
+ accList_t = accList.begin();
+ } else {
+ ++accList_t;
+ }
+ }
+ return accList;
+}
+
+MyMoneyMoney MyMoneyForecast::calculateAccountTrend(const MyMoneyAccount& acc, int trendDays)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyTransactionFilter filter;
+ MyMoneyMoney netIncome;
+ QDate startDate;
+ QDate openingDate = acc.openingDate();
+
+ //validate arguments
+ if(trendDays < 1)
+ {
+ throw new MYMONEYEXCEPTION("Illegal arguments when calling calculateAccountTrend. trendDays must be higher than 0");
+ }
+
+ //If it is a new account, we don't take into account the first day
+ //because it is usually a weird one and it would mess up the trend
+ if(openingDate.daysTo(QDate::currentDate())<trendDays){
+ startDate = (acc.openingDate()).addDays(1);
+ }
+ else {
+ startDate = QDate::currentDate().addDays(-trendDays);
+ }
+ //get all transactions for the period
+ filter.setDateFilter(startDate, QDate::currentDate());
+ if(acc.accountGroup() == MyMoneyAccount::Income
+ || acc.accountGroup() == MyMoneyAccount::Expense) {
+ filter.addCategory(acc.id());
+ } else {
+ filter.addAccount(acc.id());
+ }
+
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();
+
+ //add all transactions for that account
+ for(; it_t != transactions.end(); ++it_t ) {
+ const QValueList<MyMoneySplit>& splits = (*it_t).splits();
+ QValueList<MyMoneySplit>::const_iterator it_s = splits.begin();
+ for(; it_s != splits.end(); ++it_s ) {
+ if(!(*it_s).shares().isZero()) {
+ if(acc.id()==(*it_s).accountId()) netIncome += (*it_s).value();
+ }
+ }
+ }
+
+ //calculate trend of the account in the past period
+ MyMoneyMoney accTrend;
+
+ //don't take into account the first day of the account
+ if(openingDate.daysTo(QDate::currentDate())<trendDays) {
+ accTrend = netIncome/MyMoneyMoney(openingDate.daysTo(QDate::currentDate())-1,1);
+ } else {
+ accTrend = netIncome/MyMoneyMoney(trendDays,1);
+ }
+ return accTrend;
+}
+
+MyMoneyMoney MyMoneyForecast::accountMovingAverage(const MyMoneyAccount &acc, const int trendDay, const int forecastTerms)
+{
+ //Calculate a daily trend for the account based on the accounts of a given number of terms
+ //With a term of 1 month and 3 terms, it calculates the trend taking the transactions occurred at that day and the day before,
+ //for the last 3 months
+ MyMoneyMoney balanceVariation;
+
+ for(int it_terms = 0; (trendDay+(accountsCycle()*it_terms)) <= historyDays(); ++it_terms) //sum for each term
+ {
+ MyMoneyMoney balanceBefore = m_accountListPast[acc.id()][historyStartDate().addDays(trendDay+(accountsCycle()*it_terms)-2)]; //get balance for the day before
+ MyMoneyMoney balanceAfter = m_accountListPast[acc.id()][historyStartDate().addDays(trendDay+(accountsCycle()*it_terms)-1)];
+ balanceVariation += (balanceAfter - balanceBefore); //add the balance variation between days
+ }
+ //calculate average of the variations
+ return (balanceVariation / MyMoneyMoney(forecastTerms,1)).convert(10000);
+}
+
+MyMoneyMoney MyMoneyForecast::accountWeightedMovingAverage(const MyMoneyAccount &acc, const int trendDay, const int totalWeight)
+{
+ MyMoneyMoney balanceVariation;
+
+ for(int it_terms = 0, weight = 1; (trendDay+(accountsCycle()*it_terms)) <= historyDays(); ++it_terms, ++weight) //sum for each term multiplied by weight
+ {
+ MyMoneyMoney balanceBefore = m_accountListPast[acc.id()][historyStartDate().addDays(trendDay+(accountsCycle()*it_terms)-2)]; //get balance for the day before
+ MyMoneyMoney balanceAfter = m_accountListPast[acc.id()][historyStartDate().addDays(trendDay+(accountsCycle()*it_terms)-1)];
+ balanceVariation += ( (balanceAfter - balanceBefore) * MyMoneyMoney(weight, 1) ); //add the balance variation between days multiplied by its weight
+ }
+ //calculate average of the variations
+ return (balanceVariation / MyMoneyMoney(totalWeight, 1)).convert(10000);
+}
+
+MyMoneyMoney MyMoneyForecast::accountLinearRegression(const MyMoneyAccount &acc, const int trendDay, const int actualTerms, const MyMoneyMoney meanTerms)
+{
+ MyMoneyMoney meanBalance, totalBalance, totalTerms;
+ totalTerms = MyMoneyMoney(actualTerms, 1);
+
+ //calculate mean balance
+ for(int it_terms = forecastCycles() - actualTerms; (trendDay+(accountsCycle()*it_terms)) <= historyDays(); ++it_terms) //sum for each term
+ {
+ totalBalance += m_accountListPast[acc.id()][historyStartDate().addDays(trendDay+(accountsCycle()*it_terms)-1)];
+ }
+ meanBalance = totalBalance / MyMoneyMoney(actualTerms,1);
+ meanBalance = meanBalance.convert(10000);
+
+ //calculate b1
+
+ //first calculate x - mean x multiplied by y - mean y
+ MyMoneyMoney totalXY, totalSqX;
+ for(int it_terms = forecastCycles() - actualTerms, term = 1; (trendDay+(accountsCycle()*it_terms)) <= historyDays(); ++it_terms, ++term) //sum for each term
+ {
+ MyMoneyMoney balance = m_accountListPast[acc.id()][historyStartDate().addDays(trendDay+(accountsCycle()*it_terms)-1)];
+
+ MyMoneyMoney balMeanBal = balance - meanBalance;
+ MyMoneyMoney termMeanTerm = (MyMoneyMoney(term, 1) - meanTerms);
+
+ totalXY += (balMeanBal * termMeanTerm).convert(10000);
+
+ totalSqX += (termMeanTerm * termMeanTerm).convert(10000);
+ }
+ totalXY = (totalXY / MyMoneyMoney(actualTerms,1)).convert(10000);
+ totalSqX = (totalSqX / MyMoneyMoney(actualTerms,1)).convert(10000);
+
+ //check zero
+ if(totalSqX.isZero())
+ return MyMoneyMoney(0,1);
+
+ MyMoneyMoney linReg = (totalXY/totalSqX).convert(10000);
+
+ return linReg;
+}
+
+void MyMoneyForecast::calculateHistoricDailyBalances()
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ calculateAccountTrendList();
+
+ //Calculate account daily balances
+ QMap<QString, QString>::ConstIterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+
+ //set the starting balance of the account
+ setStartingBalance(acc);
+
+ switch(historyMethod()) {
+ case 0:
+ case 1:
+ {
+ for(QDate f_day = forecastStartDate(); f_day <= forecastEndDate(); ) {
+ for(int t_day = 1; t_day <= accountsCycle(); ++t_day) {
+ MyMoneyMoney balanceDayBefore = m_accountList[acc.id()][(f_day.addDays(-1))];//balance of the day before
+ MyMoneyMoney accountDailyTrend = m_accountTrendList[acc.id()][t_day]; //trend for that day
+ //balance of the day is the balance of the day before multiplied by the trend for the day
+ m_accountList[acc.id()][f_day] = balanceDayBefore;
+ m_accountList[acc.id()][f_day] += accountDailyTrend; //movement trend for that particular day
+ m_accountList[acc.id()][f_day] = m_accountList[acc.id()][f_day].convert(acc.fraction());
+ //m_accountList[acc.id()][f_day] += m_accountListPast[acc.id()][f_day.addDays(-historyDays())];
+ f_day = f_day.addDays(1);
+ }
+ }
+ }
+ break;
+ case 2:
+ {
+ QDate baseDate = QDate::currentDate().addDays(-accountsCycle());
+ for(int t_day = 1; t_day <= accountsCycle(); ++t_day) {
+ int f_day = 1;
+ QDate fDate = baseDate.addDays(accountsCycle()+1);
+ while (fDate <= forecastEndDate()) {
+
+ //the calculation is based on the balance for the last month, that is then multiplied by the trend
+ m_accountList[acc.id()][fDate] = m_accountListPast[acc.id()][baseDate] + (m_accountTrendList[acc.id()][t_day] * MyMoneyMoney(f_day,1));
+ m_accountList[acc.id()][fDate] = m_accountList[acc.id()][fDate].convert(acc.fraction());
+ ++f_day;
+ fDate = baseDate.addDays(accountsCycle() * f_day);
+ }
+ baseDate = baseDate.addDays(1);
+ }
+ }
+ }
+ }
+}
+
+MyMoneyMoney MyMoneyForecast::forecastBalance(const MyMoneyAccount& acc, QDate forecastDate)
+{
+
+ dailyBalances balance;
+ MyMoneyMoney MM_amount = MyMoneyMoney(0,1);
+
+ //Check if acc is not a forecast account, return 0
+ if ( !isForecastAccount ( acc ) )
+ {
+ return MM_amount;
+ }
+
+ balance = m_accountList[acc.id() ];
+ if ( balance.contains ( forecastDate ) )
+ { //if the date is not in the forecast, it returns 0
+ MM_amount = m_accountList[acc.id() ][forecastDate];
+ }
+ return MM_amount;
+}
+
+/**
+ * Returns the forecast balance trend for account @a acc for offset @p int
+ * offset is days from current date, inside forecast days.
+ * Returns 0 if offset not in range of forecast days.
+ */
+MyMoneyMoney MyMoneyForecast::forecastBalance (const MyMoneyAccount& acc, int offset )
+{
+ QDate forecastDate = QDate::currentDate().addDays(offset);
+ return forecastBalance(acc, forecastDate);
+}
+
+void MyMoneyForecast::doFutureScheduledForecast(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if(isIncludingFutureTransactions())
+ addFutureTransactions();
+
+ if(isIncludingScheduledTransactions())
+ addScheduledTransactions();
+
+ //do not show accounts with no transactions
+ if(!isIncludingUnusedAccounts())
+ purgeForecastAccountsList(m_accountList);
+
+ //adjust value of investments to deep currency
+ QMap<QString, QString>::ConstIterator it_n;
+ for ( it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n ) {
+ MyMoneyAccount acc = file->account ( *it_n );
+
+ if ( acc.isInvest() ) {
+ //get the id of the security for that account
+ MyMoneySecurity undersecurity = file->security ( acc.currencyId() );
+
+ //only do it if the security is not an actual currency
+ if ( ! undersecurity.isCurrency() )
+ {
+ //set the default value
+ MyMoneyMoney rate = MyMoneyMoney ( 1, 1 );
+ MyMoneyPrice price;
+
+ for (QDate it_day = QDate::currentDate(); it_day <= forecastEndDate(); ) {
+ //get the price for the tradingCurrency that day
+ price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), it_day );
+ if ( price.isValid() )
+ {
+ rate = price.rate ( undersecurity.tradingCurrency() );
+ }
+ //value is the amount of shares multiplied by the rate of the deep currency
+ m_accountList[acc.id() ][it_day] = m_accountList[acc.id() ][it_day] * rate;
+ it_day = it_day.addDays(1);
+ }
+ }
+ }
+ }
+}
+
+void MyMoneyForecast::addFutureTransactions(void)
+{
+ MyMoneyTransactionFilter filter;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // collect and process all transactions that have already been entered but
+ // are located in the future.
+ filter.setDateFilter(forecastStartDate(), forecastEndDate());
+ filter.setReportAllSplits(false);
+
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();
+
+ for(; it_t != transactions.end(); ++it_t ) {
+ const QValueList<MyMoneySplit>& splits = (*it_t).splits();
+ QValueList<MyMoneySplit>::const_iterator it_s = splits.begin();
+ for(; it_s != splits.end(); ++it_s ) {
+ if(!(*it_s).shares().isZero()) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ if(isForecastAccount(acc)) {
+ dailyBalances balance;
+ balance = m_accountList[acc.id()];
+ //if it is income, the balance is stored as negative number
+ if(acc.accountType() == MyMoneyAccount::Income) {
+ balance[(*it_t).postDate()] += ((*it_s).shares() * MyMoneyMoney(-1, 1));
+ } else {
+ balance[(*it_t).postDate()] += (*it_s).shares();
+ }
+ m_accountList[acc.id()] = balance;
+ }
+ }
+ }
+ }
+
+#if 0
+ QFile trcFile("forecast.csv");
+ trcFile.open(IO_WriteOnly);
+ QTextStream s(&trcFile);
+
+ {
+ s << "Already present transactions\n";
+ QMap<QString, dailyBalances>::Iterator it_a;
+ QMap<QString, QString>::ConstIterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+ it_a = m_accountList.find(*it_n);
+ s << "\"" << acc.name() << "\",";
+ for(int i = 0; i < 90; ++i) {
+ s << "\"" << (*it_a)[i].formatMoney("") << "\",";
+ }
+ s << "\n";
+ }
+}
+#endif
+
+}
+
+void MyMoneyForecast::addScheduledTransactions (void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // now process all the schedules that may have an impact
+ QValueList<MyMoneySchedule> schedule;
+
+ schedule = file->scheduleList("", MyMoneySchedule::TYPE_ANY, MyMoneySchedule::OCCUR_ANY, MyMoneySchedule::STYPE_ANY,
+ QDate::currentDate(), forecastEndDate());
+ if(schedule.count() > 0) {
+ QValueList<MyMoneySchedule>::Iterator it;
+ do {
+ qBubbleSort(schedule);
+ it = schedule.begin();
+ if(it == schedule.end())
+ break;
+
+ if((*it).isFinished()) {
+ schedule.erase(it);
+ continue;
+ }
+
+ QDate date = (*it).nextPayment((*it).lastPayment());
+ if(!date.isValid()) {
+ schedule.remove(it);
+ continue;
+ }
+
+ QDate nextDate = (*it).adjustedNextPayment((*it).lastPayment());
+ if (nextDate > forecastEndDate()) {
+ // We're done with this schedule, let's move on to the next
+ schedule.remove(it);
+ continue;
+ }
+
+ // found the next schedule. process it
+
+ MyMoneyAccount acc = (*it).account();
+
+ if(!acc.id().isEmpty()) {
+ try {
+ if(acc.accountType() != MyMoneyAccount::Investment) {
+ MyMoneyTransaction t = (*it).transaction();
+
+ // only process the entry, if it is still active
+ if(!(*it).isFinished() && nextDate != QDate()) {
+ // make sure we have all 'starting balances' so that the autocalc works
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ QMap<QString, MyMoneyMoney> balanceMap;
+
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s ) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ if(isForecastAccount(acc)) {
+ // collect all overdues on the first day
+ QDate forecastDate = nextDate;
+ if(QDate::currentDate() >= nextDate)
+ forecastDate = QDate::currentDate().addDays(1);
+
+ dailyBalances balance;
+ balance = m_accountList[acc.id()];
+ for(QDate f_day = QDate::currentDate(); f_day < forecastDate; ) {
+ balanceMap[acc.id()] += m_accountList[acc.id()][f_day];
+ f_day = f_day.addDays(1);
+ }
+ }
+ }
+
+ // take care of the autoCalc stuff
+ calculateAutoLoan(*it, t, balanceMap);
+
+ // now add the splits to the balances
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s ) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ if(isForecastAccount(acc)) {
+ dailyBalances balance;
+ balance = m_accountList[acc.id()];
+ //int offset = QDate::currentDate().daysTo(nextDate);
+ //if(offset <= 0) { // collect all overdues on the first day
+ // offset = 1;
+ //}
+ // collect all overdues on the first day
+ QDate forecastDate = nextDate;
+ if(QDate::currentDate() >= nextDate)
+ forecastDate = QDate::currentDate().addDays(1);
+
+ if(acc.accountType() == MyMoneyAccount::Income) {
+ balance[forecastDate] += ((*it_s).shares() * MyMoneyMoney(-1, 1));
+ } else {
+ balance[forecastDate] += (*it_s).shares();
+ }
+ m_accountList[acc.id()] = balance;
+ }
+ }
+ }
+ }
+ (*it).setLastPayment(date);
+
+ } catch(MyMoneyException* e) {
+ kdDebug(2) << __func__ << " Schedule " << (*it).id() << " (" << (*it).name() << "): " << e->what() << endl;
+
+ schedule.remove(it);
+ delete e;
+ }
+ } else {
+ // remove schedule from list
+ schedule.remove(it);
+ }
+ }
+ while(1);
+ }
+
+#if 0
+{
+ s << "\n\nAdded scheduled transactions\n";
+ QMap<QString, dailyBalances>::Iterator it_a;
+ QMap<QString, QString>::ConstIterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+ it_a = m_accountList.find(*it_n);
+ s << "\"" << acc.name() << "\",";
+ for(int i = 0; i < 90; ++i) {
+ s << "\"" << (*it_a)[i].formatMoney("") << "\",";
+ }
+ s << "\n";
+}
+}
+#endif
+}
+
+void MyMoneyForecast::calculateScheduledDailyBalances (void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Calculate account daily balances
+ QMap<QString, QString>::ConstIterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+
+ //set the starting balance of the account
+ setStartingBalance(acc);
+
+ for(QDate f_day = forecastStartDate(); f_day <= forecastEndDate(); ) {
+ MyMoneyMoney balanceDayBefore = m_accountList[acc.id()][(f_day.addDays(-1))];//balance of the day before
+ m_accountList[acc.id()][f_day] += balanceDayBefore; //running sum
+ f_day = f_day.addDays(1);
+ }
+ }
+
+
+}
+
+int MyMoneyForecast::daysToMinimumBalance(const MyMoneyAccount& acc)
+{
+ QString minimumBalance = acc.value("minBalanceAbsolute");
+ MyMoneyMoney minBalance = MyMoneyMoney(minimumBalance);
+ dailyBalances balance;
+
+ //Check if acc is not a forecast account, return -1
+ if(!isForecastAccount(acc)) {
+ return -1;
+ }
+
+ balance = m_accountList[acc.id()];
+
+ for(QDate it_day = QDate::currentDate() ; it_day <= forecastEndDate(); ) {
+ if(minBalance > balance[it_day]) {
+ return QDate::currentDate().daysTo(it_day);
+ }
+ it_day = it_day.addDays(1);
+ }
+ return -1;
+}
+
+int MyMoneyForecast::daysToZeroBalance(const MyMoneyAccount& acc)
+{
+ dailyBalances balance;
+
+ //Check if acc is not a forecast account, return -1
+ if(!isForecastAccount(acc)) {
+ return -2;
+ }
+
+ balance = m_accountList[acc.id()];
+
+ if (acc.accountGroup() == MyMoneyAccount::Asset) {
+ for (QDate it_day = QDate::currentDate() ; it_day <= forecastEndDate(); )
+ {
+ if ( balance[it_day] < MyMoneyMoney ( 0, 1 ) )
+ {
+ return QDate::currentDate().daysTo(it_day);
+ }
+ it_day = it_day.addDays(1);
+ }
+ } else if (acc.accountGroup() == MyMoneyAccount::Liability) {
+ for (QDate it_day = QDate::currentDate() ; it_day <= forecastEndDate(); )
+ {
+ if ( balance[it_day] > MyMoneyMoney ( 0, 1 ) )
+ {
+ return QDate::currentDate().daysTo(it_day);
+ }
+ it_day = it_day.addDays(1);
+ }
+ }
+ return -1;
+}
+
+void MyMoneyForecast::setForecastAccountList(void)
+{
+
+ //get forecast accounts
+ QValueList<MyMoneyAccount> accList;
+ accList = forecastAccountList();
+
+ QValueList<MyMoneyAccount>::const_iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ++accList_t ) {
+ MyMoneyAccount acc = *accList_t;
+ // check if this is a new account for us
+ if(m_nameIdx[acc.id()] != acc.id()) {
+ m_nameIdx[acc.id()] = acc.id();
+ }
+ }
+}
+
+MyMoneyMoney MyMoneyForecast::accountCycleVariation(const MyMoneyAccount& acc)
+{
+ MyMoneyMoney cycleVariation;
+
+ if (forecastMethod() == eHistoric) {
+ for(int t_day = 1; t_day <= accountsCycle() ; ++t_day) {
+ cycleVariation += m_accountTrendList[acc.id()][t_day];
+ }
+ }
+ return cycleVariation;
+}
+
+MyMoneyMoney MyMoneyForecast::accountTotalVariation(const MyMoneyAccount& acc)
+{
+ MyMoneyMoney totalVariation;
+
+ totalVariation = forecastBalance(acc, forecastEndDate()) - forecastBalance(acc, QDate::currentDate());
+ return totalVariation;
+}
+
+QValueList<QDate> MyMoneyForecast::accountMinimumBalanceDateList(const MyMoneyAccount& acc)
+{
+ QValueList<QDate> minBalanceList;
+ int daysToBeginDay;
+
+ daysToBeginDay = QDate::currentDate().daysTo(beginForecastDate());
+
+ for(int t_cycle = 0; ((t_cycle * accountsCycle()) + daysToBeginDay) < forecastDays() ; ++t_cycle) {
+ MyMoneyMoney minBalance = forecastBalance(acc, (t_cycle * accountsCycle() + daysToBeginDay));
+ QDate minDate = QDate::currentDate().addDays(t_cycle * accountsCycle() + daysToBeginDay);
+ for(int t_day = 1; t_day <= accountsCycle() ; ++t_day) {
+ if( minBalance > forecastBalance(acc, (t_cycle * accountsCycle()) + daysToBeginDay + t_day) ) {
+ minBalance = forecastBalance(acc, (t_cycle * accountsCycle()) + daysToBeginDay + t_day );
+ minDate = QDate::currentDate().addDays( (t_cycle * accountsCycle()) + daysToBeginDay + t_day);
+ }
+ }
+ minBalanceList.append(minDate);
+ }
+ return minBalanceList;
+}
+
+QValueList<QDate> MyMoneyForecast::accountMaximumBalanceDateList(const MyMoneyAccount& acc)
+{
+ QValueList<QDate> maxBalanceList;
+ int daysToBeginDay;
+
+ daysToBeginDay = QDate::currentDate().daysTo(beginForecastDate());
+
+ for(int t_cycle = 0; ((t_cycle * accountsCycle()) + daysToBeginDay) < forecastDays() ; ++t_cycle) {
+ MyMoneyMoney maxBalance = forecastBalance(acc, ((t_cycle * accountsCycle()) + daysToBeginDay));
+ QDate maxDate = QDate::currentDate().addDays((t_cycle * accountsCycle()) + daysToBeginDay);
+
+ for(int t_day = 0; t_day < accountsCycle() ; ++t_day) {
+ if( maxBalance < forecastBalance(acc, (t_cycle * accountsCycle()) + daysToBeginDay + t_day) ) {
+ maxBalance = forecastBalance(acc, (t_cycle * accountsCycle()) + daysToBeginDay + t_day );
+ maxDate = QDate::currentDate().addDays((t_cycle * accountsCycle()) + daysToBeginDay + t_day);
+ }
+ }
+ maxBalanceList.append(maxDate);
+ }
+ return maxBalanceList;
+}
+
+MyMoneyMoney MyMoneyForecast::accountAverageBalance(const MyMoneyAccount& acc)
+{
+ MyMoneyMoney totalBalance;
+ for(int f_day = 1; f_day <= forecastDays() ; ++f_day) {
+ totalBalance += forecastBalance(acc, f_day);
+ }
+ return totalBalance / MyMoneyMoney( forecastDays(), 1);
+}
+
+int MyMoneyForecast::calculateBeginForecastDay()
+{
+ int fDays = forecastDays();
+ int beginDay = beginForecastDay();
+ int accCycle = accountsCycle();
+ QDate beginDate;
+
+ //if 0, beginDate is current date and forecastDays remains unchanged
+ if(beginDay == 0) {
+ setBeginForecastDate(QDate::currentDate());
+ return fDays;
+ }
+
+ //adjust if beginDay more than days of current month
+ if(QDate::currentDate().daysInMonth() < beginDay)
+ beginDay = QDate::currentDate().daysInMonth();
+
+ //if beginDay still to come, calculate and return
+ if(QDate::currentDate().day() <= beginDay) {
+ beginDate = QDate( QDate::currentDate().year(), QDate::currentDate().month(), beginDay);
+ fDays += QDate::currentDate().daysTo(beginDate);
+ setBeginForecastDate(beginDate);
+ return fDays;
+ }
+
+ //adjust beginDay for next month
+ if(QDate::currentDate().addMonths(1).daysInMonth() < beginDay)
+ beginDay = QDate::currentDate().addMonths(1).daysInMonth();
+
+ //if beginDay of next month comes before 1 interval, use beginDay next month
+ if(QDate::currentDate().addDays(accCycle) >=
+ (QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1).addDays(beginDay-1) ) )
+ {
+ beginDate = QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1).addDays(beginDay-1);
+ fDays += QDate::currentDate().daysTo(beginDate);
+ }
+ else //add intervals to current beginDay and take the first after current date
+ {
+ beginDay = ((((QDate::currentDate().day()-beginDay)/accCycle) + 1) * accCycle) + beginDay;
+ beginDate = QDate::currentDate().addDays(beginDay - QDate::currentDate().day());
+ fDays += QDate::currentDate().daysTo(beginDate);
+ }
+
+ setBeginForecastDate(beginDate);
+ return fDays;
+}
+
+void MyMoneyForecast::purgeForecastAccountsList(QMap<QString, dailyBalances>& accountList)
+{
+ QMap<QString, QString>::Iterator it_n;
+ for ( it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ) {
+ if(!accountList.contains(*it_n)) {
+ m_nameIdx.remove(it_n);
+ it_n = m_nameIdx.begin();
+ } else
+ ++it_n;
+ }
+}
+
+void MyMoneyForecast::createBudget ( MyMoneyBudget& budget, QDate historyStart, QDate historyEnd, QDate budgetStart, QDate budgetEnd, const bool returnBudget )
+{
+ // clear all data except the id and name
+ QString name = budget.name();
+ budget = MyMoneyBudget(budget.id(), MyMoneyBudget());
+ budget.setName(name);
+
+ //check parameters
+ if ( historyStart > historyEnd ||
+ budgetStart > budgetEnd ||
+ budgetStart <= historyEnd )
+ {
+ throw new MYMONEYEXCEPTION ( "Illegal parameters when trying to create budget" );
+ }
+
+ //get forecast method
+ int fMethod = forecastMethod();
+
+ //set start date to 1st of month and end dates to last day of month, since we deal with full months in budget
+ historyStart = QDate ( historyStart.year(), historyStart.month(), 1 );
+ historyEnd = QDate ( historyEnd.year(), historyEnd.month(), historyEnd.daysInMonth() );
+ budgetStart = QDate ( budgetStart.year(), budgetStart.month(), 1 );
+ budgetEnd = QDate ( budgetEnd.year(), budgetEnd.month(), budgetEnd.daysInMonth() );
+
+ //set forecast parameters
+ setHistoryStartDate ( historyStart );
+ setHistoryEndDate ( historyEnd );
+ setForecastStartDate ( budgetStart );
+ setForecastEndDate ( budgetEnd );
+ setForecastDays ( budgetStart.daysTo ( budgetEnd ) + 1 );
+ if ( budgetStart.daysTo ( budgetEnd ) > historyStart.daysTo ( historyEnd ) ) { //if history period is shorter than budget, use that one as the trend length
+ setAccountsCycle ( historyStart.daysTo ( historyEnd ) ); //we set the accountsCycle to the base timeframe we will use to calculate the average (eg. 180 days, 365, etc)
+ } else { //if one timeframe is larger than the other, but not enough to be 1 time larger, we take the lowest value
+ setAccountsCycle ( budgetStart.daysTo ( budgetEnd ) );
+ }
+ setForecastCycles ( ( historyStart.daysTo ( historyEnd ) / accountsCycle() ) );
+ if ( forecastCycles() == 0 ) //the cycles must be at least 1
+ setForecastCycles ( 1 );
+
+ //do not skip opening date
+ setSkipOpeningDate ( false );
+
+ //clear and set accounts list we are going to use. Categories, in this case
+ m_nameIdx.clear();
+ setBudgetAccountList();
+
+ //calculate budget according to forecast method
+ switch(fMethod)
+ {
+ case eScheduled:
+ doFutureScheduledForecast();
+ calculateScheduledMonthlyBalances();
+ break;
+ case eHistoric:
+ pastTransactions(); //get all transactions for history period
+ calculateAccountTrendList();
+ calculateHistoricMonthlyBalances(); //add all balances of each month and put at the 1st day of each month
+ break;
+ default:
+ break;
+ }
+
+ //flag the forecast as done
+ m_forecastDone = true;
+
+ //only fill the budget if it is going to be used
+ if ( returnBudget ) {
+ //setup the budget itself
+ MyMoneyFile* file = MyMoneyFile::instance();
+ budget.setBudgetStart ( budgetStart );
+
+ //go through all the accounts and add them to budget
+ QMap<QString, QString>::ConstIterator it_nc;
+ for ( it_nc = m_nameIdx.begin(); it_nc != m_nameIdx.end(); ++it_nc ) {
+ MyMoneyAccount acc = file->account ( *it_nc );
+
+ MyMoneyBudget::AccountGroup budgetAcc;
+ budgetAcc.setId ( acc.id() );
+ budgetAcc.setBudgetLevel ( MyMoneyBudget::AccountGroup::eMonthByMonth );
+
+ for ( QDate f_date = forecastStartDate(); f_date <= forecastEndDate(); ) {
+ MyMoneyBudget::PeriodGroup period;
+
+ //add period to budget account
+ period.setStartDate ( f_date );
+ period.setAmount ( forecastBalance ( acc, f_date ) );
+ budgetAcc.addPeriod ( f_date, period );
+
+ //next month
+ f_date = f_date.addMonths ( 1 );
+ }
+ //add budget account to budget
+ budget.setAccount ( budgetAcc, acc.id() );
+ }
+ }
+}
+
+void MyMoneyForecast::setBudgetAccountList(void)
+{
+ //get budget accounts
+ QValueList<MyMoneyAccount> accList;
+ accList = budgetAccountList();
+
+ QValueList<MyMoneyAccount>::const_iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ++accList_t ) {
+ MyMoneyAccount acc = *accList_t;
+ // check if this is a new account for us
+ if(m_nameIdx[acc.id()] != acc.id()) {
+ m_nameIdx[acc.id()] = acc.id();
+ }
+ }
+}
+
+QValueList<MyMoneyAccount> MyMoneyForecast::budgetAccountList(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> accList;
+ QStringList emptyStringList;
+ //Get all accounts from the file and check if they are of the right type to calculate forecast
+ file->accountList(accList, emptyStringList, false);
+ QValueList<MyMoneyAccount>::iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ) {
+ MyMoneyAccount acc = *accList_t;
+ if(acc.isClosed() //check the account is not closed
+ || (!acc.isIncomeExpense()) ) {
+ accList.remove(accList_t); //remove the account if it is not of the correct type
+ accList_t = accList.begin();
+ } else {
+ ++accList_t;
+ }
+ }
+ return accList;
+}
+
+void MyMoneyForecast::calculateHistoricMonthlyBalances()
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Calculate account monthly balances
+ QMap<QString, QString>::ConstIterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+
+ for( QDate f_date = forecastStartDate(); f_date <= forecastEndDate(); ) {
+ for(int f_day = 1; f_day <= accountsCycle() && f_date <= forecastEndDate(); ++f_day) {
+ MyMoneyMoney accountDailyTrend = m_accountTrendList[acc.id()][f_day]; //trend for that day
+ //check for leap year
+ if(f_date.month() == 2 && f_date.day() == 29)
+ f_date = f_date.addDays(1); //skip 1 day
+ m_accountList[acc.id()][QDate(f_date.year(), f_date.month(), 1)] += accountDailyTrend; //movement trend for that particular day
+ f_date = f_date.addDays(1);
+ }
+ }
+ }
+}
+
+void MyMoneyForecast::calculateScheduledMonthlyBalances()
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+//Calculate account monthly balances
+ QMap<QString, QString>::ConstIterator it_n;
+ for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
+ MyMoneyAccount acc = file->account(*it_n);
+
+ for( QDate f_date = forecastStartDate(); f_date <= forecastEndDate(); f_date = f_date.addDays(1) ) {
+ //get the trend for the day
+ MyMoneyMoney accountDailyBalance = m_accountList[acc.id()][f_date];
+
+ //do not add if it is the beginning of the month
+ //otherwise we end up with duplicated values as reported by Marko Käning
+ if(f_date != QDate(f_date.year(), f_date.month(), 1) )
+ m_accountList[acc.id()][QDate(f_date.year(), f_date.month(), 1)] += accountDailyBalance;
+ }
+ }
+}
+
+void MyMoneyForecast::setStartingBalance(const MyMoneyAccount &acc)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Get current account balance
+ if ( acc.isInvest() ) { //investments require special treatment
+ //get the security id of that account
+ MyMoneySecurity undersecurity = file->security ( acc.currencyId() );
+
+ //only do it if the security is not an actual currency
+ if ( ! undersecurity.isCurrency() )
+ {
+ //set the default value
+ MyMoneyMoney rate = MyMoneyMoney ( 1, 1 );
+ //get te
+ MyMoneyPrice price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), QDate::currentDate() );
+ if ( price.isValid() )
+ {
+ rate = price.rate ( undersecurity.tradingCurrency() );
+ }
+ m_accountList[acc.id()][QDate::currentDate()] = file->balance(acc.id(), QDate::currentDate()) * rate;
+ }
+ } else {
+ m_accountList[acc.id()][QDate::currentDate()] = file->balance(acc.id(), QDate::currentDate());
+ }
+
+ //if the method is linear regression, we have to add the opening balance to m_accountListPast
+ if(forecastMethod() == eHistoric && historyMethod() == 2) {
+ //FIXME workaround for stock opening dates
+ QDate openingDate;
+ if(acc.accountType() == MyMoneyAccount::Stock) {
+ MyMoneyAccount parentAccount = file->account(acc.parentAccountId());
+ openingDate = parentAccount.openingDate();
+ } else {
+ openingDate = acc.openingDate();
+ }
+
+ //add opening balance only if it opened after the history start
+ if(openingDate >= historyStartDate()) {
+
+ MyMoneyMoney openingBalance;
+
+ openingBalance = file->balance(acc.id(), openingDate);
+
+ //calculate running sum
+ for(QDate it_date = openingDate; it_date <= historyEndDate(); it_date = it_date.addDays(1) ) {
+ //investments require special treatment
+ if ( acc.isInvest() ) {
+ //get the security id of that account
+ MyMoneySecurity undersecurity = file->security ( acc.currencyId() );
+
+ //only do it if the security is not an actual currency
+ if ( ! undersecurity.isCurrency() )
+ {
+ //set the default value
+ MyMoneyMoney rate = MyMoneyMoney ( 1, 1 );
+
+ //get the rate for that specific date
+ MyMoneyPrice price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), it_date );
+ if ( price.isValid() )
+ {
+ rate = price.rate ( undersecurity.tradingCurrency() );
+ }
+ m_accountListPast[acc.id()][it_date] += openingBalance * rate;
+ }
+ } else {
+ m_accountListPast[acc.id()][it_date] += openingBalance;
+ }
+ }
+ }
+ }
+}
+
+void MyMoneyForecast::calculateAutoLoan(const MyMoneySchedule& schedule, MyMoneyTransaction& transaction, const QMap<QString, MyMoneyMoney>& balances)
+{
+ if (schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT) {
+
+ //get amortization and interest autoCalc splits
+ MyMoneySplit amortizationSplit = transaction.amortizationSplit();
+ MyMoneySplit interestSplit = transaction.interestSplit();
+
+ if(!amortizationSplit.id().isEmpty() && !interestSplit.id().isEmpty()) {
+ MyMoneyAccountLoan acc(MyMoneyFile::instance()->account(amortizationSplit.accountId()));
+ MyMoneyFinancialCalculator calc;
+ QDate dueDate;
+
+ // FIXME: setup dueDate according to when the interest should be calculated
+ // current implementation: take the date of the next payment according to
+ // the schedule. If the calculation is based on the payment reception, and
+ // the payment is overdue then take the current date
+ dueDate = schedule.nextDueDate();
+ if(acc.interestCalculation() == MyMoneyAccountLoan::paymentReceived) {
+ if(dueDate < QDate::currentDate())
+ dueDate = QDate::currentDate();
+ }
+
+ // we need to calculate the balance at the time the payment is due
+
+ MyMoneyMoney balance;
+ if(balances.count() == 0)
+ balance = MyMoneyFile::instance()->balance(acc.id(), dueDate.addDays(-1));
+ else
+ balance = balances[acc.id()];
+
+ /*
+ QValueList<MyMoneyTransaction> list;
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ MyMoneySplit split;
+ MyMoneyTransactionFilter filter(acc.id());
+
+ filter.setDateFilter(QDate(), dueDate.addDays(-1));
+ list = MyMoneyFile::instance()->transactionList(filter);
+
+ for(it = list.begin(); it != list.end(); ++it) {
+ try {
+ split = (*it).splitByAccount(acc.id());
+ balance += split.value();
+
+ } catch(MyMoneyException *e) {
+ // account is not referenced within this transaction
+ delete e;
+ }
+ }
+ */
+
+ // FIXME: for now, we only support interest calculation at the end of the period
+ calc.setBep();
+ // FIXME: for now, we only support periodic compounding
+ calc.setDisc();
+
+ calc.setPF(MyMoneySchedule::eventsPerYear(schedule.occurence()));
+ MyMoneySchedule::occurenceE compoundingOccurence = static_cast<MyMoneySchedule::occurenceE>(acc.interestCompounding());
+ if(compoundingOccurence == MyMoneySchedule::OCCUR_ANY)
+ compoundingOccurence = schedule.occurence();
+
+ calc.setCF(MyMoneySchedule::eventsPerYear(compoundingOccurence));
+
+ calc.setPv(balance.toDouble());
+ calc.setIr(static_cast<FCALC_DOUBLE> (acc.interestRate(dueDate).abs().toDouble()));
+ calc.setPmt(acc.periodicPayment().toDouble());
+
+ MyMoneyMoney interest(calc.interestDue()), amortization;
+ interest = interest.abs(); // make sure it's positive for now
+ amortization = acc.periodicPayment() - interest;
+
+ if(acc.accountType() == MyMoneyAccount::AssetLoan) {
+ interest = -interest;
+ amortization = -amortization;
+ }
+
+ amortizationSplit.setShares(amortization);
+ interestSplit.setShares(interest);
+
+ // FIXME: for now we only assume loans to be in the currency of the transaction
+ amortizationSplit.setValue(amortization);
+ interestSplit.setValue(interest);
+
+ transaction.modifySplit(amortizationSplit);
+ transaction.modifySplit(interestSplit);
+ }
+ }
+}
+
diff --git a/kmymoney2/mymoney/mymoneyforecast.h b/kmymoney2/mymoney/mymoneyforecast.h
new file mode 100644
index 0000000..f69e596
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyforecast.h
@@ -0,0 +1,408 @@
+/***************************************************************************
+ mymoneyforecast.h
+ -------------------
+ begin : Wed May 30 2007
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYFORECAST_H
+#define MYMONEYFORECAST_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qmap.h>
+#include <qvaluelist.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/export.h>
+#include "mymoneybudget.h"
+
+/**
+ *
+ *
+ * @author Alvaro Soliverez <asoliverez@gmail.com>
+ */
+
+class MyMoneyForecast
+{
+public:
+ MyMoneyForecast();
+ ~MyMoneyForecast();
+
+ /**
+ * calculate forecast based on historic transactions
+ */
+ void doForecast();
+
+ /**
+ * Returns the list of accounts to be forecast.
+ */
+ QValueList<MyMoneyAccount> accountList(void);
+
+ /**
+ * Returns the balance trend for account @a acc based on a number of days @p forecastDays
+ * Collects and processes all transactions in the past for the
+ * same period of forecast and calculates the balance trend
+ */
+ static MyMoneyMoney calculateAccountTrend(const MyMoneyAccount& acc, int forecastDays);
+
+ /**
+ * Returns the forecast balance trend for account @a acc for day @p QDate
+ */
+ MyMoneyMoney forecastBalance(const MyMoneyAccount& acc, QDate forecastDate);
+
+ /**
+ * Returns the forecast balance trend for account @a acc for offset @p int
+ * offset is days from current date, inside forecast days.
+ * Returns 0 if offset not in range of forecast days.
+ */
+ MyMoneyMoney forecastBalance(const MyMoneyAccount& acc, int offset);
+
+ /**
+ * Returns true if an account @a acc is an account to be forecast
+ */
+ bool isForecastAccount(const MyMoneyAccount& acc);
+
+ /**
+ * returns the number of days when a given account is forecast to be below minimum balance
+ * returns -1 if it will not be below minimum balance in the forecast period
+ */
+ int daysToMinimumBalance(const MyMoneyAccount& acc);
+
+ /**
+ * returns the number of days when a given account is forecast to be below zero if it is an asset accounts
+ * or above zero if it is a liability account
+ * returns -1 if it will not happen in the forecast period
+ */
+ int daysToZeroBalance(const MyMoneyAccount& acc);
+
+ /**
+ * amount of variation of a given account in one cycle
+ */
+ MyMoneyMoney accountCycleVariation(const MyMoneyAccount& acc);
+
+ /**
+ * amount of variation of a given account for the whole forecast period
+ */
+ MyMoneyMoney accountTotalVariation(const MyMoneyAccount& acc);
+
+ /**
+ * returns a list of the dates where the account was on its lowest balance in each cycle
+ */
+ QValueList<QDate> accountMinimumBalanceDateList(const MyMoneyAccount& acc);
+
+ /**
+ * returns a list of the dates where the account was on its highest balance in each cycle
+ */
+ QValueList<QDate> accountMaximumBalanceDateList(const MyMoneyAccount& acc);
+
+ /**
+ * returns the average balance of the account within the forecast period
+ */
+ MyMoneyMoney accountAverageBalance(const MyMoneyAccount& acc);
+
+ /**
+ * creates a budget based on the history of a given timeframe
+ */
+ void createBudget(MyMoneyBudget& budget, QDate historyStart, QDate historyEnd, QDate budgetStart, QDate budgetEnd, const bool returnBudget);
+
+ /**
+ * number of days to go back in history to calculate forecast
+ */
+ int historyDays(void) const { return (m_historyStartDate.daysTo(m_historyEndDate) + 1); }
+
+ void setAccountsCycle(int accountsCycle) { m_accountsCycle = accountsCycle; }
+ void setForecastCycles(int forecastCycles) { m_forecastCycles = forecastCycles; }
+ void setForecastDays(int forecastDays) { m_forecastDays = forecastDays; }
+ void setBeginForecastDate(QDate beginForecastDate) { m_beginForecastDate = beginForecastDate; }
+ void setBeginForecastDay(int beginDay) { m_beginForecastDay = beginDay; }
+ void setForecastMethod(int forecastMethod) { m_forecastMethod = forecastMethod; }
+ void setHistoryStartDate(QDate historyStartDate) { m_historyStartDate = historyStartDate; }
+ void setHistoryEndDate(QDate historyEndDate) { m_historyEndDate = historyEndDate; }
+ void setHistoryStartDate(int daysToStartDate) { setHistoryStartDate(QDate::currentDate().addDays(-daysToStartDate)); }
+ void setHistoryEndDate(int daysToEndDate) { setHistoryEndDate(QDate::currentDate().addDays(-daysToEndDate)); }
+ void setForecastStartDate(QDate _startDate) { m_forecastStartDate = _startDate; }
+ void setForecastEndDate(QDate _endDate) { m_forecastEndDate = _endDate; }
+ void setSkipOpeningDate(bool _skip) { m_skipOpeningDate = _skip; }
+ void setHistoryMethod(int historyMethod) { m_historyMethod = historyMethod; }
+ void setIncludeUnusedAccounts(bool _bool) { m_includeUnusedAccounts = _bool; }
+ void setForecastDone(bool _bool) { m_forecastDone = _bool; }
+ void setIncludeFutureTransactions(bool _bool) { m_includeFutureTransactions = _bool; }
+ void setIncludeScheduledTransactions(bool _bool) { m_includeScheduledTransactions = _bool; }
+
+ int accountsCycle(void) const { return m_accountsCycle; }
+ int forecastCycles(void) const { return m_forecastCycles; }
+ int forecastDays(void) const { return m_forecastDays; }
+ QDate beginForecastDate(void) const { return m_beginForecastDate; }
+ int beginForecastDay(void) const { return m_beginForecastDay; }
+ int forecastMethod(void) const { return m_forecastMethod; }
+ QDate historyStartDate(void) const { return m_historyStartDate; }
+ QDate historyEndDate(void) const { return m_historyEndDate; }
+ QDate forecastStartDate(void) const { return m_forecastStartDate; }
+ QDate forecastEndDate(void) const { return m_forecastEndDate; }
+ bool skipOpeningDate(void) const { return m_skipOpeningDate; }
+ int historyMethod(void) const { return m_historyMethod; }
+ bool isIncludingUnusedAccounts(void) const { return m_includeUnusedAccounts; }
+ bool isForecastDone(void) const { return m_forecastDone; }
+ bool isIncludingFutureTransactions(void) const { return m_includeFutureTransactions; }
+ bool isIncludingScheduledTransactions(void) const { return m_includeScheduledTransactions; }
+
+ /**
+ * This method modifies a scheduled loan transaction such that all
+ * references to automatic calculated values are resolved to actual values.
+ *
+ * @param schedule const reference to the schedule the transaction is based on
+ * @param transaction reference to the transaction to be checked and modified
+ * @param balances QMap of (account-id,balance) pairs to be used as current balance
+ * for the calculation of interest. If map is empty, the engine
+ * will be interrogated for current balances.
+ */
+ static void calculateAutoLoan(const MyMoneySchedule& schedule, MyMoneyTransaction& transaction, const QMap<QString, MyMoneyMoney>& balances);
+
+private:
+
+ enum EForecastMethod {eScheduled = 0, eHistoric = 1 };
+
+ /**
+ * daily balances of an account
+ */
+ typedef QMap<QDate, MyMoneyMoney> dailyBalances;
+
+ /**
+ * map of trends of an account
+ */
+ typedef QMap<int, MyMoneyMoney> trendBalances;
+
+ /**
+ * Returns the list of accounts to be forecast. Only Asset and Liability are returned.
+ */
+ static QValueList<MyMoneyAccount> forecastAccountList(void);
+
+ /**
+ * Returns the list of accounts to create a budget. Only Income and Expenses are returned.
+ */
+ QValueList<MyMoneyAccount> budgetAccountList(void);
+
+ /**
+ * calculate daily forecast balance based on historic transactions
+ */
+ void calculateHistoricDailyBalances(void);
+
+ /**
+ * calculate monthly budget balance based on historic transactions
+ */
+ void calculateHistoricMonthlyBalances();
+
+ /**
+ * calculate monthly budget balance based on historic transactions
+ */
+ void calculateScheduledMonthlyBalances();
+
+ /**
+ * calculate forecast based on future and scheduled transactions
+ */
+ void doFutureScheduledForecast(void);
+
+ /**
+ * add future transactions to forecast
+ */
+ void addFutureTransactions(void);
+
+ /**
+ * add scheduled transactions to forecast
+ */
+ void addScheduledTransactions (void);
+
+ /**
+ * calculate daily forecast balance based on future and scheduled transactions
+ */
+ void calculateScheduledDailyBalances(void);
+
+ /**
+ * set the starting balance for an accounts
+ */
+ void setStartingBalance(const MyMoneyAccount& acc);
+
+ /**
+ * Returns the day moving average for the account @a acc based on the daily balances of a given number of @p forecastTerms
+ * It returns the moving average for a given @p trendDay of the forecastTerm
+ * With a term of 1 month and 3 terms, it calculates the trend taking the transactions occured
+ * at that day and the day before,for the last 3 months
+ */
+ MyMoneyMoney accountMovingAverage(const MyMoneyAccount& acc, const int trendDay, const int forecastTerms);
+
+ /**
+ * Returns the weighted moving average for a given @p trendDay
+ */
+ MyMoneyMoney accountWeightedMovingAverage(const MyMoneyAccount& acc, const int trendDay, const int totalWeight);
+
+ /**
+ * Returns the linear regression for a given @p trendDay
+ */
+ MyMoneyMoney accountLinearRegression(const MyMoneyAccount &acc, const int trendDay, const int totalWeight, const MyMoneyMoney meanTerms);
+
+ /**
+ * calculate daily forecast trend based on historic transactions
+ */
+ void calculateAccountTrendList(void);
+
+ /**
+ * set the internal list of accounts to be forecast
+ */
+ void setForecastAccountList(void);
+
+ /**
+ * set the internal list of accounts to create a budget
+ */
+ void setBudgetAccountList(void);
+
+ /**
+ * get past transactions for the accounts to be forecast
+ */
+ void pastTransactions(void);
+
+ /**
+ * calculate the day to start forecast and sets the begin date
+ * The quantity of forecast days will be counted from this date
+ * Depends on the values of begin day and accounts cycle
+ * The rules to calculate begin day are as follows:
+ * - if beginDay is 0, begin date is current date
+ * - if the day of the month set by beginDay has not passed, that will be used
+ * - if adding an account cycle to beginDay, will not go past the beginDay of next month,
+ * that date will be used, otherwise it will add account cycle to beginDay until it is past current date
+ * It returns the total amount of Forecast Days from current date.
+ */
+ int calculateBeginForecastDay();
+
+ /**
+ * remove accounts from the list if the accounts has no transactions in the forecast timeframe.
+ * Used for scheduled-forecast method.
+ */
+ void purgeForecastAccountsList(QMap<QString, dailyBalances>& accountList);
+
+ /**
+ * daily forecast balance of accounts
+ */
+ QMap<QString, dailyBalances> m_accountList;
+
+ /**
+ * daily past balance of accounts
+ */
+ QMap<QString, dailyBalances> m_accountListPast;
+
+ /**
+ * daily forecast trends of accounts
+ */
+ QMap<QString, trendBalances> m_accountTrendList;
+
+ /**
+ * list of forecast accounts
+ */
+ QMap<QString, QString> m_nameIdx;
+
+ /**
+ * cycle of accounts in days
+ */
+ int m_accountsCycle;
+
+ /**
+ * number of cycles to use in forecast
+ */
+ int m_forecastCycles;
+
+ /**
+ * number of days to forecast
+ */
+ int m_forecastDays;
+
+ /**
+ * date to start forecast
+ */
+ QDate m_beginForecastDate;
+
+ /**
+ * day to start forecast
+ */
+ int m_beginForecastDay;
+
+ /**
+ * forecast method
+ */
+ int m_forecastMethod;
+
+ /**
+ * history method
+ */
+ int m_historyMethod;
+
+ /**
+ * start date of history
+ */
+ QDate m_historyStartDate;
+
+ /**
+ * end date of history
+ */
+ QDate m_historyEndDate;
+
+ /**
+ * start date of forecast
+ */
+ QDate m_forecastStartDate;
+
+ /**
+ * end date of forecast
+ */
+ QDate m_forecastEndDate;
+
+ /**
+ * skip opening date when fetching transactions of an account
+ */
+ bool m_skipOpeningDate;
+
+ /**
+ * include accounts with no transactions in the forecast timeframe. default is false.
+ */
+ bool m_includeUnusedAccounts;
+
+ /**
+ * forecast already done
+ */
+ bool m_forecastDone;
+
+ /**
+ * include future transactions when doing a scheduled-based forecast
+ */
+ bool m_includeFutureTransactions;
+
+ /**
+ * include scheduled transactions when doing a scheduled-based forecast
+ */
+ bool m_includeScheduledTransactions;
+
+};
+
+#endif // MYMONEYFORECAST_H
+
diff --git a/kmymoney2/mymoney/mymoneyforecasttest.cpp b/kmymoney2/mymoney/mymoneyforecasttest.cpp
new file mode 100644
index 0000000..dbe96ac
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyforecasttest.cpp
@@ -0,0 +1,977 @@
+/***************************************************************************
+ mymoneyforecasttest.cpp
+ -------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyforecasttest.h"
+
+#include <iostream>
+#include <qvaluelist.h>
+
+#include "mymoneybudget.h"
+
+#include <kmymoney/mymoneyexception.h>
+
+#include "../kmymoneyglobalsettings.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+#include "../reports/reportstestcommon.h"
+
+
+using namespace test;
+
+MyMoneyForecastTest::MyMoneyForecastTest()
+{
+ this->moT1 = MyMoneyMoney(57,1);
+ this->moT2 = MyMoneyMoney(63,1);
+ this->moT3 = MyMoneyMoney(84,1);
+ this->moT4 = MyMoneyMoney(62,1);
+ this->moT5 = MyMoneyMoney(104,1);
+}
+
+
+void MyMoneyForecastTest::setUp () {
+
+ //all this has been taken from pivottabletest.cpp, by Thomas Baumgart and Ace Jones
+
+ storage = new MyMoneySeqAccessMgr;
+ file = MyMoneyFile::instance();
+ file->attachStorage(storage);
+
+ MyMoneyFileTransaction ft;
+ file->addCurrency(MyMoneySecurity("CAD", "Canadian Dollar", "C$"));
+ file->addCurrency(MyMoneySecurity("USD", "US Dollar", "$"));
+ file->addCurrency(MyMoneySecurity("JPY", "Japanese Yen", QChar(0x00A5), 100, 1));
+ file->addCurrency(MyMoneySecurity("GBP", "British Pound", "#"));
+ file->setBaseCurrency(file->currency("USD"));
+
+ MyMoneyPayee payeeTest("Test Payee");
+ file->addPayee(payeeTest);
+ MyMoneyPayee payeeTest2("Alvaro Soliverez");
+ file->addPayee(payeeTest2);
+
+ acAsset = (MyMoneyFile::instance()->asset().id());
+ acLiability = (MyMoneyFile::instance()->liability().id());
+ acExpense = (MyMoneyFile::instance()->expense().id());
+ acIncome = (MyMoneyFile::instance()->income().id());
+ acChecking = makeAccount(QString("Checking Account"),MyMoneyAccount::Checkings,moCheckingOpen,QDate(2004,5,15),acAsset, "USD");
+ acCredit = makeAccount(QString("Credit Card"),MyMoneyAccount::CreditCard,moCreditOpen,QDate(2004,7,15),acLiability, "USD");
+ acSolo = makeAccount(QString("Solo"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense, "USD");
+ acParent = makeAccount(QString("Parent"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense, "USD");
+ acChild = makeAccount(QString("Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent, "USD");
+ acForeign = makeAccount(QString("Foreign"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense, "USD");
+ acInvestment = makeAccount("Investment",MyMoneyAccount::Investment,moZero,QDate(2004,1,1),acAsset, "USD");
+
+ acSecondChild = makeAccount(QString("Second Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent, "USD");
+ acGrandChild1 = makeAccount(QString("Grand Child 1"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild, "USD");
+ acGrandChild2 = makeAccount(QString("Grand Child 2"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild, "USD");
+
+ //this account added to have an account to test opening date calculations
+ acCash = makeAccount(QString("Cash"),MyMoneyAccount::Cash,moCreditOpen,QDate::currentDate().addDays(-2),acAsset, "USD");
+
+
+ MyMoneyInstitution i("Bank of the World","","","","","","");
+ file->addInstitution(i);
+ inBank = i.id();
+ ft.commit();
+
+}
+
+void MyMoneyForecastTest::tearDown () {
+ file->detachStorage(storage);
+ delete storage;
+}
+
+void MyMoneyForecastTest::testEmptyConstructor() {
+ MyMoneyForecast a;
+ MyMoneyAccount b;
+
+ int f = a.forecastBalance(b, QDate::currentDate());
+
+ CPPUNIT_ASSERT(f == 0);
+ CPPUNIT_ASSERT(!a.isForecastAccount(b));
+ CPPUNIT_ASSERT(a.forecastBalance(b, QDate::currentDate()) == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(b) == -1);
+ CPPUNIT_ASSERT(a.daysToZeroBalance(b) == -2);
+ CPPUNIT_ASSERT(a.forecastDays() == KMyMoneyGlobalSettings::forecastDays());
+ CPPUNIT_ASSERT(a.accountsCycle() == KMyMoneyGlobalSettings::forecastAccountCycle());
+ CPPUNIT_ASSERT(a.forecastCycles() == KMyMoneyGlobalSettings::forecastCycles());
+ CPPUNIT_ASSERT(a.historyStartDate() == QDate::currentDate().addDays(-KMyMoneyGlobalSettings::forecastCycles()*KMyMoneyGlobalSettings::forecastAccountCycle()));
+ CPPUNIT_ASSERT(a.historyEndDate() == QDate::currentDate().addDays(-1));
+ CPPUNIT_ASSERT(a.historyDays() == KMyMoneyGlobalSettings::forecastAccountCycle() * KMyMoneyGlobalSettings::forecastCycles());
+}
+
+
+void MyMoneyForecastTest::testDoForecastInit() {
+ MyMoneyForecast a;
+
+ a.doForecast();
+ /*
+ //check the illegal argument validation
+ try {
+ KMyMoneyGlobalSettings::setForecastDays(-10);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e)
+ {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ KMyMoneyGlobalSettings::setForecastAccountCycle(-20);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ KMyMoneyGlobalSettings::setForecastCycles(-10);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ try {
+ KMyMoneyGlobalSettings::setForecastAccountCycle(0);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ KMyMoneyGlobalSettings::setForecastDays(0);
+ KMyMoneyGlobalSettings::setForecastCycles(0);
+ KMyMoneyGlobalSettings::setForecastAccountCycle(0);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_ASSERT("Unexpected exception");
+ }*/
+}
+
+//test that it forecasts correctly with transactions in the period of forecast
+void MyMoneyForecastTest::testDoForecast() {
+ //set up environment
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_credit = file->account(acCredit);
+
+ //test empty forecast
+ a.doForecast(); //this is just to check nothing goes wrong if forecast is run agains an empty template
+
+ //setup some transactions
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT1, acChecking, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -(this->moT2), acCredit, acParent);
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionTransfer, this->moT1, acCredit, acChecking);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.setHistoryMethod(0); //moving average
+ a.doForecast();
+
+ //checking didn't have balance variations, so the forecast should be equal to the current balance
+ MyMoneyMoney b_checking = file->balance(a_checking.id(), QDate::currentDate());
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(1))==b_checking);
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(2))==b_checking);
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(3))==b_checking);
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate())==b_checking);
+ //credit had a variation so the forecast should be different for each day
+ MyMoneyMoney b_credit = file->balance(a_credit.id(), QDate::currentDate());
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, 0) == b_credit);
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1)) == (b_credit+(moT2-moT1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2)) == (b_credit+((moT2-moT1)*2)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3)) == b_credit+((moT2-moT1)*3));
+
+ a.setHistoryMethod(1); //weighted moving average
+ a.doForecast();
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, 0) == b_credit);
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1)) == (b_credit+(moT2-moT1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2)) == (b_credit+((moT2-moT1)*2)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3)) == b_credit+((moT2-moT1)*3));
+
+ //insert transactions outside the forecast period. The calculation should be the same.
+ TransactionHelper t4( QDate::currentDate().addDays(-2), MyMoneySplit::ActionDeposit, -moT2, acCredit, acParent );
+ TransactionHelper t5( QDate::currentDate().addDays(-10), MyMoneySplit::ActionDeposit, -moT2, acCredit, acParent );
+ TransactionHelper t6( QDate::currentDate().addDays(-3), MyMoneySplit::ActionDeposit, -moT2, acCredit, acParent );
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.setHistoryMethod(0); //moving average
+ a.doForecast();
+ //check forecast
+ b_credit = file->balance(a_credit.id(), QDate::currentDate());
+ MyMoneyMoney b_credit_1_exp = (b_credit+((moT2-moT1)));
+ MyMoneyMoney b_credit_2 = a.forecastBalance(a_credit, QDate::currentDate().addDays(2));
+ MyMoneyMoney b_credit_2_exp = (b_credit+((moT2-moT1)*2));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate())==file->balance(a_credit.id(), QDate::currentDate()));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1))==b_credit+(moT2-moT1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2))==b_credit+((moT2-moT1)*2));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3))==b_credit+((moT2-moT1)*3));
+
+ //test weighted moving average
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(3);
+ a.setBeginForecastDay(0);
+ a.setHistoryMethod(1);
+ a.doForecast();
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, 0) == b_credit);
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1)) == (b_credit+(((moT2-moT1)*3+moT2*2+moT2)/MyMoneyMoney(6,1))));
+
+}
+
+void MyMoneyForecastTest::testGetForecastAccountList()
+{
+ MyMoneyForecast a;
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_parent = file->account(acParent);
+ QValueList<MyMoneyAccount> b;
+
+ b = a.forecastAccountList();
+ //check that it contains asset account, but not expense accounts
+ CPPUNIT_ASSERT(b.contains(a_checking));
+ CPPUNIT_ASSERT(!b.contains(a_parent));
+
+}
+
+void MyMoneyForecastTest::testCalculateAccountTrend()
+{
+ //set up environment
+ TransactionHelper t1( QDate::currentDate().addDays(-3), MyMoneySplit::ActionDeposit, -moT2, acChecking, acSolo );
+ MyMoneyAccount a_checking = file->account(acChecking);
+
+ //test invalid arguments
+
+ try {
+ MyMoneyForecast::calculateAccountTrend(a_checking, 0);
+ }
+ catch (MyMoneyException *e) {
+ CPPUNIT_ASSERT(e->what().compare("Illegal arguments when calling calculateAccountTrend. trendDays must be higher than 0") == 0);
+ delete e;
+ }
+ try {
+ MyMoneyForecast::calculateAccountTrend(a_checking, -10);
+ }
+ catch (MyMoneyException *e) {
+ CPPUNIT_ASSERT(e->what().compare("Illegal arguments when calling calculateAccountTrend. trendDays must be higher than 0") == 0);
+ delete e;
+ }
+
+ //test that it calculates correctly
+ CPPUNIT_ASSERT(MyMoneyForecast::calculateAccountTrend(a_checking ,3) == moT2/MyMoneyMoney(3,1));
+
+ //test that it works for all kind of accounts
+ MyMoneyAccount a_solo = file->account(acSolo);
+ MyMoneyMoney soloTrend = MyMoneyForecast::calculateAccountTrend(a_solo,3);
+ MyMoneyMoney soloTrendExp = -moT2/MyMoneyMoney(3,1);
+ CPPUNIT_ASSERT(MyMoneyForecast::calculateAccountTrend(a_solo,3) == -moT2/MyMoneyMoney(3,1));
+
+ //test that it does not take into account the transactions of the opening date of the account
+ MyMoneyAccount a_cash = file->account(acCash);
+ TransactionHelper t2( QDate::currentDate().addDays(-2), MyMoneySplit::ActionDeposit, moT2, acCash, acParent );
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, moT1, acCash, acParent );
+ CPPUNIT_ASSERT(MyMoneyForecast::calculateAccountTrend(a_cash,3) == -moT1);
+
+}
+
+void MyMoneyForecastTest::testGetForecastBalance()
+{
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT1, acChecking, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -(this->moT2), acCredit, acParent);
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionTransfer, this->moT1, acCredit, acChecking);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setHistoryMethod(0);
+ a.doForecast();
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_credit = file->account(acCredit);
+
+ //test invalid arguments
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(-1))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(-10))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, -1)==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, -100)==MyMoneyMoney(0,1));
+
+ //test a date outside the forecast days
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(4))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, 4)==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(10))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, 10)==MyMoneyMoney(0,1));
+
+ //test it returns valid results
+ MyMoneyMoney b_credit = file->balance(a_credit.id(), QDate::currentDate());
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate())==file->balance(a_credit.id(), QDate::currentDate()));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1))==b_credit+(moT2-moT1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2))==b_credit+((moT2-moT1)*2));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3))==b_credit+((moT2-moT1)*3));
+}
+
+void MyMoneyForecastTest::testIsForecastAccount()
+{
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_solo = file->account(acSolo);
+ MyMoneyAccount a_investment = file->account(acInvestment);
+
+ //test an invalid account
+ CPPUNIT_ASSERT(a.isForecastAccount(a_solo)==false);
+ CPPUNIT_ASSERT(a.isForecastAccount(a_investment)==true);
+
+ //test a valid account
+ CPPUNIT_ASSERT(a.isForecastAccount(a_checking)==true);
+
+}
+
+void MyMoneyForecastTest::testDoFutureScheduledForecast()
+{
+ //set up future transactions
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_cash = file->account(acCash);
+ TransactionHelper t1( QDate::currentDate().addDays(1), MyMoneySplit::ActionDeposit, -moT1, acCash, acParent );
+ TransactionHelper t2( QDate::currentDate().addDays(2), MyMoneySplit::ActionDeposit, -moT2, acCash, acParent );
+ TransactionHelper t3( QDate::currentDate().addDays(3), MyMoneySplit::ActionDeposit, -moT3, acCash, acParent );
+ TransactionHelper t4( QDate::currentDate().addDays(10), MyMoneySplit::ActionDeposit, -moT4, acCash, acParent );
+
+ a.setForecastMethod(0);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.doForecast();
+
+ MyMoneyMoney b_cash = file->balance(a_cash.id(), QDate::currentDate());
+
+ //test valid results
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate())==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(1))==b_cash+moT1);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(2))==b_cash+moT1+moT2);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(3))==b_cash+moT1+moT2+moT3);
+}
+
+void MyMoneyForecastTest::testScheduleForecast()
+{
+ //set up schedule environment for testing
+ MyMoneyAccount a_cash = file->account(acCash);
+ MyMoneyAccount a_parent = file->account(acParent);
+
+ MyMoneyFileTransaction ft;
+ MyMoneySchedule sch( "A Name",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate().addDays(1),
+ QDate(),
+ true,
+ true);
+
+ MyMoneyTransaction t;
+ t.setPostDate(QDate::currentDate().addDays(1));
+ t.setEntryDate(QDate::currentDate().addDays(1));
+ //t.setId("T000000000000000001");
+ t.setBankID("BID");
+ t.setMemo("Wohnung:Miete");
+ t.setCommodity("USD");
+ t.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(moT2);
+ s.setValue(moT2);
+ s.setAccountId(a_parent.id());
+ s.setBankID("SPID1");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ t.addSplit(s);
+
+ s.setPayeeId("P000001");
+ s.setShares(-moT2);
+ s.setValue(-moT2);
+ s.setAccountId(a_cash.id());
+ s.setBankID("SPID2");
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ s.clearId();
+ t.addSplit(s);
+
+ sch.setTransaction(t);
+
+ file->addSchedule(sch);
+ ft.commit();
+
+ MyMoneyFileTransaction ft3;
+ MyMoneySchedule sch3( "A Name1",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate().addDays(5),
+ QDate(),
+ true,
+ true);
+
+ //sch.setLastPayment(QDate::currentDate());
+ //sch.recordPayment(QDate::currentDate().addDays(1));
+ //sch.setId("SCH0001");
+
+ MyMoneyTransaction t3;
+ t3.setPostDate(QDate::currentDate().addDays(5));
+ t3.setEntryDate(QDate::currentDate().addDays(5));
+ //t.setId("T000000000000000001");
+ t3.setBankID("BID");
+ t3.setMemo("Wohnung:Miete");
+ t3.setCommodity("USD");
+ t3.setValue("key", "value");
+
+ MyMoneySplit s3;
+ s3.setPayeeId("P000001");
+ s3.setShares(moT2);
+ s3.setValue(moT2);
+ s3.setAccountId(a_parent.id());
+ s3.setBankID("SPID1");
+ s3.setReconcileFlag(MyMoneySplit::Reconciled);
+ t3.addSplit(s3);
+
+ s3.setPayeeId("P000001");
+ s3.setShares(-moT2);
+ s3.setValue(-moT2);
+ s3.setAccountId(a_cash.id());
+ s3.setBankID("SPID2");
+ s3.setReconcileFlag(MyMoneySplit::Cleared);
+ s3.clearId();
+ t3.addSplit(s3);
+
+ sch3.setTransaction(t3);
+
+ file->addSchedule(sch3);
+ ft3.commit();
+
+
+ MyMoneyFileTransaction ft2;
+ MyMoneySchedule sch2( "A Name2",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate().addDays(2),
+ QDate(),
+ true,
+ true);
+
+ //sch.setLastPayment(QDate::currentDate());
+ //sch.recordPayment(QDate::currentDate().addDays(1));
+ //sch.setId("SCH0001");
+
+ MyMoneyTransaction t2;
+ t2.setPostDate(QDate::currentDate().addDays(2));
+ t2.setEntryDate(QDate::currentDate().addDays(2));
+ //t.setId("T000000000000000001");
+ t2.setBankID("BID");
+ t2.setMemo("Wohnung:Miete");
+ t2.setCommodity("USD");
+ t2.setValue("key", "value");
+
+ MyMoneySplit s2;
+ s2.setPayeeId("P000001");
+ s2.setShares(moT1);
+ s2.setValue(moT1);
+ s2.setAccountId(a_parent.id());
+ s2.setBankID("SPID1");
+ s2.setReconcileFlag(MyMoneySplit::Reconciled);
+ t2.addSplit(s2);
+
+ s2.setPayeeId("P000001");
+ s2.setShares(-moT1);
+ s2.setValue(-moT1);
+ s2.setAccountId(a_cash.id());
+ s2.setBankID("SPID2");
+ s2.setReconcileFlag(MyMoneySplit::Cleared);
+ s2.clearId();
+ t2.addSplit(s2);
+
+ sch2.setTransaction(t2);
+
+ file->addSchedule(sch2);
+
+ ft2.commit();
+
+ //run forecast
+ MyMoneyForecast a;
+ a.setForecastMethod(0);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.doForecast();
+
+ //check result for single schedule
+ MyMoneyMoney b_cash = file->balance(a_cash.id(), QDate::currentDate());
+ MyMoneyMoney b_cash1 = a.forecastBalance(a_cash, QDate::currentDate().addDays(1));
+
+ //test valid results
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate())==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(1))==b_cash-moT2);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(2))==b_cash-moT2-moT1);
+}
+
+
+void MyMoneyForecastTest::testDaysToMinimumBalance()
+{
+ //setup environment
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_cash = file->account(acCash);
+ MyMoneyAccount a_credit = file->account(acCredit);
+ MyMoneyAccount a_parent = file->account(acParent);
+ a_cash.setValue("minBalanceAbsolute", "50");
+ a_credit.setValue("minBalanceAbsolute", "50");
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -moT1, acCash, acParent );
+ TransactionHelper t2( QDate::currentDate().addDays(2), MyMoneySplit::ActionDeposit, moT2, acCash, acParent );
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, -moT1, acCredit, acParent );
+ TransactionHelper t4( QDate::currentDate().addDays(4), MyMoneySplit::ActionWithdrawal, moT5, acCredit, acParent );
+
+ a.setForecastMethod(0);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ //test invalid arguments
+ MyMoneyAccount nullAcc;
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(nullAcc) == -1);
+
+ //test when not a forecast account
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(a_parent) == -1);
+
+ //test it warns when inside the forecast period
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(a_cash) == 2);
+
+ //test it does not warn when it will be outside of the forecast period
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(a_credit) == -1);
+}
+void MyMoneyForecastTest::testDaysToZeroBalance()
+{
+ //set up environment
+ MyMoneyAccount a_Solo = file->account(acSolo);
+ MyMoneyAccount a_Cash = file->account(acCash);
+ MyMoneyAccount a_Credit = file->account(acCredit);
+
+ //MyMoneyFileTransaction ft;
+ TransactionHelper t1( QDate::currentDate().addDays(2), MyMoneySplit::ActionWithdrawal, -moT1, acChecking, acSolo );
+ TransactionHelper t2( QDate::currentDate().addDays(2), MyMoneySplit::ActionTransfer, (moT5), acCash, acCredit );
+ TransactionHelper t3( QDate::currentDate().addDays(2), MyMoneySplit::ActionWithdrawal, (moT5*100), acCredit, acParent );
+ //ft.commit();
+
+ MyMoneyForecast a;
+ a.setForecastMethod(0);
+ a.setForecastDays(30);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(3);
+ a.doForecast();
+
+ //test invalid arguments
+ MyMoneyAccount nullAcc;
+ try {
+ a.daysToZeroBalance(nullAcc);
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ //test when not a forecast account
+ MyMoneyAccount a_solo = file->account(acSolo);
+ int iSolo = a.daysToZeroBalance(a_Solo);
+
+ CPPUNIT_ASSERT(iSolo == -2);
+
+ //test it warns when inside the forecast period
+
+ MyMoneyMoney fCash = a.forecastBalance(a_Cash, QDate::currentDate().addDays(2));
+
+ CPPUNIT_ASSERT(a.daysToZeroBalance(a_Cash) == 2);
+
+ //test it does not warn when it will be outside of the forecast period
+
+}
+
+void MyMoneyForecastTest::testSkipOpeningDate()
+{
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(1);
+ a.setHistoryMethod(0);
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test it has no variation because it skipped the variation of the opening date
+ MyMoneyMoney b_cash = file->balance(a_cash.id(), QDate::currentDate());
+ CPPUNIT_ASSERT(a.skipOpeningDate() == true);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate())==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(1))==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(2))==b_cash-moT2);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(3))==b_cash-moT2);
+}
+
+void MyMoneyForecastTest::testAccountMinimumBalanceDateList() {
+
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(6);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(3);
+ a.setHistoryMethod(0);
+ a.setBeginForecastDay(QDate::currentDate().addDays(1).day());
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test
+ QValueList<QDate> dateList;
+ dateList = a.accountMinimumBalanceDateList(a_cash);
+
+ QValueList<QDate>::iterator it = dateList.begin();
+
+ QDate minDate = *it;
+
+ CPPUNIT_ASSERT(minDate==QDate::currentDate().addDays(2));
+ it++;
+ minDate = *it;
+ CPPUNIT_ASSERT(minDate==QDate::currentDate().addDays(4));
+ it++;
+ minDate = *it;
+ CPPUNIT_ASSERT(minDate==QDate::currentDate().addDays(6));
+
+}
+
+void MyMoneyForecastTest::testAccountMaximumBalanceDateList() {
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(6);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(3);
+ a.setHistoryMethod(0);
+ a.setBeginForecastDay(QDate::currentDate().addDays(1).day());
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test
+ QValueList<QDate> dateList;
+ dateList = a.accountMaximumBalanceDateList(a_cash);
+
+ QValueList<QDate>::iterator it = dateList.begin();
+
+ QDate maxDate = *it;
+
+ CPPUNIT_ASSERT(maxDate==QDate::currentDate().addDays(1));
+ it++;
+ maxDate = *it;
+ CPPUNIT_ASSERT(maxDate==QDate::currentDate().addDays(3));
+ it++;
+ maxDate = *it;
+ CPPUNIT_ASSERT(maxDate==QDate::currentDate().addDays(5));
+
+
+}
+
+void MyMoneyForecastTest::testAccountAverageBalance() {
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test
+ MyMoneyMoney b_cash1 = a.forecastBalance(a_cash, QDate::currentDate().addDays(1));
+ MyMoneyMoney b_cash2 = a.forecastBalance(a_cash, QDate::currentDate().addDays(2));
+ MyMoneyMoney b_cash3 = a.forecastBalance(a_cash, QDate::currentDate().addDays(3));
+
+ MyMoneyMoney average = (b_cash1 + b_cash2 +b_cash3)/MyMoneyMoney(3,1);
+
+
+ CPPUNIT_ASSERT(a.accountAverageBalance(a_cash)==average);
+}
+
+void MyMoneyForecastTest::testBeginForecastDate() {
+ //set up environment
+ MyMoneyForecast a;
+ QDate beginDate;
+ int beginDay;
+
+ a.setForecastMethod(1);
+ a.setForecastDays(90);
+ a.setAccountsCycle(14);
+ a.setForecastCycles(3);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ //test when using old method without begin day
+ CPPUNIT_ASSERT(QDate::currentDate() == a.beginForecastDate());
+
+ //setup begin to last day of month
+ a.setBeginForecastDay(31);
+ beginDay = a.beginForecastDay();
+ a.doForecast();
+
+ //test
+ if(QDate::currentDate().day() < beginDay)
+ {
+ if(QDate::currentDate().daysInMonth() < beginDay)
+ beginDay = QDate::currentDate().daysInMonth();
+
+ beginDate = QDate(QDate::currentDate().year(), QDate::currentDate().month(), beginDay);
+
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+ }
+
+ //setup begin day to same date
+ a.setBeginForecastDay(QDate::currentDate().day());
+ beginDay = a.beginForecastDay();
+ a.doForecast();
+
+ CPPUNIT_ASSERT(QDate::currentDate() == a.beginForecastDate());
+
+ //setup to first day of month with small interval
+ a.setBeginForecastDay(1);
+ a.setAccountsCycle(1);
+ beginDay = a.beginForecastDay();
+ a.doForecast();
+
+ //test
+ if(QDate::currentDate() == a.beginForecastDate()) {
+ CPPUNIT_ASSERT(QDate::currentDate() == a.beginForecastDate());
+ } else {
+ beginDay = ((((QDate::currentDate().day() - beginDay)/a.accountsCycle()) + 1) * a.accountsCycle()) + beginDay;
+ if(beginDay > QDate::currentDate().daysInMonth())
+ beginDay = QDate::currentDate().daysInMonth();
+ beginDate = QDate(QDate::currentDate().year(), QDate::currentDate().month(), beginDay);
+ if(QDate::currentDate().day() == QDate::currentDate().daysInMonth() ) {
+ std::cout << std::endl << "testBeginForecastDate(): test of first day of month with small interval skipped because it is the last day of month" << std::endl;
+ } else {
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+ }
+ }
+
+ //setup to test when current date plus cycle equals begin day
+ a.setAccountsCycle(14);
+ beginDay = QDate::currentDate().addDays(14).day();
+ a.setBeginForecastDay(beginDay);
+ beginDate = QDate::currentDate().addDays(14);
+ a.doForecast();
+
+ //test
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+
+ //setup to test when the begin day will be next month
+ a.setBeginForecastDay(1);
+ a.setAccountsCycle(40);
+ a.doForecast();
+
+ beginDate = QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1);
+
+ //test
+ if(QDate::currentDate().day() > 1) {
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+ } else {
+ //test is not valid if today is 1st of month
+ std::cout << std::endl << "testBeginForecastDate(): test of first day of month skipped because current day is 1st of month" << std::endl;
+ }
+}
+
+ void MyMoneyForecastTest::testHistoryDays(void)
+{
+ MyMoneyForecast a;
+
+ CPPUNIT_ASSERT(a.historyStartDate() == QDate::currentDate().addDays(-a.forecastCycles()*a.accountsCycle()) );
+ CPPUNIT_ASSERT(a.historyEndDate() == QDate::currentDate().addDays(-1) );
+ CPPUNIT_ASSERT(a.historyDays() == a.forecastCycles()*a.accountsCycle());
+
+ a.setForecastMethod(1);
+ a.setForecastDays(90);
+ a.setAccountsCycle(14);
+ a.setForecastCycles(3);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ CPPUNIT_ASSERT(a.historyStartDate() == QDate::currentDate().addDays(-14*3) );
+ CPPUNIT_ASSERT(a.historyDays() == (14*3));
+ CPPUNIT_ASSERT(a.historyEndDate() == (QDate::currentDate().addDays(-1)) );
+}
+
+void MyMoneyForecastTest::testCreateBudget()
+{
+ //set up environment
+ MyMoneyForecast a;
+ MyMoneyForecast b;
+ MyMoneyBudget budget;
+
+ TransactionHelper t1( QDate(2005, 1, 3), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate(2005, 1, 15), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acParent);
+ TransactionHelper t3( QDate(2005, 1, 30), MyMoneySplit::ActionWithdrawal, this->moT3, acCash, acSolo);
+ TransactionHelper t4( QDate(2006, 1, 25), MyMoneySplit::ActionWithdrawal, this->moT4, acCash, acParent);
+ TransactionHelper t5( QDate(2005, 4, 3), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t6( QDate(2006, 5, 15), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acParent);
+ TransactionHelper t7( QDate(2005, 8, 3), MyMoneySplit::ActionWithdrawal, this->moT3, acCash, acSolo);
+ TransactionHelper t8( QDate(2006, 9, 15), MyMoneySplit::ActionWithdrawal, this->moT4, acCash, acParent);
+
+ a.setHistoryMethod(0);
+ a.setForecastMethod(1);
+ a.createBudget(budget, QDate(2005, 1, 1), QDate(2006, 12, 31), QDate(2007, 1, 1), QDate(2007, 12, 31), true);
+
+ //test
+ MyMoneyAccount a_solo = file->account(acSolo);
+ MyMoneyAccount a_parent = file->account(acParent);
+
+ //test it has no variation because it skipped the variation of the opening date
+ CPPUNIT_ASSERT(a.forecastBalance(a_solo, QDate(2007, 1, 1)) == ((moT1+moT3)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_parent, QDate(2007, 1, 1)) == ((moT2+moT4)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_solo, QDate(2007, 4, 1)) == ((moT1)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_parent, QDate(2007, 5, 1)) == ((moT2)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_solo, QDate(2007, 8, 1)) == ((moT3)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_parent, QDate(2007, 9, 1)) == ((moT4)/MyMoneyMoney(2, 1)));
+ //test the budget object returned by the method
+ CPPUNIT_ASSERT(budget.account(a_parent.id()).period(QDate(2007, 9, 1)).amount() == ((moT4)/MyMoneyMoney(2, 1)));
+
+ //setup test for a length lower than a year
+ b.setForecastMethod(1);
+ b.setHistoryMethod(0);
+ b.createBudget(budget, QDate(2005, 1, 1), QDate(2005, 6, 30), QDate(2007, 1, 1), QDate(2007, 6, 30), true);
+
+ //test
+ CPPUNIT_ASSERT(b.forecastBalance(a_solo, QDate(2007, 1, 1)) == (moT1+moT3));
+ CPPUNIT_ASSERT(b.forecastBalance(a_parent, QDate(2007, 1, 1)) == (moT2));
+ CPPUNIT_ASSERT(b.forecastBalance(a_solo, QDate(2007, 4, 1)) == (moT1));
+ CPPUNIT_ASSERT(b.forecastBalance(a_parent, QDate(2007, 5, 1)) == (MyMoneyMoney(0, 1)));
+
+ //set up schedule environment for testing
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ MyMoneyFileTransaction ft;
+ MyMoneySchedule sch( "A Name",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_MONTHLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate(),
+ QDate(),
+ true,
+ true);
+
+ MyMoneyTransaction t10;
+ t10.setPostDate(QDate::currentDate().addMonths(1));
+ t10.setEntryDate(QDate::currentDate().addMonths(1));
+ //t.setId("T000000000000000001");
+ t10.setBankID("BID");
+ t10.setMemo("Wohnung:Miete");
+ t10.setCommodity("USD");
+ t10.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(moT2);
+ s.setValue(moT2);
+ s.setAccountId(a_parent.id());
+ s.setBankID("SPID1");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ t10.addSplit(s);
+
+ s.setPayeeId("P000001");
+ s.setShares(-moT2);
+ s.setValue(-moT2);
+ s.setAccountId(a_cash.id());
+ s.setBankID("SPID2");
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ s.clearId();
+ t10.addSplit(s);
+
+ sch.setTransaction(t10);
+
+ file->addSchedule(sch);
+ ft.commit();
+
+ //run forecast
+ MyMoneyForecast c;
+ c.setForecastMethod(0);
+ c.setForecastCycles(1);
+ c.createBudget(budget, QDate::currentDate().addYears(-2), QDate::currentDate().addYears(-1), QDate::currentDate().addMonths(-2), QDate::currentDate().addMonths(6), true);
+
+ MyMoneyMoney c_parent = c.forecastBalance(a_parent, QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1) );
+
+ //test valid results
+ CPPUNIT_ASSERT(c.forecastBalance(a_parent, QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1) ) == (moT2));
+}
+
+void MyMoneyForecastTest::testLinearRegression() {
+ //set up environment
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_credit = file->account(acCredit);
+
+ //setup some transactions
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT1, acChecking, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -(this->moT2), acCredit, acParent);
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionTransfer, this->moT1, acCredit, acChecking);
+
+//TODO Add tests specific for linear regression
+
+
+}
diff --git a/kmymoney2/mymoney/mymoneyforecasttest.h b/kmymoney2/mymoney/mymoneyforecasttest.h
new file mode 100644
index 0000000..9ec2ae9
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyforecasttest.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ mymoneyforecasttest.h
+ -------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYFORECASTTEST_H__
+#define __MYMONEYFORECASTTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+#define private public
+#include "mymoneyforecast.h"
+#undef private
+
+
+class MyMoneyForecastTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE ( MyMoneyForecastTest );
+ CPPUNIT_TEST ( testEmptyConstructor );
+ CPPUNIT_TEST ( testDoForecast );
+ CPPUNIT_TEST ( testDoForecastInit );
+ CPPUNIT_TEST ( testGetForecastAccountList );
+ CPPUNIT_TEST ( testCalculateAccountTrend );
+ CPPUNIT_TEST ( testGetForecastBalance );
+ CPPUNIT_TEST ( testIsForecastAccount );
+ CPPUNIT_TEST ( testDoFutureScheduledForecast );
+ CPPUNIT_TEST ( testDaysToMinimumBalance );
+ CPPUNIT_TEST ( testDaysToZeroBalance );
+ CPPUNIT_TEST ( testScheduleForecast );
+ CPPUNIT_TEST ( testSkipOpeningDate );
+ CPPUNIT_TEST ( testAccountMinimumBalanceDateList );
+ CPPUNIT_TEST ( testAccountMaximumBalanceDateList );
+ CPPUNIT_TEST ( testAccountAverageBalance );
+ CPPUNIT_TEST ( testBeginForecastDate );
+ CPPUNIT_TEST ( testHistoryDays );
+ CPPUNIT_TEST ( testCreateBudget );
+ CPPUNIT_TEST ( testLinearRegression );
+ CPPUNIT_TEST_SUITE_END();
+
+
+
+ public:
+ MyMoneyForecastTest();
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testDoForecast();
+ void testDoForecastInit();
+ void testGetForecastAccountList();
+ void testCalculateAccountTrend();
+ void testGetForecastBalance();
+ void testIsForecastAccount();
+ void testDoFutureScheduledForecast();
+ void testDaysToMinimumBalance();
+ void testDaysToZeroBalance();
+ void testScheduleForecast();
+ void testSkipOpeningDate();
+ void testAccountMinimumBalanceDateList();
+ void testAccountMaximumBalanceDateList();
+ void testAccountAverageBalance();
+ void testBeginForecastDate();
+ void testHistoryDays();
+ void testCreateBudget();
+ void testLinearRegression();
+
+ protected:
+ MyMoneyForecast *m;
+
+ private:
+ MyMoneyAccount *account;
+
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyFile* file;
+
+ MyMoneyMoney moT1;
+ MyMoneyMoney moT2;
+ MyMoneyMoney moT3;
+ MyMoneyMoney moT4;
+ MyMoneyMoney moT5;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyinstitution.cpp b/kmymoney2/mymoney/mymoneyinstitution.cpp
new file mode 100644
index 0000000..9969ee7
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyinstitution.cpp
@@ -0,0 +1,182 @@
+/***************************************************************************
+ mymoneyinstitution.cpp
+ -------------------
+ copyright : (C) 2001 by Michael Edwardes,
+ 2002-2005 by Thomas Baumgart
+ email : mte@users.sourceforge.net,
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyinstitution.h"
+#include <kmymoney/mymoneyexception.h>
+
+MyMoneyInstitution::MyMoneyInstitution()
+{
+}
+
+MyMoneyInstitution::MyMoneyInstitution(const QString& id, const MyMoneyInstitution& right) :
+ MyMoneyObject(id)
+{
+ *this = right;
+ m_id = id;
+}
+
+MyMoneyInstitution::MyMoneyInstitution(const QString& name,
+ const QString& town,
+ const QString& street,
+ const QString& postcode,
+ const QString& telephone,
+ const QString& manager,
+ const QString& sortcode)
+{
+ clearId();
+ m_name = name;
+ m_town = town;
+ m_street = street;
+ m_postcode = postcode;
+ m_telephone = telephone;
+ m_manager = manager;
+ m_sortcode = sortcode;
+}
+
+MyMoneyInstitution::MyMoneyInstitution(const QDomElement& node) :
+ MyMoneyObject(node),
+ MyMoneyKeyValueContainer(node.elementsByTagName("KEYVALUEPAIRS").item(0).toElement())
+{
+ if("INSTITUTION" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not INSTITUTION");
+
+ m_sortcode = node.attribute("sortcode");
+ m_name = node.attribute("name");
+ m_manager = node.attribute("manager");
+
+ QDomNodeList nodeList = node.elementsByTagName("ADDRESS");
+ if(nodeList.count() == 0) {
+ QString msg = QString("No ADDRESS in institution %1").arg(m_name);
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ QDomElement addrNode = nodeList.item(0).toElement();
+ m_street = addrNode.attribute("street");
+ m_town = addrNode.attribute("city");
+ m_postcode = addrNode.attribute("zip");
+ m_telephone = addrNode.attribute("telephone");
+
+ m_accountList.clear();
+
+ nodeList = node.elementsByTagName("ACCOUNTIDS");
+ if(nodeList.count() > 0) {
+ nodeList = nodeList.item(0).toElement().elementsByTagName("ACCOUNTID");
+ for(unsigned int i = 0; i < nodeList.count(); ++i) {
+ m_accountList << nodeList.item(i).toElement().attribute("id");
+ }
+ }
+}
+
+MyMoneyInstitution::~MyMoneyInstitution()
+{
+}
+
+void MyMoneyInstitution::addAccountId(const QString& account)
+{
+ // only add this account if it is not yet presently in the list
+ if(m_accountList.contains(account) == 0)
+ m_accountList.append(account);
+}
+
+QString MyMoneyInstitution::removeAccountId(const QString& account)
+{
+ QStringList::Iterator pos;
+ QString rc;
+
+ pos = m_accountList.find(account);
+ if(pos != m_accountList.end()) {
+ m_accountList.remove(pos);
+ rc = account;
+ }
+ return rc;
+}
+
+bool MyMoneyInstitution::operator < (const MyMoneyInstitution& right) const
+{
+ return m_name < right.m_name;
+}
+
+bool MyMoneyInstitution::operator == (const MyMoneyInstitution& right) const
+{
+ if (MyMoneyObject::operator==(right) &&
+ ((m_name.length() == 0 && right.m_name.length() == 0) || (m_name == right.m_name)) &&
+ ((m_town.length() == 0 && right.m_town.length() == 0) || (m_town == right.m_town)) &&
+ ((m_street.length() == 0 && right.m_street.length() == 0) || (m_street == right.m_street)) &&
+ ((m_postcode.length() == 0 && right.m_postcode.length() == 0) || (m_postcode == right.m_postcode)) &&
+ ((m_telephone.length() == 0 && right.m_telephone.length() == 0) || (m_telephone == right.m_telephone)) &&
+ ((m_sortcode.length() == 0 && right.m_sortcode.length() == 0) || (m_sortcode == right.m_sortcode)) &&
+ ((m_manager.length() == 0 && right.m_manager.length() == 0) || (m_manager == right.m_manager)) &&
+ (m_accountList == right.m_accountList) ) {
+ return true;
+ } else
+ return false;
+}
+
+void MyMoneyInstitution::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("INSTITUTION");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("name", m_name);
+ el.setAttribute("manager", m_manager);
+ el.setAttribute("sortcode", m_sortcode);
+
+ QDomElement address = document.createElement("ADDRESS");
+ address.setAttribute("street", m_street);
+ address.setAttribute("city", m_town);
+ address.setAttribute("zip", m_postcode);
+ address.setAttribute("telephone", m_telephone);
+ el.appendChild(address);
+
+
+ QDomElement accounts = document.createElement("ACCOUNTIDS");
+ for(QStringList::ConstIterator it = accountList().begin(); it != accountList().end(); ++it){
+ QDomElement temp = document.createElement("ACCOUNTID");
+ temp.setAttribute("id", (*it));
+ accounts.appendChild(temp);
+ }
+ el.appendChild(accounts);
+
+ //Add in Key-Value Pairs for institutions.
+ MyMoneyKeyValueContainer::writeXML(document, el);
+
+ parent.appendChild(el);
+}
+
+bool MyMoneyInstitution::hasReferenceTo(const QString& /* id */) const
+{
+ bool rc = false;
+ return rc;
+}
+
+QPixmap MyMoneyInstitution::pixmap() const {
+ return QPixmap(KGlobal::dirs()->findResource("appdata",QString( "icons/hicolor/22x22/actions/%1.png").arg("bank")));
+}
+
diff --git a/kmymoney2/mymoney/mymoneyinstitution.h b/kmymoney2/mymoney/mymoneyinstitution.h
new file mode 100644
index 0000000..35b44c5
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyinstitution.h
@@ -0,0 +1,206 @@
+/***************************************************************************
+ mymoneyinstitution.h
+ -------------------
+ copyright : (C) 2002-2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYINSTITUTION_H
+#define MYMONEYINSTITUTION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qpixmap.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyutils.h"
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include <kmymoney/export.h>
+
+class MyMoneyFile;
+class MyMoneyMoney;
+
+/**
+ * This class represents a Bank contained within a MyMoneyFile object
+ *
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT MyMoneyInstitution : public MyMoneyObject, public MyMoneyKeyValueContainer
+{
+public:
+ /**
+ * This is the constructor for a new empty institution description
+ */
+ MyMoneyInstitution();
+
+ /**
+ * This is the constructor used by an application to fill the
+ * values required for a new institution. This object should then be
+ * passed to @see MyMoneyFile::addInstitution
+ */
+ MyMoneyInstitution(const QString& name,
+ const QString& city,
+ const QString& street,
+ const QString& postcode,
+ const QString& telephone,
+ const QString& manager,
+ const QString& sortCode);
+
+ /**
+ * This is the destructor for any MyMoneyInstitution object
+ */
+ ~MyMoneyInstitution();
+
+ /**
+ * This is the constructor for a new institution known to the current file
+ *
+ * @param id id assigned to the new institution object
+ * @param right institution definition
+ */
+ MyMoneyInstitution(const QString& id, const MyMoneyInstitution& right);
+
+ /**
+ * This is the constructor for an institution that is described by a
+ * QDomElement (e.g. from a file).
+ *
+ * @param el const reference to the QDomElement from which to
+ * create the object
+ */
+ MyMoneyInstitution(const QDomElement& el);
+
+ const QString& manager(void) const { return m_manager; }
+ const QString& name(void) const { return m_name; }
+ const QString& postcode(void) const { return m_postcode; }
+ const QString& street(void) const { return m_street; }
+ const QString& telephone(void) const { return m_telephone; }
+ const QString& town(void) const { return m_town; }
+ const QString& city(void) const { return town(); }
+ const QString& sortcode(void) const { return m_sortcode; }
+
+ void setManager(QString manager) { m_manager = manager; }
+ void setName(QString name) { m_name = name; }
+ void setPostcode(QString code) { m_postcode = code; }
+ void setStreet(QString street) { m_street = street; }
+ void setTelephone(QString tel) { m_telephone = tel; }
+ void setTown(QString town) { m_town = town; }
+ void setCity(QString town) { setTown(town); }
+ void setSortcode(QString code) { m_sortcode = code; }
+
+ /**
+ * This method adds the id of an account to the account list of
+ * this institution It is verified, that the account is only
+ * mentioned once.
+ *
+ * @param account id of the account to be added
+ */
+ void addAccountId(const QString& account);
+
+ /**
+ * This method deletes the id of an account from the account list
+ * of this institution
+ *
+ * @param account id of the account to be deleted
+ * @return id of account deleted, otherwise empty string
+ */
+ QString removeAccountId(const QString& account);
+
+ /**
+ * This method is used to return the set of accounts known to
+ * this institution
+ * return QStringList of account ids
+ */
+ const QStringList& accountList(void) const { return m_accountList; }
+
+ /**
+ * This method returns the number of accounts known to
+ * this institution
+ * @return number of accounts
+ */
+ unsigned int accountCount(void) const { return m_accountList.count(); }
+
+ bool operator == (const MyMoneyInstitution&) const;
+ bool operator < (const MyMoneyInstitution& right) const;
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ QPixmap pixmap() const;
+
+private:
+ // Bank 'fields'
+ /**
+ * This member variable keeps the name of the institution
+ */
+ QString m_name;
+
+ /**
+ * This member variable keeps the city of the institution
+ */
+ QString m_town;
+
+ /**
+ * This member variable keeps the street of the institution
+ */
+ QString m_street;
+
+ /**
+ * This member variable keeps the zip-code of the institution
+ */
+ QString m_postcode;
+
+ /**
+ * This member variable keeps the telephone number of the institution
+ */
+ QString m_telephone;
+
+ /**
+ * This member variable keeps the name of the representative of
+ * the institution
+ */
+ QString m_manager;
+
+ /**
+ * This member variable keeps the sort code of the institution.
+ * FIXME: I have no idea
+ * what it is good for. I keep it because it was in the old engine.
+ */
+ QString m_sortcode;
+
+ /**
+ * This member variable keeps the sorted list of the account ids
+ * available at this institution
+ */
+ QStringList m_accountList;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyinstitutiontest.cpp b/kmymoney2/mymoney/mymoneyinstitutiontest.cpp
new file mode 100644
index 0000000..ce707ec
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyinstitutiontest.cpp
@@ -0,0 +1,296 @@
+/***************************************************************************
+ mymoneyinstitutiontest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyinstitutiontest.h"
+#include <kmymoney/mymoneyexception.h>
+
+MyMoneyInstitutionTest::MyMoneyInstitutionTest()
+{
+}
+
+
+void MyMoneyInstitutionTest::setUp () {
+ m = new MyMoneyInstitution();
+ n = new MyMoneyInstitution("name", "town", "street", "postcode",
+ "telephone", "manager", "sortcode");
+}
+
+void MyMoneyInstitutionTest::tearDown () {
+ delete m;
+ delete n;
+}
+
+void MyMoneyInstitutionTest::testEmptyConstructor() {
+ CPPUNIT_ASSERT(m->id().isEmpty());
+ CPPUNIT_ASSERT(m->street().isEmpty());
+ CPPUNIT_ASSERT(m->town().isEmpty());
+ CPPUNIT_ASSERT(m->postcode().isEmpty());
+ CPPUNIT_ASSERT(m->telephone().isEmpty());
+ CPPUNIT_ASSERT(m->manager().isEmpty());
+
+ CPPUNIT_ASSERT(m->accountCount() == 0);
+}
+
+void MyMoneyInstitutionTest::testSetFunctions() {
+ m->setStreet("street");
+ m->setTown("town");
+ m->setPostcode("postcode");
+ m->setTelephone("telephone");
+ m->setManager("manager");
+ m->setName("name");
+
+ CPPUNIT_ASSERT(m->id().isEmpty());
+ CPPUNIT_ASSERT(m->street() == "street");
+ CPPUNIT_ASSERT(m->town() == "town");
+ CPPUNIT_ASSERT(m->postcode() == "postcode");
+ CPPUNIT_ASSERT(m->telephone() == "telephone");
+ CPPUNIT_ASSERT(m->manager() == "manager");
+ CPPUNIT_ASSERT(m->name() == "name");
+}
+
+void MyMoneyInstitutionTest::testNonemptyConstructor() {
+ CPPUNIT_ASSERT(n->id().isEmpty());
+ CPPUNIT_ASSERT(n->street() == "street");
+ CPPUNIT_ASSERT(n->town() == "town");
+ CPPUNIT_ASSERT(n->postcode() == "postcode");
+ CPPUNIT_ASSERT(n->telephone() == "telephone");
+ CPPUNIT_ASSERT(n->manager() == "manager");
+ CPPUNIT_ASSERT(n->name() == "name");
+ CPPUNIT_ASSERT(n->sortcode() == "sortcode");
+}
+
+void MyMoneyInstitutionTest::testCopyConstructor() {
+ MyMoneyInstitution* n1 = new MyMoneyInstitution("GUID1", *n);
+ MyMoneyInstitution n2(*n1);
+
+ CPPUNIT_ASSERT(*n1 == n2);
+
+ delete n1;
+}
+
+void MyMoneyInstitutionTest::testMyMoneyFileConstructor() {
+ MyMoneyInstitution *t = new MyMoneyInstitution("GUID", *n);
+
+ CPPUNIT_ASSERT(t->id() == "GUID");
+
+ CPPUNIT_ASSERT(t->street() == "street");
+ CPPUNIT_ASSERT(t->town() == "town");
+ CPPUNIT_ASSERT(t->postcode() == "postcode");
+ CPPUNIT_ASSERT(t->telephone() == "telephone");
+ CPPUNIT_ASSERT(t->manager() == "manager");
+ CPPUNIT_ASSERT(t->name() == "name");
+ CPPUNIT_ASSERT(t->sortcode() == "sortcode");
+
+ delete t;
+}
+
+void MyMoneyInstitutionTest::testEquality () {
+ MyMoneyInstitution t("name", "town", "street", "postcode",
+ "telephone", "manager", "sortcode");
+
+ CPPUNIT_ASSERT(t == *n);
+ t.setStreet("x");
+ CPPUNIT_ASSERT(!(t == *n));
+ t.setStreet("street");
+ CPPUNIT_ASSERT(t == *n);
+ t.setName("x");
+ CPPUNIT_ASSERT(!(t == *n));
+ t.setName("name");
+ CPPUNIT_ASSERT(t == *n);
+ t.setTown("x");
+ CPPUNIT_ASSERT(!(t == *n));
+ t.setTown("town");
+ CPPUNIT_ASSERT(t == *n);
+ t.setPostcode("x");
+ CPPUNIT_ASSERT(!(t == *n));
+ t.setPostcode("postcode");
+ CPPUNIT_ASSERT(t == *n);
+ t.setTelephone("x");
+ CPPUNIT_ASSERT(!(t == *n));
+ t.setTelephone("telephone");
+ CPPUNIT_ASSERT(t == *n);
+ t.setManager("x");
+ CPPUNIT_ASSERT(!(t == *n));
+ t.setManager("manager");
+ CPPUNIT_ASSERT(t == *n);
+
+ MyMoneyInstitution* n1 = new MyMoneyInstitution("GUID1", *n);
+ MyMoneyInstitution* n2 = new MyMoneyInstitution("GUID1", *n);
+
+ n1->addAccountId("A000001");
+ n2->addAccountId("A000001");
+
+ CPPUNIT_ASSERT(*n1 == *n2);
+
+ delete n1;
+ delete n2;
+}
+
+void MyMoneyInstitutionTest::testInequality () {
+ MyMoneyInstitution* n1 = new MyMoneyInstitution("GUID0", *n);
+ MyMoneyInstitution* n2 = new MyMoneyInstitution("GUID1", *n);
+ MyMoneyInstitution* n3 = new MyMoneyInstitution("GUID2", *n);
+ MyMoneyInstitution* n4 = new MyMoneyInstitution("GUID2", *n);
+
+ CPPUNIT_ASSERT(!(*n1 == *n2));
+ CPPUNIT_ASSERT(!(*n1 == *n3));
+ CPPUNIT_ASSERT(*n3 == *n4);
+
+ n3->addAccountId("A000001");
+ n4->addAccountId("A000002");
+ CPPUNIT_ASSERT(!(*n3 == *n4));
+
+ delete n1;
+ delete n2;
+ delete n3;
+ delete n4;
+}
+
+void MyMoneyInstitutionTest::testAccountIDList () {
+ MyMoneyInstitution institution;
+ QStringList list;
+ QString id;
+
+ // list must be empty
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 0);
+
+ // add one account
+ institution.addAccountId("A000002");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+
+ // adding same account shouldn't make a difference
+ institution.addAccountId("A000002");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+
+ // now add another account
+ institution.addAccountId("A000001");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+ CPPUNIT_ASSERT(list.contains("A000001") == 1);
+
+ id = institution.removeAccountId("A000001");
+ CPPUNIT_ASSERT(id == "A000001");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+
+}
+
+void MyMoneyInstitutionTest::testWriteXML() {
+ MyMoneyKeyValueContainer kvp;
+
+ n->addAccountId("A000001");
+ n->addAccountId("A000003");
+ n->setValue(QString("key"), "value");
+
+ QDomDocument doc("TEST");
+ QDomElement el = doc.createElement("INSTITUTION-CONTAINER");
+ doc.appendChild(el);
+
+ MyMoneyInstitution i("I00001", *n);
+
+ i.writeXML(doc, el);
+
+ QString ref = QString(
+ "<!DOCTYPE TEST>\n"
+ "<INSTITUTION-CONTAINER>\n"
+ " <INSTITUTION sortcode=\"sortcode\" id=\"I00001\" manager=\"manager\" name=\"name\" >\n"
+ " <ADDRESS street=\"street\" zip=\"postcode\" city=\"town\" telephone=\"telephone\" />\n"
+ " <ACCOUNTIDS>\n"
+ " <ACCOUNTID id=\"A000001\" />\n"
+ " <ACCOUNTID id=\"A000003\" />\n"
+ " </ACCOUNTIDS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </INSTITUTION>\n"
+ "</INSTITUTION-CONTAINER>\n");
+
+ CPPUNIT_ASSERT(doc.toString() == ref);
+}
+
+void MyMoneyInstitutionTest::testReadXML() {
+ MyMoneyInstitution i;
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<INSTITUTION-CONTAINER>\n"
+ " <INSTITUTION sortcode=\"sortcode\" id=\"I00001\" manager=\"manager\" name=\"name\" >\n"
+ " <ADDRESS street=\"street\" zip=\"postcode\" city=\"town\" telephone=\"telephone\" />\n"
+ " <ACCOUNTIDS>\n"
+ " <ACCOUNTID id=\"A000001\" />\n"
+ " <ACCOUNTID id=\"A000003\" />\n"
+ " </ACCOUNTIDS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </INSTITUTION>\n"
+ "</INSTITUTION-CONTAINER>\n");
+
+ QString ref_false = QString(
+ "<!DOCTYPE TEST>\n"
+ "<INSTITUTION-CONTAINER>\n"
+ " <KINSTITUTION sortcode=\"sortcode\" id=\"I00001\" manager=\"manager\" name=\"name\" >\n"
+ " <ADDRESS street=\"street\" zip=\"postcode\" city=\"town\" telephone=\"telephone\" />\n"
+ " <ACCOUNTIDS>\n"
+ " <ACCOUNTID id=\"A000001\" />\n"
+ " <ACCOUNTID id=\"A000003\" />\n"
+ " </ACCOUNTIDS>\n"
+ " </KINSTITUTION>\n"
+ "</INSTITUTION-CONTAINER>\n");
+
+ QDomDocument doc;
+ QDomElement node;
+
+ doc.setContent(ref_false);
+ node = doc.documentElement().firstChild().toElement();
+ try {
+ i = MyMoneyInstitution(node);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ i.addAccountId("TEST");
+
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+ try {
+ QStringList alist;
+ alist << "A000001" << "A000003";
+ i = MyMoneyInstitution(node);
+
+ CPPUNIT_ASSERT(i.sortcode() == "sortcode");
+ CPPUNIT_ASSERT(i.id() == "I00001");
+ CPPUNIT_ASSERT(i.manager() == "manager");
+ CPPUNIT_ASSERT(i.name() == "name");
+ CPPUNIT_ASSERT(i.street() == "street");
+ CPPUNIT_ASSERT(i.postcode() == "postcode");
+ CPPUNIT_ASSERT(i.city() == "town");
+ CPPUNIT_ASSERT(i.telephone() == "telephone");
+ CPPUNIT_ASSERT(i.accountList() == alist);
+ CPPUNIT_ASSERT(i.value(QString("key")) == "value");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
diff --git a/kmymoney2/mymoney/mymoneyinstitutiontest.h b/kmymoney2/mymoney/mymoneyinstitutiontest.h
new file mode 100644
index 0000000..8954d6a
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyinstitutiontest.h
@@ -0,0 +1,61 @@
+
+/***************************************************************************
+ mymoneyinstitutiontest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYINSTITUTIONTEST_H__
+#define __MYMONEYINSTITUTIONTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneyinstitution.h"
+#undef private
+
+class MyMoneyInstitutionTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyInstitutionTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testNonemptyConstructor);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testMyMoneyFileConstructor);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST(testInequality);
+ CPPUNIT_TEST(testAccountIDList);
+ CPPUNIT_TEST(testWriteXML);
+ CPPUNIT_TEST(testReadXML);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyInstitution *m, *n;
+
+public:
+ MyMoneyInstitutionTest();
+
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testSetFunctions();
+ void testNonemptyConstructor();
+ void testCopyConstructor();
+ void testMyMoneyFileConstructor();
+ void testEquality ();
+ void testInequality ();
+ void testAccountIDList ();
+ void testWriteXML();
+ void testReadXML();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyinvesttransaction.cpp b/kmymoney2/mymoney/mymoneyinvesttransaction.cpp
new file mode 100644
index 0000000..a7cf082
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyinvesttransaction.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ mymoneyinvesttransaction.cpp - description
+ -------------------
+ begin : Sun Feb 3 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyinvesttransaction.h"
+
+#if 0
+MyMoneyInvestTransaction::MyMoneyInvestTransaction(MyMoneyAccount *parent, const long id, transactionMethod method, const QString& number, const QString& memo,
+ const MyMoneyMoney& amount, const QDate& date, const QString& categoryMajor, const QString& categoryMinor, const QString& atmName,
+ const QString& fromTo, const QString& bankFrom, const QString& bankTo, stateE state)
+ : MyMoneyTransaction(parent, id, method, number, memo, amount, date, categoryMajor, categoryMinor, atmName, fromTo, bankFrom, bankTo, state)
+{
+
+}
+
+MyMoneyInvestTransaction::MyMoneyInvestTransaction()
+{
+}
+
+MyMoneyInvestTransaction::~MyMoneyInvestTransaction()
+{
+}
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyinvesttransaction.h b/kmymoney2/mymoney/mymoneyinvesttransaction.h
new file mode 100644
index 0000000..59f5d5b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyinvesttransaction.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ mymoneyinvesttransaction.h - description
+ -------------------
+ begin : Sun Feb 3 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYINVESTTRANSACTION_H
+#define MYMONEYINVESTTRANSACTION_H
+
+#include "mymoneytransaction.h"
+
+#if 0
+/**
+ *@author Kevin Tambascio
+ */
+
+class MyMoneyInvestTransaction : public MyMoneyTransaction {
+public:
+ MyMoneyInvestTransaction();
+ MyMoneyInvestTransaction(MyMoneyAccount *parent, const long id, transactionMethod method, const QString& number, const QString& memo,
+ const MyMoneyMoney& amount, const QDate& date, const QString& categoryMajor, const QString& categoryMinor, const QString& atmName,
+ const QString& fromTo, const QString& bankFrom, const QString& bankTo, stateE state);
+ ~MyMoneyInvestTransaction();
+};
+#endif
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneykeyvaluecontainer.cpp b/kmymoney2/mymoney/mymoneykeyvaluecontainer.cpp
new file mode 100644
index 0000000..4df855b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneykeyvaluecontainer.cpp
@@ -0,0 +1,120 @@
+/***************************************************************************
+ mymoneykeyvaluecontainer.cpp
+ -------------------
+ begin : Sun Nov 10 2002
+ copyright : (C) 2002-2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include <kmymoney/mymoneyexception.h>
+
+MyMoneyKeyValueContainer::MyMoneyKeyValueContainer()
+{
+}
+
+MyMoneyKeyValueContainer::MyMoneyKeyValueContainer(const QDomElement& node)
+{
+ if(!node.isNull()) {
+ if("KEYVALUEPAIRS" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not KEYVALUEPAIRS");
+
+ m_kvp.clear();
+
+ QDomNodeList nodeList = node.elementsByTagName("PAIR");
+ for(unsigned int i = 0; i < nodeList.count(); ++i) {
+ const QDomElement& el(nodeList.item(i).toElement());
+ m_kvp[el.attribute("key")] = el.attribute("value");
+ }
+ }
+}
+
+MyMoneyKeyValueContainer::~MyMoneyKeyValueContainer()
+{
+}
+
+const QString& MyMoneyKeyValueContainer::value(const QString& key) const
+{
+ QMap<QString, QString>::ConstIterator it;
+
+ it = m_kvp.find(key);
+ if(it != m_kvp.end())
+ return (*it);
+ return QString::null;
+}
+
+void MyMoneyKeyValueContainer::setValue(const QString& key, const QString& value)
+{
+ m_kvp[key] = value;
+}
+
+
+void MyMoneyKeyValueContainer::setPairs(const QMap<QString, QString>& list)
+{
+ m_kvp = list;
+}
+
+void MyMoneyKeyValueContainer::deletePair(const QString& key)
+{
+ QMap<QString, QString>::Iterator it;
+
+ it = m_kvp.find(key);
+ if(it != m_kvp.end())
+ m_kvp.remove(it);
+}
+
+void MyMoneyKeyValueContainer::clear(void)
+{
+ m_kvp.clear();
+}
+
+bool MyMoneyKeyValueContainer::operator == (const MyMoneyKeyValueContainer& right) const
+{
+ QMap<QString, QString>::ConstIterator it_a, it_b;
+
+ it_a = m_kvp.begin();
+ it_b = right.m_kvp.begin();
+
+ while(it_a != m_kvp.end() && it_b != right.m_kvp.end()) {
+ if(it_a.key() != it_b.key()
+ || (((*it_a).length() != 0 || (*it_b).length() != 0) && *it_a != *it_b))
+ return false;
+ ++it_a;
+ ++it_b;
+ }
+
+ return (it_a == m_kvp.end() && it_b == right.m_kvp.end());
+}
+
+void MyMoneyKeyValueContainer::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ if(m_kvp.count() != 0) {
+ QDomElement el = document.createElement("KEYVALUEPAIRS");
+
+ QMap<QString, QString>::ConstIterator it;
+ for(it = m_kvp.begin(); it != m_kvp.end(); ++it)
+ {
+ QDomElement pair = document.createElement("PAIR");
+ pair.setAttribute("key", it.key());
+ pair.setAttribute("value", it.data());
+ el.appendChild(pair);
+ }
+
+ parent.appendChild(el);
+ }
+}
diff --git a/kmymoney2/mymoney/mymoneykeyvaluecontainer.h b/kmymoney2/mymoney/mymoneykeyvaluecontainer.h
new file mode 100644
index 0000000..fa045b9
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneykeyvaluecontainer.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+ mymoneykeyvaluecontainer.h
+ -------------------
+ begin : Sun Nov 10 2002
+ copyright : (C) 2000-2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYKEYVALUECONTAINER_H
+#define MYMONEYKEYVALUECONTAINER_H
+
+
+/**
+ * @author Thomas Baumgart
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qdom.h>
+#include <kmymoney/export.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+/**
+ * This class implements a container for key/value pairs. This is used
+ * to store an arbitrary number of attributes with any of the engine
+ * object. The container can also be used to have attributes that are
+ * attached to this object only for a limited time (e.g. between
+ * start of reconciliation end it's end).
+ *
+ * To give any class the ability to have a key/value pair container,
+ * just derive the class from this one. See MyMoneyAccount as an example.
+ */
+class KMYMONEY_EXPORT MyMoneyKeyValueContainer
+{
+public:
+ MyMoneyKeyValueContainer();
+ MyMoneyKeyValueContainer(const QDomElement& node);
+
+ ~MyMoneyKeyValueContainer();
+
+ /**
+ * This method can be used to retrieve the value for a specific @p key.
+ * If the key is unknown in this container, an empty string will be returned.
+ *
+ * @param key const reference to QString with the key to search for
+ * @return reference to value of this key. If the key does not exist,
+ * an emtpy string is returned.
+ */
+ const QString& value(const QString& key) const;
+
+ /**
+ * This method is used to add a key/value pair to the container or
+ * modify an existing pair.
+ *
+ * @param key const reference to QString with the key to search for
+ * @param value const reference to QString with the value for this key
+ */
+ void setValue(const QString& key, const QString& value);
+
+ /**
+ * This method is used to remove an existing key/value pair from the
+ * container. If the key does not exist, the container is not changed.
+ *
+ * @param key const reference to QString with the key to remove
+ */
+ void deletePair(const QString& key);
+
+ /**
+ * This method clears all pairs currently in the container.
+ */
+ void clear(void);
+
+ /**
+ * This method is used to retrieve the whole set of key/value pairs
+ * from the container. It is meant to be used for permanent storage
+ * functionality.
+ *
+ * @return QMap<QString, QString> containing all key/value pairs of
+ * this container.
+ */
+ const QMap<QString, QString>& pairs(void) const { return m_kvp; };
+
+ /**
+ * This method is used to initially store a set of key/value pairs
+ * in the container. It is meant to be used for loading functionality
+ * from permanent storage.
+ *
+ * @param list const QMap<QString, QString> containing the set of
+ * key/value pairs to be loaded into the container.
+ *
+ * @note All existing key/value pairs in the container will be deleted.
+ */
+ void setPairs(const QMap<QString, QString>& list);
+
+ /**
+ * This operator tests for equality of two MyMoneyKeyValueContainer objects
+ */
+ bool operator == (const MyMoneyKeyValueContainer &) const;
+
+ const QString& operator[] ( const QString& k ) const { return value(k); }
+
+ QString& operator[] ( const QString& k) { return m_kvp[k]; }
+
+ /**
+ * This method creates a QDomElement for the @p document
+ * under the parent node @p parent.
+ *
+ * @param document reference to QDomDocument
+ * @param parent reference to QDomElement parent node
+ */
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+private:
+ /**
+ * This member variable represents the container of key/value pairs.
+ */
+ QMap<QString, QString> m_kvp;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneykeyvaluecontainertest.cpp b/kmymoney2/mymoney/mymoneykeyvaluecontainertest.cpp
new file mode 100644
index 0000000..6d3d1db
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneykeyvaluecontainertest.cpp
@@ -0,0 +1,189 @@
+/***************************************************************************
+ mymoneykeyvaluecontainertest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneykeyvaluecontainertest.h"
+#include <kmymoney/mymoneyexception.h>
+
+MyMoneyKeyValueContainerTest::MyMoneyKeyValueContainerTest()
+{
+}
+
+
+void MyMoneyKeyValueContainerTest::setUp () {
+ m = new MyMoneyKeyValueContainer;
+}
+
+void MyMoneyKeyValueContainerTest::tearDown () {
+ delete m;
+}
+
+void MyMoneyKeyValueContainerTest::testEmptyConstructor() {
+ CPPUNIT_ASSERT(m->m_kvp.count() == 0);
+}
+
+void MyMoneyKeyValueContainerTest::testRetrieveValue() {
+ // load a value into the container
+ m->m_kvp["Key"] = "Value";
+ // make sure it's there
+ CPPUNIT_ASSERT(m->m_kvp.count() == 1);
+ CPPUNIT_ASSERT(m->m_kvp["Key"] == "Value");
+ // now check that the access function works
+ CPPUNIT_ASSERT(m->value("Key") == "Value");
+ CPPUNIT_ASSERT(m->value("key").isEmpty());
+}
+
+void MyMoneyKeyValueContainerTest::testSetValue() {
+ m->setValue("Key", "Value");
+ CPPUNIT_ASSERT(m->m_kvp.count() == 1);
+ CPPUNIT_ASSERT(m->m_kvp["Key"] == "Value");
+}
+
+void MyMoneyKeyValueContainerTest::testDeletePair() {
+ m->setValue("Key", "Value");
+ m->setValue("key", "value");
+ CPPUNIT_ASSERT(m->m_kvp.count() == 2);
+ m->deletePair("Key");
+ CPPUNIT_ASSERT(m->m_kvp.count() == 1);
+ CPPUNIT_ASSERT(m->value("Key").isEmpty());
+ CPPUNIT_ASSERT(m->value("key") == "value");
+}
+
+void MyMoneyKeyValueContainerTest::testClear() {
+ m->setValue("Key", "Value");
+ m->setValue("key", "value");
+ CPPUNIT_ASSERT(m->m_kvp.count() == 2);
+ m->clear();
+ CPPUNIT_ASSERT(m->m_kvp.count() == 0);
+}
+
+void MyMoneyKeyValueContainerTest::testRetrieveList() {
+ QMap<QString, QString> copy;
+
+ copy = m->pairs();
+ CPPUNIT_ASSERT(copy.count() == 0);
+ m->setValue("Key", "Value");
+ m->setValue("key", "value");
+ copy = m->pairs();
+ CPPUNIT_ASSERT(copy.count() == 2);
+ CPPUNIT_ASSERT(copy["Key"] == "Value");
+ CPPUNIT_ASSERT(copy["key"] == "value");
+}
+
+void MyMoneyKeyValueContainerTest::testLoadList() {
+ m->setValue("Key", "Value");
+ m->setValue("key", "value");
+
+ CPPUNIT_ASSERT(m->m_kvp.count() == 2);
+ CPPUNIT_ASSERT(m->m_kvp["Key"] == "Value");
+ CPPUNIT_ASSERT(m->m_kvp["key"] == "value");
+}
+
+void MyMoneyKeyValueContainerTest::testWriteXML() {
+ m->setValue("Key", "Value");
+ m->setValue("key", "value");
+
+ QDomDocument doc("TEST");
+ QDomElement el = doc.createElement("KVP-CONTAINER");
+ doc.appendChild(el);
+ m->writeXML(doc, el);
+
+ QString ref(
+ "<!DOCTYPE TEST>\n"
+ "<KVP-CONTAINER>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"Key\" value=\"Value\" />\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ "</KVP-CONTAINER>\n");
+
+ CPPUNIT_ASSERT(doc.toString() == ref);
+}
+
+void MyMoneyKeyValueContainerTest::testReadXML() {
+ m->setValue("Key", "Value");
+ m->setValue("key", "value");
+
+ QString ref_ok(
+ "<!DOCTYPE TEST>\n"
+ "<KVP-CONTAINER>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"Value\" />\n"
+ " <PAIR key=\"Key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ "</KVP-CONTAINER>\n");
+
+ QString ref_false(
+ "<!DOCTYPE TEST>\n"
+ "<KVP-CONTAINER>\n"
+ " <KEYVALUE-PAIRS>\n"
+ " <PAIR key=\"key\" value=\"Value\" />\n"
+ " <PAIR key=\"Key\" value=\"value\" />\n"
+ " </KEYVALUE-PAIRS>\n"
+ "</KVP-CONTAINER>\n");
+
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_false);
+ node = doc.documentElement().firstChild().toElement();
+
+ // make sure, an empty node does not trigger an exception
+ try {
+ MyMoneyKeyValueContainer k(QDomNode());
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ try {
+ MyMoneyKeyValueContainer k(node);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+ try {
+ MyMoneyKeyValueContainer k(node);
+ CPPUNIT_ASSERT(k.m_kvp.count() == 2);
+ CPPUNIT_ASSERT(k.value("key") == "Value");
+ CPPUNIT_ASSERT(k.value("Key") == "value");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyKeyValueContainerTest::testArrayRead()
+{
+ MyMoneyKeyValueContainer kvp;
+ const MyMoneyKeyValueContainer& ckvp = kvp;
+ CPPUNIT_ASSERT(kvp.pairs().count() == 0);
+ CPPUNIT_ASSERT(ckvp["Key"].isEmpty());
+ CPPUNIT_ASSERT(kvp.pairs().count() == 0);
+ kvp.setValue("Key", "Value");
+ CPPUNIT_ASSERT(kvp["Key"] == "Value");
+}
+
+void MyMoneyKeyValueContainerTest::testArrayWrite()
+{
+ MyMoneyKeyValueContainer kvp;
+ kvp["Key"] = "Value";
+ CPPUNIT_ASSERT(kvp.pairs().count() == 1);
+ CPPUNIT_ASSERT(kvp.value("Key") == "Value");
+}
+
diff --git a/kmymoney2/mymoney/mymoneykeyvaluecontainertest.h b/kmymoney2/mymoney/mymoneykeyvaluecontainertest.h
new file mode 100644
index 0000000..d2d89d8
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneykeyvaluecontainertest.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ mymoneykeyvaluecontainertest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYKEYVALUECONTAINERTEST_H__
+#define __MYMONEYKEYVALUECONTAINERTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneykeyvaluecontainer.h"
+#undef private
+
+class MyMoneyKeyValueContainerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyKeyValueContainerTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testRetrieveValue);
+ CPPUNIT_TEST(testSetValue);
+ CPPUNIT_TEST(testDeletePair);
+ CPPUNIT_TEST(testClear);
+ CPPUNIT_TEST(testRetrieveList);
+ CPPUNIT_TEST(testLoadList);
+ CPPUNIT_TEST(testWriteXML);
+ CPPUNIT_TEST(testReadXML);
+ CPPUNIT_TEST(testArrayRead);
+ CPPUNIT_TEST(testArrayWrite);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyKeyValueContainer *m;
+
+public:
+ MyMoneyKeyValueContainerTest();
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testRetrieveValue();
+ void testSetValue();
+ void testDeletePair();
+ void testClear();
+ void testRetrieveList();
+ void testLoadList();
+ void testArrayRead();
+ void testArrayWrite();
+ void testWriteXML();
+ void testReadXML();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneymoney.cpp b/kmymoney2/mymoney/mymoneymoney.cpp
new file mode 100644
index 0000000..993a872
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneymoney.cpp
@@ -0,0 +1,794 @@
+/***************************************************************************
+ mymoneymymoney.cpp - description
+ -------------------
+ begin : Thu Feb 21 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// make sure, that this is defined before we even include any other header file
+#ifndef __STDC_LIMIT_MACROS
+ #define __STDC_LIMIT_MACROS // force definition of min and max values
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneymoney.h"
+#include "mymoneyaccount.h"
+#include "mymoneysecurity.h"
+
+unsigned char MyMoneyMoney::_thousandSeparator = ',';
+unsigned char MyMoneyMoney::_decimalSeparator = '.';
+MyMoneyMoney::signPosition MyMoneyMoney::_negativeMonetarySignPosition = BeforeQuantityMoney;
+MyMoneyMoney::signPosition MyMoneyMoney::_positiveMonetarySignPosition = BeforeQuantityMoney;
+bool MyMoneyMoney::_negativePrefixCurrencySymbol = false;
+bool MyMoneyMoney::_positivePrefixCurrencySymbol = false;
+
+MyMoneyMoney::fileVersionE MyMoneyMoney::_fileVersion = MyMoneyMoney::FILE_4_BYTE_VALUE;
+
+MyMoneyMoney MyMoneyMoney::maxValue = MyMoneyMoney(INT64_MAX,100);
+MyMoneyMoney MyMoneyMoney::minValue = MyMoneyMoney(INT64_MIN,100);
+MyMoneyMoney MyMoneyMoney::autoCalc = MyMoneyMoney(INT64_MIN+1,100);
+
+void MyMoneyMoney::setNegativePrefixCurrencySymbol(const bool flag)
+{
+ _negativePrefixCurrencySymbol = flag;
+}
+
+void MyMoneyMoney::setPositivePrefixCurrencySymbol(const bool flag)
+{
+ _positivePrefixCurrencySymbol = flag;
+}
+
+void MyMoneyMoney::setNegativeMonetarySignPosition(const signPosition pos)
+{
+ _negativeMonetarySignPosition = pos;
+}
+
+MyMoneyMoney::signPosition MyMoneyMoney::negativeMonetarySignPosition(void)
+{
+ return _negativeMonetarySignPosition;
+}
+
+void MyMoneyMoney::setPositiveMonetarySignPosition(const signPosition pos)
+{
+ _positiveMonetarySignPosition = pos;
+}
+
+MyMoneyMoney::signPosition MyMoneyMoney::positiveMonetarySignPosition(void)
+{
+ return _positiveMonetarySignPosition;
+}
+
+void MyMoneyMoney::setThousandSeparator(const unsigned char separator)
+{
+ if(separator != ' ')
+ _thousandSeparator = separator;
+ else
+ _thousandSeparator = 0;
+}
+
+unsigned char MyMoneyMoney::thousandSeparator(void)
+{
+ return _thousandSeparator;
+}
+
+void MyMoneyMoney::setDecimalSeparator(const unsigned char separator)
+{
+ if(separator != ' ')
+ _decimalSeparator = separator;
+ else
+ _decimalSeparator = 0;
+}
+
+unsigned char MyMoneyMoney::decimalSeparator(void)
+{
+ return _decimalSeparator;
+}
+
+void MyMoneyMoney::setFileVersion(fileVersionE version)
+{
+ _fileVersion = version;
+}
+
+MyMoneyMoney::MyMoneyMoney(const QString& pszAmount)
+{
+ m_num = 0;
+ m_denom = 1;
+
+ // an empty string is zero
+ if (pszAmount.isEmpty())
+ return;
+
+ // take care of prices given in the form "8 5/16"
+ // and our own internal represenation
+ QRegExp regExp("^((\\d+)\\s+|-)?(\\d+)/(\\d+)");
+ // +-#2-+ +-#3-+ +-#4-+
+ // +-----#1-----+
+ if (regExp.search(pszAmount) > -1) {
+ m_num = regExp.cap(3).toLongLong();
+ m_denom = regExp.cap(4).toLongLong();
+ const QString& part1 = regExp.cap(1);
+ if(!part1.isEmpty()) {
+ if(part1 == QString("-")) {
+ m_num = -m_num;
+
+ } else {
+ *this += MyMoneyMoney(regExp.cap(2));
+ }
+ }
+ return;
+ }
+
+ QString res = pszAmount;
+ // get rid of anything that is not
+ // a) numeric
+ // b) _decimalSeparator
+ // c) negative indicator
+ QString validChars = QString("\\d%1").arg(QChar(decimalSeparator()));
+ // we need to escape the minus sign here, because later on it will be
+ // part of "\d,-()" and that does not work. It needs to be "\d,\-()"
+ // And we need two of them, because we're in C
+ QString negChars("\\-");
+ if(_negativeMonetarySignPosition == ParensAround) {
+ // Since we want to allow '-' as well as '()' for negative entry
+ // we just add the parens here.
+ negChars += "()";
+ }
+ validChars += negChars;
+ // qDebug("0: '%s'", validChars.data());
+
+ QRegExp invChars(QString("[^%1]").arg(validChars));
+ // qDebug("1: '%s'", res.data());
+ res.remove(invChars);
+
+ QRegExp negCharSet(QString("[%1]").arg(negChars));
+ bool isNegative = false;
+ if(res.find(negCharSet) != -1) {
+ isNegative = true;
+ res.remove(negCharSet);
+ }
+ // qDebug("2: '%s' %s", res.data(), isNegative ? "(-)" : "");
+ int pos;
+
+ // qDebug("3: '%s'", res.data());
+ if((pos = res.find(_decimalSeparator)) != -1) {
+ // make sure, we get the denominator right
+ m_denom = precToDenom(res.length() - pos - 1);
+
+ // now remove the decimal symbol
+ res.remove(pos, 1);
+ }
+ // qDebug("4: '%s'", res.data());
+ if(res.length() > 0)
+ m_num = atoll( res );
+
+ if(isNegative)
+ m_num = -m_num;
+}
+
+QString MyMoneyMoney::formatMoney(int denom, bool showThousandSeparator) const
+{
+ return formatMoney("", denomToPrec(denom), showThousandSeparator);
+}
+
+QString MyMoneyMoney::formatMoney(const MyMoneyAccount& acc, const MyMoneySecurity& sec, bool showThousandSeparator) const
+{
+ return formatMoney(sec.tradingSymbol(), denomToPrec(acc.fraction()), showThousandSeparator);
+}
+
+QString MyMoneyMoney::formatMoney(const MyMoneySecurity& sec, bool showThousandSeparator) const
+{
+ return formatMoney(sec.tradingSymbol(), denomToPrec(sec.smallestAccountFraction()), showThousandSeparator);
+}
+
+QString MyMoneyMoney::formatMoney(const QString& currency, const int prec, bool showThousandSeparator) const
+{
+ QString res;
+ QString tmpCurrency = currency;
+ int tmpPrec = prec;
+ signed64 denom = 1;
+ signed64 m_64Value;
+
+ // if prec == -1 we want the maximum possible but w/o trailing zeroes
+ if(tmpPrec > -1) {
+ while(tmpPrec--) {
+ denom *= 10;
+ }
+ } else {
+ // fix it to a max of 8 digits on the right side for now
+ denom = 100000000;
+ }
+
+ m_64Value = convert(denom).m_num;
+
+ // Once we really support multiple currencies then this method will
+ // be much better than using KGlobal::locale()->formatMoney.
+ bool bNegative = false;
+ signed64 left = m_64Value / denom;
+ signed64 right = m_64Value % denom;
+
+ if (right < 0){
+ right = -right;
+ bNegative = true;
+ }
+ if (left < 0) {
+ left = -left;
+ bNegative = true;
+ }
+
+ if(left & 0xFFFFFFFF00000000LL) {
+ signed64 tmp = left;
+
+ // QString.sprintf("%Ld") did not work :-(, so I had to
+ // do it the old ugly way.
+ while(tmp) {
+ res.insert(0, QString("%1").arg(static_cast<int>(tmp % 10)));
+ tmp /= 10;
+ }
+
+ } else
+ res = QString("%1").arg((long)left);
+
+ if(showThousandSeparator) {
+ int pos = res.length();
+ while((0 < (pos -= 3)) && thousandSeparator())
+ res.insert(pos, thousandSeparator());
+ }
+
+ if(prec > 0 || (prec == -1 && right != 0)) {
+ if(decimalSeparator())
+ res += decimalSeparator();
+
+ // using
+ //
+ // res += QString("%1").arg(right).rightJustify(prec, '0', true);
+ //
+ // caused some weird results if right was rather large. Eg: right being
+ // 666600000 should have appended a 0, but instead it prepended a 0. With
+ // res being "2," the result wasn't "2,6666000000" as expected, but rather
+ // "2,0666600000" which was not usable. The code below works for me.
+ QString rs = QString("%1").arg(right);
+ if(prec != -1)
+ rs = rs.rightJustify(prec, '0', true);
+ else {
+ rs = rs.rightJustify(8, '0', true);
+ // no trailing zeroes or decimal separators
+ while(rs.endsWith("0"))
+ rs.truncate(rs.length()-1);
+ while(rs.endsWith(QChar(decimalSeparator())))
+ rs.truncate(rs.length()-1);
+ }
+ res += rs;
+ }
+
+ signPosition signpos = bNegative ? _negativeMonetarySignPosition : _positiveMonetarySignPosition;
+ QString sign = bNegative ? "-" : "";
+
+ switch(signpos) {
+ case ParensAround:
+ res.prepend('(');
+ res.append(')');
+ break;
+ case BeforeQuantityMoney:
+ res.prepend(sign);
+ break;
+ case AfterQuantityMoney:
+ res.append(sign);
+ break;
+ case BeforeMoney:
+ tmpCurrency.prepend(sign);
+ break;
+ case AfterMoney:
+ tmpCurrency.append(sign);
+ break;
+ }
+ if(!tmpCurrency.isEmpty()) {
+ if(bNegative ? _negativePrefixCurrencySymbol : _positivePrefixCurrencySymbol){
+ res.prepend(' ');
+ res.prepend(tmpCurrency);
+ } else {
+ res.append(' ');
+ res.append(tmpCurrency);
+ }
+ }
+
+ return res;
+}
+
+const QString MyMoneyMoney::toString(void) const
+{
+ signed64 tmp = m_num < 0 ? - m_num : m_num;
+ QString res;
+ QString resf;
+
+ // QString.sprintf("%Ld") did not work :-(, so I had to
+ // do it the old ugly way.
+ while(tmp) {
+ res.prepend(QString("%1").arg(static_cast<int>(tmp % 10)));
+ tmp /= 10;
+ }
+ if(res.isEmpty())
+ res = QString("0");
+
+ if(m_num < 0)
+ res.prepend('-');
+
+ tmp = m_denom;
+ while(tmp) {
+ resf.prepend(QString("%1").arg(static_cast<int>(tmp % 10)));
+ tmp /= 10;
+ }
+ return res + "/" + resf;
+}
+
+QDataStream &operator<<(QDataStream &s, const MyMoneyMoney &_money)
+{
+ // We WILL lose data here if the user has more than 2 billion pounds :-(
+ // QT defined it here as long:
+ // qglobal.h:typedef long Q_INT64;
+
+ MyMoneyMoney money = _money.convert(100);
+
+ switch(MyMoneyMoney::_fileVersion) {
+ case MyMoneyMoney::FILE_4_BYTE_VALUE:
+ if(money.m_num & 0xffffffff00000000LL)
+ qWarning("Lost data while writing out MyMoneyMoney object using deprecated 4 byte writer");
+
+ s << static_cast<Q_INT32> (money.m_num & 0xffffffff);
+ break;
+
+ default:
+ qDebug("Unknown file version while writing MyMoneyMoney object! Use FILE_8_BYTE_VALUE");
+ // tricky fall through here
+
+ case MyMoneyMoney::FILE_8_BYTE_VALUE:
+ s << static_cast<Q_INT32> (money.m_num >> 32);
+ s << static_cast<Q_INT32> (money.m_num & 0xffffffff);
+ break;
+ }
+ return s;
+}
+
+QDataStream &operator>>(QDataStream &s, MyMoneyMoney &money)
+{
+ Q_INT32 tmp;
+ switch(MyMoneyMoney::_fileVersion) {
+ case MyMoneyMoney::FILE_4_BYTE_VALUE:
+ s >> tmp;
+ money.m_num = static_cast<signed64> (tmp);
+ money.m_denom = 100;
+ break;
+
+ default:
+ qDebug("Unknown file version while writing MyMoneyMoney object! FILE_8_BYTE_VALUE assumed");
+ // tricky fall through here
+
+ case MyMoneyMoney::FILE_8_BYTE_VALUE:
+ s >> tmp;
+ money.m_num = static_cast<signed64> (tmp);
+ money.m_num <<= 32;
+ s >> tmp;
+ money.m_num |= static_cast<signed64> (tmp);
+ money.m_denom = 100;
+ break;
+ }
+ return s;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator+
+// Purpose: Addition operator - adds the input amount to the object
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: b - MyMoneyMoney object to be added
+//
+////////////////////////////////////////////////////////////////////////////////
+MyMoneyMoney MyMoneyMoney::operator+( const MyMoneyMoney& _b) const
+{
+ MyMoneyMoney a(*this);
+ MyMoneyMoney b(_b);
+ MyMoneyMoney sum;
+ signed64 lcd;
+
+ if(a.m_denom < 0) {
+ a.m_num *= a.m_denom;
+ a.m_denom = 1;
+ }
+ if(b.m_denom < 0) {
+ b.m_num *= b.m_denom;
+ b.m_denom = 1;
+ }
+
+ if(a.m_denom == b.m_denom) {
+ sum.m_num = a.m_num + b.m_num;
+ sum.m_denom = a.m_denom;
+ } else {
+ lcd = a.getLcd(b);
+ sum.m_num = a.m_num*(lcd/a.m_denom) + b.m_num*(lcd/b.m_denom);
+ sum.m_denom = lcd;
+ }
+ return sum;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator-
+// Purpose: Addition operator - subtracts the input amount from the object
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: AmountInPence - MyMoneyMoney object to be subtracted
+//
+////////////////////////////////////////////////////////////////////////////////
+MyMoneyMoney MyMoneyMoney::operator-( const MyMoneyMoney& _b) const
+{
+ MyMoneyMoney a(*this);
+ MyMoneyMoney b(_b);
+ MyMoneyMoney diff;
+ signed64 lcd;
+
+ if(a.m_denom < 0) {
+ a.m_num *= a.m_denom;
+ a.m_denom = 1;
+ }
+ if(b.m_denom < 0) {
+ b.m_num *= b.m_denom;
+ b.m_denom = 1;
+ }
+
+ if(a.m_denom == b.m_denom) {
+ diff.m_num = a.m_num - b.m_num;
+ diff.m_denom = a.m_denom;
+ } else {
+ lcd = a.getLcd(b);
+ diff.m_num = a.m_num*(lcd/a.m_denom) - b.m_num*(lcd/b.m_denom);
+ diff.m_denom = lcd;
+ }
+ return diff;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator*
+// Purpose: Multiplication operator - multiplies the input amount to the object
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: b - MyMoneyMoney object to be multiplied
+//
+////////////////////////////////////////////////////////////////////////////////
+MyMoneyMoney MyMoneyMoney::operator*( const MyMoneyMoney& _b ) const
+{
+ MyMoneyMoney a(*this);
+ MyMoneyMoney b(_b);
+ MyMoneyMoney product;
+
+ if(a.m_denom < 0) {
+ a.m_num *= a.m_denom;
+ a.m_denom = 1;
+ }
+ if(b.m_denom < 0) {
+ b.m_num *= b.m_denom;
+ b.m_denom = 1;
+ }
+
+ product.m_num = a.m_num * b.m_num;
+ product.m_denom = a.m_denom * b.m_denom;
+
+ if(product.m_denom < 0) {
+ product.m_num = -product.m_num;
+ product.m_denom = -product.m_denom;
+ }
+ return product;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator/
+// Purpose: Division operator - divides the object by the input amount
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: b - MyMoneyMoney object to be used as dividend
+//
+////////////////////////////////////////////////////////////////////////////////
+MyMoneyMoney MyMoneyMoney::operator / ( const MyMoneyMoney& _b ) const
+{
+ MyMoneyMoney a(*this);
+ MyMoneyMoney b(_b);
+ MyMoneyMoney quotient;
+ signed64 lcd;
+
+ if(a.m_denom < 0) {
+ a.m_num *= a.m_denom;
+ a.m_denom = 1;
+ }
+ if(b.m_denom < 0) {
+ b.m_num *= b.m_denom;
+ b.m_denom = 1;
+ }
+
+ if(a.m_denom == b.m_denom) {
+ quotient.m_num = a.m_num;
+ quotient.m_denom = b.m_num;
+ }
+ else {
+ /* ok, convert to the lcd and compute from there... */
+ lcd = a.getLcd(b);
+ quotient.m_num = a.m_num*(lcd/a.m_denom);
+ quotient.m_denom = b.m_num*(lcd/b.m_denom);
+ }
+
+ if(quotient.m_denom < 0) {
+ quotient.m_num = -quotient.m_num;
+ quotient.m_denom = -quotient.m_denom;
+ }
+
+ Q_ASSERT(quotient.m_denom != 0);
+
+ return quotient;
+}
+
+signed64 MyMoneyMoney::getLcd(const MyMoneyMoney& b) const
+{
+ signed64 current_divisor = 2;
+ signed64 max_square;
+ signed64 three_count = 0;
+ signed64 small_denom;
+ signed64 big_denom;
+
+ if(b.m_denom < m_denom) {
+ small_denom = b.m_denom;
+ big_denom = m_denom;
+ }
+ else {
+ small_denom = m_denom;
+ big_denom = b.m_denom;
+ }
+
+ /* special case: smaller divides smoothly into larger */
+ if((big_denom % small_denom) == 0) {
+ return big_denom;
+ }
+
+ max_square = small_denom;
+
+ /* the LCM algorithm : factor out the union of the prime factors of the
+ * two args and then multiply the remainders together.
+ *
+ * To do this, we find the successive prime factors of the smaller
+ * denominator and eliminate them from both the smaller and larger
+ * denominator (so we only count factors on a one-on-one basis),
+ * then multiply the original smaller by the remains of the larger.
+ *
+ * I.e. LCM 100,96875 == 2*2*5*5,31*5*5*5*5 = 2*2,31*5*5
+ * answer: multiply 100 by 31*5*5 == 387500
+ */
+ while((current_divisor * current_divisor) <= max_square) {
+ if(((small_denom % current_divisor) == 0) &&
+ ((big_denom % current_divisor) == 0)) {
+ big_denom = big_denom / current_divisor;
+ small_denom = small_denom / current_divisor;
+ }
+ else {
+ if(current_divisor == 2) {
+ current_divisor++;
+ }
+ else if(three_count == 3) {
+ current_divisor += 4;
+ three_count = 1;
+ }
+ else {
+ current_divisor += 2;
+ three_count++;
+ }
+ }
+
+ if((current_divisor > small_denom) ||
+ (current_divisor > big_denom)) {
+ break;
+ }
+ }
+
+ /* max_sqaure is the original small_denom */
+ return max_square * big_denom;
+}
+
+const MyMoneyMoney MyMoneyMoney::convert(const signed64 _denom, const roundingMethod how) const
+{
+ MyMoneyMoney out(*this);
+ MyMoneyMoney in (*this);
+ MyMoneyMoney temp;
+
+ signed64 denom = _denom;
+ signed64 temp_bc;
+ signed64 temp_a;
+ signed64 remainder;
+ signed64 sign;
+ int denom_neg=0;
+
+ if(m_denom != denom) {
+ /* if the denominator of the input value is negative, get rid of that. */
+ if(m_denom < 0) {
+ in.m_num = in.m_num * (- in.m_denom);
+ in.m_denom = 1;
+ }
+
+ sign = (in.m_num < 0) ? -1 : 1;
+
+ /* if the denominator is less than zero, we are to interpret it as
+ * the reciprocal of its magnitude. */
+ if(denom < 0) {
+ denom = - denom;
+ denom_neg = 1;
+ temp_a = (in.m_num < 0) ? -in.m_num : in.m_num;
+ temp_bc = in.m_denom * denom;
+ remainder = in.m_num % temp_bc;
+ out.m_num = in.m_num / temp_bc;
+ out.m_denom = -denom;
+ }
+ else {
+ /* do all the modulo and int division on positive values to make
+ * things a little clearer. Reduce the fraction denom/in.denom to
+ * help with range errors (FIXME : need bigger intermediate rep) */
+ temp.m_num = denom;
+ temp.m_denom = in.m_denom;
+ temp = temp.reduce();
+
+ out.m_num = in.m_num * temp.m_num;
+ out.m_num = (out.m_num < 0) ? -out.m_num : out.m_num;
+ remainder = out.m_num % temp.m_denom;
+ out.m_num = out.m_num / temp.m_denom;
+ out.m_denom = denom;
+ }
+
+ if(remainder > 0) {
+ switch(how) {
+ case RndFloor:
+ if(sign < 0) {
+ out.m_num = out.m_num + 1;
+ }
+ break;
+
+ case RndCeil:
+ if(sign > 0) {
+ out.m_num = out.m_num + 1;
+ }
+ break;
+
+ case RndTrunc:
+ break;
+
+ case RndPromote:
+ out.m_num = out.m_num + 1;
+ break;
+
+ case RndHalfDown:
+ if(denom_neg) {
+ if((2 * remainder) > in.m_denom*denom) {
+ out.m_num = out.m_num + 1;
+ }
+ }
+ else if((2 * remainder) > temp.m_denom) {
+ out.m_num = out.m_num + 1;
+ }
+ break;
+
+ case RndHalfUp:
+ if(denom_neg) {
+ if((2 * remainder) >= in.m_denom*denom) {
+ out.m_num = out.m_num + 1;
+ }
+ }
+ else if((2 * remainder ) >= temp.m_denom) {
+ out.m_num = out.m_num + 1;
+ }
+ break;
+
+ case RndRound:
+ if(denom_neg) {
+ if((2 * remainder) > in.m_denom*denom) {
+ out.m_num = out.m_num + 1;
+ }
+ else if((2 * remainder) == in.m_denom*denom) {
+ if(out.m_num % 2) {
+ out.m_num = out.m_num + 1;
+ }
+ }
+ }
+ else {
+ if((2 * remainder ) > temp.m_denom) {
+ out.m_num = out.m_num + 1;
+ }
+ else if((2 * remainder) == temp.m_denom) {
+ if(out.m_num % 2) {
+ out.m_num = out.m_num + 1;
+ }
+ }
+ }
+ break;
+
+ case RndNever:
+ qWarning("MyMoneyMoney: have remainder \"%Ld/%Ld\"->convert(%Ld, %d)",
+ m_num, m_denom, _denom, how);
+ break;
+ }
+ }
+ out.m_num = (sign > 0) ? out.m_num : (-out.m_num);
+ }
+
+ return out;
+}
+
+/********************************************************************
+ * gnc_numeric_reduce
+ * reduce a fraction by GCF elimination. This is NOT done as a
+ * part of the arithmetic API unless GNC_DENOM_REDUCE is specified
+ * as the output denominator.
+ ********************************************************************/
+const MyMoneyMoney MyMoneyMoney::reduce(void) const
+{
+ MyMoneyMoney out;
+ signed64 t;
+ signed64 num = (m_num < 0) ? (- m_num) : m_num ;
+ signed64 denom = m_denom;
+
+ /* the strategy is to use euclid's algorithm */
+ while (denom > 0) {
+ t = num % denom;
+ num = denom;
+ denom = t;
+ }
+ /* num = gcd */
+
+ /* all calculations are done on positive num, since it's not
+ * well defined what % does for negative values */
+ out.m_num = m_num / num;
+ out.m_denom = m_denom / num;
+ return out;
+}
+
+signed64 MyMoneyMoney::precToDenom(int prec)
+{
+ signed64 denom = 1;
+
+ while(prec--)
+ denom *= 10;
+
+ return denom;
+}
+
+double MyMoneyMoney::toDouble(void) const
+{
+ return static_cast<double>(m_num) / static_cast<double>(m_denom);
+}
+
+int MyMoneyMoney::denomToPrec(signed64 fract)
+{
+ int rc = 0;
+ while(fract > 1) {
+ rc++;
+ fract /= 10;
+ }
+ return rc;
+}
+
+MyMoneyMoney::operator int() const
+{
+ return static_cast<int> (m_num / m_denom);
+}
diff --git a/kmymoney2/mymoney/mymoneymoney.h b/kmymoney2/mymoney/mymoneymoney.h
new file mode 100644
index 0000000..74235c7
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneymoney.h
@@ -0,0 +1,612 @@
+/***************************************************************************
+ mymoneymoney.h
+ -------------------
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef _MYMONEYMONEY_H
+#define _MYMONEYMONEY_H
+
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_ATOLL
+# ifdef HAVE_STRTOLL
+# define atoll(a) strtoll(a, 0, 10)
+# endif
+#endif
+
+#include <cmath>
+
+#ifdef _GLIBCPP_HAVE_MODFL
+#define HAVE_LONG_DOUBLE 1
+#endif
+
+#ifndef HAVE_LONG_DOUBLE
+#define HAVE_LONG_DOUBLE 0
+#endif
+
+// So we can save this object
+#include <qstring.h>
+#include <qdatastream.h>
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneyexception.h>
+
+// Check for standard definitions
+#ifdef HAVE_STDINT_H
+ #ifndef __STDC_LIMIT_MACROS
+ #define __STDC_LIMIT_MACROS // force definition of min and max values
+ #endif
+ #include <stdint.h>
+#else
+ #include <limits.h>
+ #define INT64_MAX LLONG_MAX
+ #define INT64_MIN LLONG_MIN
+#endif
+
+typedef int64_t signed64;
+typedef uint64_t unsigned64;
+
+class MyMoneyAccount;
+class MyMoneySecurity;
+
+/**
+ * This class represents a value within the MyMoney Engine
+ *
+ * @author Michael Edwardes
+ */
+class KMYMONEY_EXPORT MyMoneyMoney
+{
+public:
+ enum fileVersionE {
+ FILE_4_BYTE_VALUE = 0,
+ FILE_8_BYTE_VALUE
+ };
+
+ enum signPosition {
+ // keep those in sync with the ones defined in klocale.h
+ ParensAround = 0,
+ BeforeQuantityMoney = 1,
+ AfterQuantityMoney = 2,
+ BeforeMoney = 3,
+ AfterMoney = 4
+ };
+
+ enum roundingMethod {
+ RndNever = 0,
+ RndFloor,
+ RndCeil,
+ RndTrunc,
+ RndPromote,
+ RndHalfDown,
+ RndHalfUp,
+ RndRound
+ };
+
+ // construction
+ MyMoneyMoney();
+ MyMoneyMoney( const int iAmount, const signed64 denom = 100 );
+ MyMoneyMoney( const QString& pszAmount );
+ MyMoneyMoney( const signed64 Amount, const signed64 denom = 100 );
+ MyMoneyMoney( const double dAmount, const signed64 denom = 100 );
+#if HAVE_LONG_DOUBLE
+ MyMoneyMoney( const long double dAmount, const signed64 denom = 100 );
+#endif
+
+ // copy constructor
+ MyMoneyMoney( const MyMoneyMoney& AmountInPence );
+
+ // signed64 value(const int prec = 2) const;
+ const MyMoneyMoney abs(void) const { return m_num < 0 ? -(*this) : *this; };
+
+ /**
+ * This method returns a formatted string according to the settings
+ * of _thousandSeparator, _decimalSeparator, _negativeMonetarySignPosition,
+ * _positiveMonetaryPosition, _negativePrefixCurrencySymbol and
+ * _positivePrefixCurrencySymbol. Those values can be modified using
+ * the appropriate set-methods.
+ *
+ * @param currency The currency symbol
+ * @param prec The number of fractional digits
+ * @param showThousandSeparator should the thousandSeparator symbol be inserted
+ * (@a true) or not (@a false) (default true)
+ */
+ QString formatMoney(const QString& currency, const int prec, bool showThousandSeparator = true) const;
+
+ /**
+ * This is a convenience method. It behaves exactly as the above one, but takes the information
+ * about currency symbol and precision out of the MyMoneySecurity and MyMoneyAccount objects
+ * @a acc and @a sec.
+ */
+ QString formatMoney(const MyMoneyAccount& acc, const MyMoneySecurity& sec, bool showThousandSeparator = true) const;
+
+ /**
+ * This is a convenience method. It behaves exactly as the above one, but takes the information
+ * about currency symbol and precision out of the MyMoneySecurity object @a sec.
+ */
+ QString formatMoney(const MyMoneySecurity& sec, bool showThousandSeparator = true) const;
+
+ /**
+ * This is a convenience method. It behaves exactly as the above one, but takes the information
+ * about precision out of the denomination @a denom. No currency symbol is shown. If you want
+ * to see a currency symbol, please use formatMoney(const MyMoneyAccount& acc, const MyMoneySecurity& sec, bool showThousandSeparator)
+ * instead.
+ *
+ * @note denom is often set to account.fraction(security).
+ */
+ QString formatMoney(int denom, bool showThousandSeparator = true) const;
+
+ /**
+ * This method is used to convert the smallest fraction information into
+ * the corresponding number of digits used for precision.
+ *
+ * @param fract smallest fractional part (e.g. 100 for cents)
+ * @return number of precision digits (e.g. 2 for cents)
+ */
+ static int denomToPrec(signed64 fract);
+
+ const QString toString(void) const;
+ const MyMoneyMoney convert(const signed64 denom = 100, const roundingMethod how = RndRound) const;
+ static signed64 precToDenom(int prec);
+ double toDouble(void) const;
+
+ static void setThousandSeparator(const unsigned char);
+ static void setDecimalSeparator(const unsigned char);
+ static void setNegativeMonetarySignPosition(const signPosition pos);
+ static void setPositiveMonetarySignPosition(const signPosition pos);
+ static void setNegativePrefixCurrencySymbol(const bool flags);
+ static void setPositivePrefixCurrencySymbol(const bool flags);
+
+ static unsigned char thousandSeparator(void);
+ static unsigned char decimalSeparator(void);
+ static signPosition negativeMonetarySignPosition(void);
+ static signPosition positiveMonetarySignPosition(void);
+ static void setFileVersion(const fileVersionE version);
+
+ // assignment
+ const MyMoneyMoney& operator=( const MyMoneyMoney& Amount );
+ const MyMoneyMoney& operator=( const QString& pszAmount );
+
+ // comparison
+ bool operator==( const MyMoneyMoney& Amount ) const;
+ bool operator!=( const MyMoneyMoney& Amount ) const;
+ bool operator<( const MyMoneyMoney& Amount ) const;
+ bool operator>( const MyMoneyMoney& Amount ) const;
+ bool operator<=( const MyMoneyMoney& Amount ) const;
+ bool operator>=( const MyMoneyMoney& Amount ) const;
+
+ bool operator==( const QString& pszAmount ) const;
+ bool operator!=( const QString& pszAmount ) const;
+ bool operator<( const QString& pszAmount ) const;
+ bool operator>( const QString& pszAmount ) const;
+ bool operator<=( const QString& pszAmount ) const;
+ bool operator>=( const QString& pszAmount ) const;
+
+ // calculation
+ MyMoneyMoney operator+( const MyMoneyMoney& Amount ) const;
+
+ MyMoneyMoney operator-( const MyMoneyMoney& Amount ) const;
+ MyMoneyMoney operator-( ) const;
+
+ MyMoneyMoney operator*( const MyMoneyMoney& factor ) const;
+ MyMoneyMoney operator*( int factor ) const;
+ MyMoneyMoney operator*( signed64 factor ) const;
+ MyMoneyMoney operator/( const MyMoneyMoney& Amount ) const;
+
+ // unary operators
+ MyMoneyMoney& operator+= ( const MyMoneyMoney& Amount );
+ MyMoneyMoney& operator-= ( const MyMoneyMoney& Amount );
+ MyMoneyMoney& operator/= ( const MyMoneyMoney& Amount );
+
+ // conversion
+ operator int() const;
+
+ static MyMoneyMoney maxValue;
+ static MyMoneyMoney minValue;
+ static MyMoneyMoney autoCalc;
+
+ bool isNegative() const { return (m_num < 0) ? true : false; }
+ bool isPositive() const { return (m_num > 0) ? true : false; }
+ bool isZero() const { return m_num == 0; }
+ bool isAutoCalc(void) const { return (*this == autoCalc); }
+
+ const MyMoneyMoney reduce(void) const;
+
+private:
+ signed64 m_num;
+ signed64 m_denom;
+
+ signed64 getLcd(const MyMoneyMoney& b) const;
+
+ KMYMONEY_EXPORT friend QDataStream &operator<<(QDataStream &, const MyMoneyMoney &);
+ KMYMONEY_EXPORT friend QDataStream &operator>>(QDataStream &, MyMoneyMoney &);
+
+ static unsigned char _thousandSeparator;
+ static unsigned char _decimalSeparator;
+ static signPosition _negativeMonetarySignPosition;
+ static signPosition _positiveMonetarySignPosition;
+ static bool _negativePrefixCurrencySymbol;
+ static bool _positivePrefixCurrencySymbol;
+ static MyMoneyMoney::fileVersionE _fileVersion;
+
+};
+
+//=============================================================================
+//
+// Inline functions
+//
+//=============================================================================
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: MyMoneyMoney
+// Purpose: Constructor - constructs object set to 0.
+// Returns: None
+// Throws: Nothing.
+// Arguments: None
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney::MyMoneyMoney()
+{
+ m_num = 0;
+ m_denom = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: MyMoneyMoney
+// Purpose: Constructor - constructs object from an amount in a signed64 value
+// Returns: None
+// Throws: Nothing.
+// Arguments: Amount - signed 64 object containing amount
+// denom - denominator of the object
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney::MyMoneyMoney(signed64 Amount, const signed64 denom)
+{
+ if(!denom)
+ throw new MYMONEYEXCEPTION("Denominator 0 not allowed!");
+
+ m_num = Amount;
+ m_denom = denom;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: MyMoneyMoney
+// Purpose: Constructor - constructs object from an amount in a double value
+// Returns: None
+// Throws: Nothing.
+// Arguments: dAmount - double object containing amount
+// denom - denominator of the object
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney::MyMoneyMoney(const double dAmount, const signed64 denom)
+{
+ double adj = dAmount < 0 ? -0.5 : 0.5;
+ m_denom = denom;
+ m_num = (signed64) (dAmount * (double)m_denom + adj);
+}
+
+#if HAVE_LONG_DOUBLE
+////////////////////////////////////////////////////////////////////////////////
+// Name: MyMoneyMoney
+// Purpose: Constructor - constructs object from an amount in a long double value
+// Returns: None
+// Throws: Nothing.
+// Arguments: dAmount - long double object containing amount
+// denom - denominator of the object
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney::MyMoneyMoney(const long double dAmount, const signed64 denom)
+{
+ long double adj = dAmount < 0 ? -0.5 : 0.5;
+ m_denom = denom;
+ m_num = static_cast<signed64> (dAmount * m_denom + adj);
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: MyMoneyMoney
+// Purpose: Constructor - constructs object from an amount in a integer value
+// Returns: None
+// Throws: Nothing.
+// Arguments: iAmount - integer object containing amount
+// denom - denominator of the object
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney::MyMoneyMoney(const int iAmount, const signed64 denom)
+{
+ if(!denom)
+ throw new MYMONEYEXCEPTION("Denominator 0 not allowed!");
+
+ m_num = static_cast<signed64>(iAmount);
+ m_denom = denom;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: MyMoneyMoney
+// Purpose: Copy Constructor - constructs object from another MyMoneyMoney object
+// Returns: None
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be copied
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney::MyMoneyMoney(const MyMoneyMoney& Amount)
+{
+ m_num = Amount.m_num;
+ m_denom = Amount.m_denom;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator=
+// Purpose: Assignment operator - modifies object from input MyMoneyMoney object
+// Returns: Const reference to the object
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be modified from
+//
+////////////////////////////////////////////////////////////////////////////////
+inline const MyMoneyMoney& MyMoneyMoney::operator=(const MyMoneyMoney& Amount)
+{
+ m_num = Amount.m_num;
+ m_denom = Amount.m_denom;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator=
+// Purpose: Assignment operator - modifies object from input NULL terminated
+// string
+// Returns: Const reference to the object
+// Throws: Nothing.
+// Arguments: pszAmount - NULL terminated string that contains amount
+//
+////////////////////////////////////////////////////////////////////////////////
+inline const MyMoneyMoney& MyMoneyMoney::operator=(const QString& pszAmount)
+{
+ *this = MyMoneyMoney( pszAmount );
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator==
+// Purpose: Compare equal operator - compares object with input MyMoneyMoney object
+// Returns: true if equal, otherwise false
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be compared with
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator==(const MyMoneyMoney& Amount) const
+{
+ if(m_denom == Amount.m_denom)
+ return m_num == Amount.m_num;
+
+ if(m_num == 0 && Amount.m_num == 0)
+ return true;
+
+ return (*this - Amount).m_num == 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator!=
+// Purpose: Compare not equal operator - compares object with input MyMoneyMoney object
+// Returns: true if not equal, otherwise false
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be compared with
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator!=(const MyMoneyMoney& Amount) const
+{
+ if(m_num == Amount.m_num && m_denom == Amount.m_denom)
+ return false;
+
+ return (*this - Amount).m_num != 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator<
+// Purpose: Compare less than operator - compares object with input MyMoneyMoney object
+// Returns: true if object less than input amount
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be compared with
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator<(const MyMoneyMoney& Amount) const
+{
+ if(m_denom == Amount.m_denom)
+ return (m_num < Amount.m_num);
+
+ signed64 ab, ba;
+
+ ab = m_num * Amount.m_denom;
+ ba = m_denom * Amount.m_num;
+
+ return ( ab < ba ) ;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator>
+// Purpose: Compare greater than operator - compares object with input MyMoneyMoney
+// object
+// Returns: true if object greater than input amount
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be compared with
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator>(const MyMoneyMoney& Amount) const
+{
+ if(m_denom == Amount.m_denom)
+ return (m_num > Amount.m_num);
+
+ signed64 ab, ba;
+
+ ab = m_num * Amount.m_denom;
+ ba = m_denom * Amount.m_num;
+
+ return ( ab > ba ) ;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator<=
+// Purpose: Compare less than equal to operator - compares object with input
+// MyMoneyMoney object
+// Returns: true if object less than or equal to input amount
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be compared with
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator<=(const MyMoneyMoney& Amount) const
+{
+ if(m_denom == Amount.m_denom)
+ return (m_num <= Amount.m_num);
+
+ signed64 ab, ba;
+
+ ab = m_num * Amount.m_denom;
+ ba = m_denom * Amount.m_num;
+
+ return ( ab <= ba ) ;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator>=
+// Purpose: Compare greater than equal to operator - compares object with input
+// MyMoneyMoney object
+// Returns: true if object greater than or equal to input amount
+// Throws: Nothing.
+// Arguments: Amount - MyMoneyMoney object to be compared with
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator>=(const MyMoneyMoney& Amount) const
+{
+ if(m_denom == Amount.m_denom)
+ return (m_num >= Amount.m_num);
+
+ signed64 ab, ba;
+
+ ab = m_num * Amount.m_denom;
+ ba = m_denom * Amount.m_num;
+
+ return ( ab >= ba ) ;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator==
+// Purpose: Compare equal operator - compares object with input amount in a
+// NULL terminated string
+// Returns: true if equal, otherwise false
+// Throws: Nothing.
+// Arguments: pszAmount - NULL terminated string that contains amount
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator==(const QString& pszAmount) const
+{
+ MyMoneyMoney Amount( pszAmount );
+ return ( *this == Amount ) ;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator!=
+// Purpose: Compare not equal operator - compares object with input amount in
+// a NULL terminated string
+// Returns: true if not equal, otherwise false
+// Throws: Nothing.
+// Arguments: pszAmount - NULL terminated string that contains amount
+//
+////////////////////////////////////////////////////////////////////////////////
+inline bool MyMoneyMoney::operator!=(const QString& pszAmount) const
+{
+ MyMoneyMoney Amount( pszAmount );
+ return ( *this != Amount ) ;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator-
+// Purpose: Unary operator - returns the negative value from the object
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: None
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney MyMoneyMoney::operator-() const
+{
+ MyMoneyMoney result(*this);
+ result.m_num = -result.m_num;
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator*
+// Purpose: Multiplication operator - multiplies the object with factor
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: AmountInPence - signed64 object to be multiplied
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney MyMoneyMoney::operator*(signed64 factor) const
+{
+ MyMoneyMoney result(*this);
+ result.m_num *= factor;
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator*
+// Purpose: Multiplication operator - multiplies the object with factor
+// Returns: The current object
+// Throws: Nothing.
+// Arguments: AmountInPence - long object to be multiplied
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney MyMoneyMoney::operator*(int factor) const
+{
+ MyMoneyMoney result(*this);
+ result.m_num *= factor;
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator+=
+// Purpose: Addition operator - adds the input amount to the object together
+// Returns: Reference to the current object
+// Throws: Nothing.
+// Arguments: AmountInPence - MyMoneyMoney object to be added
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney& MyMoneyMoney::operator+=(const MyMoneyMoney& AmountInPence)
+{
+ *this = *this + AmountInPence;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name: operator-=
+// Purpose: Subtraction operator - subtracts the input amount from the object
+// Returns: Reference to the current object
+// Throws: Nothing.
+// Arguments: AmountInPence - MyMoneyMoney object to be subtracted
+//
+////////////////////////////////////////////////////////////////////////////////
+inline MyMoneyMoney& MyMoneyMoney::operator-=(const MyMoneyMoney& AmountInPence)
+{
+ *this = *this - AmountInPence;
+ return *this;
+}
+
+inline MyMoneyMoney& MyMoneyMoney::operator/=(const MyMoneyMoney& AmountInPence)
+{
+ *this = *this / AmountInPence;
+ return *this;
+}
+
+#endif
+
diff --git a/kmymoney2/mymoney/mymoneymoneytest.cpp b/kmymoney2/mymoney/mymoneymoneytest.cpp
new file mode 100644
index 0000000..64c2961
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneymoneytest.cpp
@@ -0,0 +1,591 @@
+/***************************************************************************
+ mymoneymoneytest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// make sure, that this is defined before we even include any other header file
+#ifndef __STDC_LIMIT_MACROS
+ #define __STDC_LIMIT_MACROS // force definition of min and max values
+#endif
+
+#include "mymoneymoneytest.h"
+#include "mymoneyexception.h"
+#include <iostream>
+#include <stdint.h>
+
+// make sure, we have the correct suffix
+#if SIZEOF_LONG == 8
+#define LLCONST(a) a ## L
+#else
+#define LLCONST(a) a ## LL
+#endif
+
+MyMoneyMoneyTest::MyMoneyMoneyTest()
+{
+}
+
+
+void MyMoneyMoneyTest::setUp()
+{
+ m_0 = new MyMoneyMoney(12);
+ m_1 = new MyMoneyMoney(-10);
+ m_2 = new MyMoneyMoney(2);
+ m_3 = new MyMoneyMoney(123,1);
+ m_4 = new MyMoneyMoney(1234,1000);
+ m_5 = new MyMoneyMoney(195883,100000);
+
+ MyMoneyMoney::setDecimalSeparator('.');
+ MyMoneyMoney::setThousandSeparator(',');
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+}
+
+void MyMoneyMoneyTest::tearDown()
+{
+ delete m_0;
+ delete m_1;
+ delete m_2;
+ delete m_3;
+ delete m_4;
+ delete m_5;
+}
+
+void MyMoneyMoneyTest::testEmptyConstructor()
+{
+ MyMoneyMoney *m = new MyMoneyMoney();
+ CPPUNIT_ASSERT(m->m_num == 0);
+ CPPUNIT_ASSERT(m->m_denom == 1);
+ delete m;
+}
+
+void MyMoneyMoneyTest::testIntConstructor()
+{
+ CPPUNIT_ASSERT(m_0->m_num == 12);
+ CPPUNIT_ASSERT(m_0->m_denom == 100);
+
+ MyMoneyMoney a(123, 10000);
+ CPPUNIT_ASSERT(a.m_num == 123);
+ CPPUNIT_ASSERT(a.m_denom == 10000);
+}
+
+void MyMoneyMoneyTest::testAssignment()
+{
+ MyMoneyMoney *m = new MyMoneyMoney();
+ *m = *m_1;
+ CPPUNIT_ASSERT(m->m_num == -10);
+ CPPUNIT_ASSERT(m->m_denom == 100);
+#if 0
+ *m = 0;
+ CPPUNIT_ASSERT(m->m_num == 0);
+ CPPUNIT_ASSERT(m->m_denom == 100);
+
+ *m = 777888999;
+ CPPUNIT_ASSERT(m->m_num == 777888999);
+ CPPUNIT_ASSERT(m->m_denom == 100);
+
+ *m = (int)-5678;
+ CPPUNIT_ASSERT(m->m_num == -5678);
+ CPPUNIT_ASSERT(m->m_denom == 100);
+
+ *m = QString("-987");
+ CPPUNIT_ASSERT(m->m_num == -987);
+ CPPUNIT_ASSERT(m->m_denom == 1);
+
+ *m = QString("9998887776665554.44");
+ CPPUNIT_ASSERT(m->m_num == 999888777666555444LL);
+ CPPUNIT_ASSERT(m->m_denom == 100);
+
+ *m = QString("-99988877766655.444");
+ CPPUNIT_ASSERT(m->m_num == -99988877766655444LL);
+ CPPUNIT_ASSERT(m->m_denom == 1000);
+
+ *m = -666555444333222111LL;
+ CPPUNIT_ASSERT(m->m_num == -666555444333222111LL);
+ CPPUNIT_ASSERT(m->m_denom == 100);
+#endif
+ delete m;
+}
+
+void MyMoneyMoneyTest::testStringConstructor()
+{
+ MyMoneyMoney *m1 = new MyMoneyMoney("-999666555444");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(-999666555444));
+ CPPUNIT_ASSERT(m1->m_denom == 1);
+
+ MyMoneyMoney *m2 = new MyMoneyMoney("4445556669.99");
+ CPPUNIT_ASSERT(m2->m_num == LLCONST(444555666999));
+ CPPUNIT_ASSERT(m2->m_denom == 100);
+
+ delete m1;
+ delete m2;
+
+ m1 = new MyMoneyMoney("");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(0));
+ CPPUNIT_ASSERT(m1->m_denom == 1);
+ delete m1;
+
+ m1 = new MyMoneyMoney("1,123.");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(1123));
+ CPPUNIT_ASSERT(m1->m_denom == 1);
+ delete m1;
+
+ m1 = new MyMoneyMoney("123.1");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(1231));
+ CPPUNIT_ASSERT(m1->m_denom == 10);
+ delete m1;
+
+ m1 = new MyMoneyMoney("123.456");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(123456));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+
+ m1 = new MyMoneyMoney("12345/100");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(12345));
+ CPPUNIT_ASSERT(m1->m_denom == 100);
+ delete m1;
+
+ MyMoneyMoney::setDecimalSeparator(',');
+ MyMoneyMoney::setThousandSeparator('.');
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::ParensAround);
+ m1 = new MyMoneyMoney("x1.234,567 EUR");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(1234567));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+
+ m1 = new MyMoneyMoney("x(1.234,567) EUR");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(-1234567));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+
+ m1 = new MyMoneyMoney("1 5/8");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(13));
+ CPPUNIT_ASSERT(m1->m_denom == 8);
+ delete m1;
+}
+
+void MyMoneyMoneyTest::testConvert()
+{
+ MyMoneyMoney a("123.456");
+ MyMoneyMoney b = a.convert(100);
+ CPPUNIT_ASSERT(b.m_num == 12346);
+ CPPUNIT_ASSERT(b.m_denom == 100);
+ a = QString("-123.456");
+ b = a.convert(100);
+ CPPUNIT_ASSERT(b.m_num == -12346);
+ CPPUNIT_ASSERT(b.m_denom == 100);
+
+ a = QString("123.1");
+ b = a.convert(100);
+ CPPUNIT_ASSERT(b.m_num == 12310);
+ CPPUNIT_ASSERT(b.m_denom == 100);
+
+ a = QString("-73010.28");
+ b = QString("1.95583");
+ CPPUNIT_ASSERT((a * b).convert(100) == QString("-142795.70"));
+
+ a = QString("-142795.69");
+ CPPUNIT_ASSERT((a / b).convert(100) == QString("-73010.28"));
+}
+
+void MyMoneyMoneyTest::testEquality()
+{
+ CPPUNIT_ASSERT (*m_1 == *m_1);
+ CPPUNIT_ASSERT (!(*m_1 == *m_0));
+
+ MyMoneyMoney m1(LLCONST(999666555444));
+ MyMoneyMoney m2(LLCONST(999666555444));
+ CPPUNIT_ASSERT(m1 == m2);
+
+ MyMoneyMoney m3(LLCONST(-999666555444));
+ MyMoneyMoney m4(LLCONST(-999666555444));
+ CPPUNIT_ASSERT(m3 == m4);
+
+ MyMoneyMoney m5(1230,100);
+ MyMoneyMoney m6(123,10);
+ MyMoneyMoney m7(246,20);
+ CPPUNIT_ASSERT(m5 == m6);
+ CPPUNIT_ASSERT(m5 == m7);
+
+ CPPUNIT_ASSERT(m5 == QString("369/30"));
+
+ CPPUNIT_ASSERT(MyMoneyMoney::autoCalc == MyMoneyMoney::autoCalc);
+}
+
+void MyMoneyMoneyTest::testInequality()
+{
+ CPPUNIT_ASSERT (*m_1 != *m_0);
+ CPPUNIT_ASSERT (!(*m_1 != *m_1));
+
+ MyMoneyMoney m1(LLCONST(999666555444));
+ MyMoneyMoney m2(LLCONST(-999666555444));
+ CPPUNIT_ASSERT(m1 != m2);
+
+ MyMoneyMoney m3(LLCONST(-999666555444));
+ MyMoneyMoney m4(LLCONST(999666555444));
+ CPPUNIT_ASSERT(m3 != m4);
+
+ CPPUNIT_ASSERT(m4 != QString("999666555444"));
+
+ CPPUNIT_ASSERT(MyMoneyMoney::autoCalc != MyMoneyMoney(1,100));
+ CPPUNIT_ASSERT(MyMoneyMoney(1,100) != MyMoneyMoney::autoCalc);
+}
+
+
+void MyMoneyMoneyTest::testAddition()
+{
+ CPPUNIT_ASSERT (*m_0 + *m_1 == *m_2);
+
+ MyMoneyMoney m1(100);
+
+ // CPPUNIT_ASSERT((m1 + 50) == MyMoneyMoney(51,1));
+ // CPPUNIT_ASSERT((m1 + 1000000000) == MyMoneyMoney(1000000001,1));
+ // CPPUNIT_ASSERT((m1 + -50) == MyMoneyMoney(-49,1));
+
+ CPPUNIT_ASSERT((m1 += *m_0) == MyMoneyMoney(112));
+ // CPPUNIT_ASSERT((m1 += -12) == MyMoneyMoney(100));
+
+ // m1++;
+ // CPPUNIT_ASSERT(m1 == MyMoneyMoney(101));
+ // CPPUNIT_ASSERT((++m1) == MyMoneyMoney(102));
+
+ m1 = QString("123.20");
+ MyMoneyMoney m2(40, 1000);
+ CPPUNIT_ASSERT((m1 + m2) == QString("123.24"));
+
+ m1 += m2;
+ CPPUNIT_ASSERT(m1.m_num == 123240);
+ CPPUNIT_ASSERT(m1.m_denom == 1000);
+}
+
+void MyMoneyMoneyTest::testSubtraction()
+{
+ CPPUNIT_ASSERT (*m_2 - *m_1 == *m_0);
+
+ MyMoneyMoney m1(100);
+
+ // CPPUNIT_ASSERT((m1-50) == MyMoneyMoney(-49,1));
+ // CPPUNIT_ASSERT((m1-1000000000) == MyMoneyMoney(-999999999,1));
+ // CPPUNIT_ASSERT((m1 - -50) == MyMoneyMoney(51,1));
+
+ CPPUNIT_ASSERT((m1 -= *m_0) == MyMoneyMoney(88));
+ // CPPUNIT_ASSERT((m1 -= -12) == MyMoneyMoney(100));
+
+ // m1--;
+ // CPPUNIT_ASSERT(m1 == MyMoneyMoney(99));
+ // CPPUNIT_ASSERT((--m1) == MyMoneyMoney(98));
+
+ m1 = QString("123.20");
+ MyMoneyMoney m2(1, 5);
+ CPPUNIT_ASSERT((m1 - m2) == MyMoneyMoney(123,1));
+
+ m1 -= m2;
+ CPPUNIT_ASSERT(m1.m_num == 12300);
+ CPPUNIT_ASSERT(m1.m_denom == 100);
+}
+
+void MyMoneyMoneyTest::testMultiplication()
+{
+ MyMoneyMoney m1(100,1);
+
+ CPPUNIT_ASSERT((m1 * MyMoneyMoney(50,1)) == MyMoneyMoney(5000,1));
+ CPPUNIT_ASSERT((m1 * MyMoneyMoney(10000000,1)) == MyMoneyMoney(1000000000,1));
+ CPPUNIT_ASSERT((m1 * (*m_0)) == MyMoneyMoney(1200));
+
+ MyMoneyMoney m2 = QString("-73010.28");
+ m1 = QString("1.95583");
+ CPPUNIT_ASSERT((m1 * m2) == QString("-142795.6959324"));
+}
+
+void MyMoneyMoneyTest::testDivision()
+{
+ MyMoneyMoney m1(100);
+ CPPUNIT_ASSERT((m1 / MyMoneyMoney(50)) == MyMoneyMoney(2,1));
+
+ MyMoneyMoney m2 = QString("-142795.69");
+ m1 = QString("1.95583");
+ CPPUNIT_ASSERT((m2 / m1).convert(100000000) == QString("-73010.27696681"));
+
+ MyMoneyMoney m3 = MyMoneyMoney(0) / MyMoneyMoney(100);
+ CPPUNIT_ASSERT(m3.m_num == 0);
+ CPPUNIT_ASSERT(m3.m_denom != 0);
+}
+
+void MyMoneyMoneyTest::testSetDecimalSeparator()
+{
+ MyMoneyMoney m1(100000);
+ MyMoneyMoney m2(200000);
+
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("1,000.00"));
+ CPPUNIT_ASSERT(MyMoneyMoney::decimalSeparator() == '.');
+
+ MyMoneyMoney::setDecimalSeparator(':');
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("1,000:00"));
+ CPPUNIT_ASSERT(m2.formatMoney("", 2) == QString("2,000:00"));
+
+ CPPUNIT_ASSERT(MyMoneyMoney::decimalSeparator() == ':');
+}
+
+void MyMoneyMoneyTest::testSetThousandSeparator()
+{
+ MyMoneyMoney m1(100000);
+ MyMoneyMoney m2(200000);
+
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("1,000.00"));
+ CPPUNIT_ASSERT(MyMoneyMoney::thousandSeparator() == ',');
+
+ MyMoneyMoney::setThousandSeparator(':');
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("1:000.00"));
+ CPPUNIT_ASSERT(m2.formatMoney("", 2) == QString("2:000.00"));
+
+ CPPUNIT_ASSERT(MyMoneyMoney::thousandSeparator() == ':');
+}
+
+void MyMoneyMoneyTest::testFormatMoney()
+{
+ CPPUNIT_ASSERT(m_0->formatMoney("", 2) == QString("0.12"));
+ CPPUNIT_ASSERT(m_1->formatMoney("", 2) == QString("-0.10"));
+
+ MyMoneyMoney m1(10099);
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("100.99"));
+
+ m1 = MyMoneyMoney(100,1);
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("100.00"));
+ CPPUNIT_ASSERT(m1.formatMoney("", -1) == QString("100"));
+
+ m1 = m1 * 10;
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("1,000.00"));
+ CPPUNIT_ASSERT(m1.formatMoney("", -1) == QString("1,000"));
+ CPPUNIT_ASSERT(m1.formatMoney("", -1, false) == QString("1000"));
+ CPPUNIT_ASSERT(m1.formatMoney("", 3, false) == QString("1000.000"));
+
+ m1 = MyMoneyMoney(INT64_MAX, 100);
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("92,233,720,368,547,758.07"));
+ CPPUNIT_ASSERT(m1.formatMoney(100) == QString("92,233,720,368,547,758.07"));
+ CPPUNIT_ASSERT(m1.formatMoney("", 2, false) == QString("92233720368547758.07"));
+ CPPUNIT_ASSERT(m1.formatMoney(100, false) == QString("92233720368547758.07"));
+
+ m1 = MyMoneyMoney(INT64_MIN, 100);
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("-92,233,720,368,547,758.08"));
+ CPPUNIT_ASSERT(m1.formatMoney(100) == QString("-92,233,720,368,547,758.08"));
+ CPPUNIT_ASSERT(m1.formatMoney("", 2, false) == QString("-92233720368547758.08"));
+ CPPUNIT_ASSERT(m1.formatMoney(100, false) == QString("-92233720368547758.08"));
+
+ m1 = MyMoneyMoney(1,5);
+ CPPUNIT_ASSERT(m1.formatMoney("", 2) == QString("0.20"));
+ CPPUNIT_ASSERT(m1.formatMoney(1000) == QString("0.200"));
+ CPPUNIT_ASSERT(m1.formatMoney(100) == QString("0.20"));
+ CPPUNIT_ASSERT(m1.formatMoney(10) == QString("0.2"));
+
+ m1 = MyMoneyMoney(13333,5000);
+ CPPUNIT_ASSERT(m1.formatMoney("", 10) == QString("2.6666000000"));
+
+ m1 = MyMoneyMoney(-1404,100);
+ CPPUNIT_ASSERT(m1.formatMoney("",-1) == QString("-14.04"));
+}
+
+void MyMoneyMoneyTest::testRelation()
+{
+ MyMoneyMoney m1(100);
+ MyMoneyMoney m2(50);
+ MyMoneyMoney m3(100);
+
+ // tests with same denominator
+ CPPUNIT_ASSERT(m1 > m2);
+ CPPUNIT_ASSERT(m2 < m1);
+
+ CPPUNIT_ASSERT(m1 <= m3);
+ CPPUNIT_ASSERT(m3 >= m1);
+ CPPUNIT_ASSERT(m1 <= m1);
+ CPPUNIT_ASSERT(m3 >= m3);
+
+ // tests with different denominator
+ m1 = QString("1/8");
+ m2 = QString("1/7");
+ CPPUNIT_ASSERT(m1 < m2);
+ CPPUNIT_ASSERT(m2 > m1);
+ m2 = QString("-1/7");
+ CPPUNIT_ASSERT(m2 < m1);
+ CPPUNIT_ASSERT(m1 > m2);
+ CPPUNIT_ASSERT(m1 >= m2);
+ CPPUNIT_ASSERT(m2 <= m1);
+
+ m1 = QString("-2/14");
+ CPPUNIT_ASSERT(m1 >= m2);
+ CPPUNIT_ASSERT(m1 <= m2);
+
+}
+
+void MyMoneyMoneyTest::testUnaryMinus()
+{
+ MyMoneyMoney m1(100);
+ MyMoneyMoney m2;
+
+ m2 = -m1;
+
+ CPPUNIT_ASSERT(m1 == MyMoneyMoney(100));
+ CPPUNIT_ASSERT(m2 == MyMoneyMoney(-100));
+}
+
+void MyMoneyMoneyTest::testDoubleConstructor()
+{
+ for(int i = -123456; i < 123456; ++i) {
+ double d = i;
+ MyMoneyMoney r(i);
+ d /= 100;
+ MyMoneyMoney t(d);
+ CPPUNIT_ASSERT(t == r);
+ }
+}
+
+void MyMoneyMoneyTest::testAbsoluteFunction()
+{
+ MyMoneyMoney m1(-100);
+ MyMoneyMoney m2(100);
+
+ CPPUNIT_ASSERT(m2.abs() == MyMoneyMoney(100));
+ CPPUNIT_ASSERT(m1.abs() == MyMoneyMoney(100));
+}
+
+void MyMoneyMoneyTest::testToString()
+{
+ MyMoneyMoney m1(-100);
+ MyMoneyMoney m2(1234);
+ MyMoneyMoney m3;
+
+ CPPUNIT_ASSERT(m1.toString() == QString("-100/100"));
+ CPPUNIT_ASSERT(m2.toString() == QString("1234/100"));
+ CPPUNIT_ASSERT(m3.toString() == QString("0/1"));
+}
+
+void MyMoneyMoneyTest::testNegativeSignPos(void)
+{
+ MyMoneyMoney m("-123456/100");
+
+ MyMoneyMoney::signPosition pos = MyMoneyMoney::negativeMonetarySignPosition();
+
+ MyMoneyMoney::setNegativePrefixCurrencySymbol(false);
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::ParensAround);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "(1,234.56) CUR");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "-1,234.56 CUR");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::AfterQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56- CUR");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56 -CUR");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::AfterMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56 CUR-");
+
+ MyMoneyMoney::setNegativePrefixCurrencySymbol(true);
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::ParensAround);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR (1,234.56)");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR -1,234.56");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::AfterQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR 1,234.56-");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "-CUR 1,234.56");
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::AfterMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR- 1,234.56");
+
+ MyMoneyMoney::setNegativeMonetarySignPosition(pos);
+}
+
+void MyMoneyMoneyTest::testPositiveSignPos(void)
+{
+ MyMoneyMoney m("123456/100");
+
+ MyMoneyMoney::signPosition pos = MyMoneyMoney::positiveMonetarySignPosition();
+
+ MyMoneyMoney::setPositivePrefixCurrencySymbol(false);
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::ParensAround);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "(1,234.56) CUR");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56 CUR");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::AfterQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56 CUR");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::BeforeMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56 CUR");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::AfterMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "1,234.56 CUR");
+
+ MyMoneyMoney::setPositivePrefixCurrencySymbol(true);
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::ParensAround);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR (1,234.56)");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR 1,234.56");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::AfterQuantityMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR 1,234.56");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::BeforeMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR 1,234.56");
+ MyMoneyMoney::setPositiveMonetarySignPosition(MyMoneyMoney::AfterMoney);
+ CPPUNIT_ASSERT(m.formatMoney("CUR", 2) == "CUR 1,234.56");
+
+ MyMoneyMoney::setPositiveMonetarySignPosition(pos);
+}
+
+void MyMoneyMoneyTest::testNegativeStringConstructor(void)
+{
+ MyMoneyMoney *m1;
+ MyMoneyMoney::setDecimalSeparator(',');
+ MyMoneyMoney::setThousandSeparator('.');
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::ParensAround);
+ m1 = new MyMoneyMoney("x(1.234,567) EUR");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(-1234567));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+ MyMoneyMoney::setNegativeMonetarySignPosition(MyMoneyMoney::BeforeQuantityMoney);
+ m1 = new MyMoneyMoney("x1.234,567- EUR");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(-1234567));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+ m1 = new MyMoneyMoney("x1.234,567 -EUR");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(-1234567));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+ m1 = new MyMoneyMoney("-1.234,567 EUR");
+ CPPUNIT_ASSERT(m1->m_num == LLCONST(-1234567));
+ CPPUNIT_ASSERT(m1->m_denom == 1000);
+ delete m1;
+}
+
+void MyMoneyMoneyTest::testReduce(void)
+{
+ MyMoneyMoney a(36488100, 1267390000);
+ MyMoneyMoney b(-a);
+
+ a = a.reduce();
+ CPPUNIT_ASSERT(a.m_num == 364881);
+ CPPUNIT_ASSERT(a.m_denom == 12673900);
+
+ b = b.reduce();
+ CPPUNIT_ASSERT(b.m_num == -364881);
+ CPPUNIT_ASSERT(b.m_denom == 12673900);
+}
+
+void MyMoneyMoneyTest::testZeroDenominator()
+{
+ try {
+ MyMoneyMoney m((int)1, 0);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ MyMoneyMoney m((signed64)1, 0);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
diff --git a/kmymoney2/mymoney/mymoneymoneytest.h b/kmymoney2/mymoney/mymoneymoneytest.h
new file mode 100644
index 0000000..ffb2c0e
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneymoneytest.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ mymoneymoneytest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYMONEYTEST_H__
+#define __MYMONEYMONEYTEST_H__
+
+// Check for standard definitions
+#ifdef HAVE_STDINT_H
+ #ifndef __STDC_LIMIT_MACROS
+ #define __STDC_LIMIT_MACROS // force definition of min and max values
+ #endif
+ #include <stdint.h>
+#else
+ #include <limits.h>
+ #define INT64_MAX LLONG_MAX
+ #define INT64_MIN LLONG_MIN
+#endif
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneymoney.h"
+#undef private
+
+class MyMoneyMoneyTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyMoneyTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testIntConstructor);
+ CPPUNIT_TEST(testStringConstructor);
+ CPPUNIT_TEST(testAssignment);
+ CPPUNIT_TEST(testConvert);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST(testInequality);
+ CPPUNIT_TEST(testAddition);
+ CPPUNIT_TEST(testSubtraction);
+ CPPUNIT_TEST(testMultiplication);
+ CPPUNIT_TEST(testDivision);
+ CPPUNIT_TEST(testSetDecimalSeparator);
+ CPPUNIT_TEST(testSetThousandSeparator);
+ CPPUNIT_TEST(testFormatMoney);
+ CPPUNIT_TEST(testRelation);
+ CPPUNIT_TEST(testUnaryMinus);
+ CPPUNIT_TEST(testDoubleConstructor);
+ CPPUNIT_TEST(testAbsoluteFunction);
+ CPPUNIT_TEST(testToString);
+ CPPUNIT_TEST(testNegativeSignPos);
+ CPPUNIT_TEST(testPositiveSignPos);
+ CPPUNIT_TEST(testNegativeStringConstructor);
+ CPPUNIT_TEST(testReduce);
+ CPPUNIT_TEST(testZeroDenominator);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyMoney *m_0, *m_1, *m_2, *m_3, *m_4, *m_5;
+public:
+ MyMoneyMoneyTest();
+
+ void setUp();
+ void tearDown();
+ void testEmptyConstructor();
+ void testIntConstructor();
+ void testStringConstructor();
+ void testAssignment();
+ void testConvert();
+ void testEquality();
+ void testInequality();
+ void testAddition();
+ void testSubtraction();
+ void testMultiplication();
+ void testDivision();
+ void testFormatMoney();
+ void testSetDecimalSeparator();
+ void testSetThousandSeparator();
+ void testRelation();
+ void testUnaryMinus();
+ void testDoubleConstructor();
+ void testAbsoluteFunction();
+ void testToString();
+ void testNegativeSignPos();
+ void testPositiveSignPos();
+ void testNegativeStringConstructor();
+ void testReduce();
+ void testZeroDenominator();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyobject.cpp b/kmymoney2/mymoney/mymoneyobject.cpp
new file mode 100644
index 0000000..7939ff0
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobject.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ mymoneyobject.cpp
+ -------------------
+ copyright : (C) 2005 by Thomas Baumagrt
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyobject.h"
+#include "mymoneyutils.h"
+#include "mymoneyexception.h"
+
+const QString MyMoneyObject::m_emptyId;
+
+MyMoneyObject::MyMoneyObject(const QString& id)
+{
+ m_id = id;
+}
+
+MyMoneyObject::MyMoneyObject(const QDomElement& el, const bool forceId)
+{
+ m_id = QStringEmpty(el.attribute("id"));
+ if(m_id.length() == 0 && forceId)
+ throw new MYMONEYEXCEPTION("Node has no ID");
+}
+
+MyMoneyObject::MyMoneyObject()
+{
+}
+
+MyMoneyObject::~MyMoneyObject()
+{
+}
+
+void MyMoneyObject::setId(const QString& id)
+{
+ m_id = id;
+}
+
+bool MyMoneyObject::operator == (const MyMoneyObject& right) const
+{
+ return m_id == right.m_id;
+}
+
+void MyMoneyObject::clearId(void)
+{
+ m_id = QString();
+}
+
+const QString& MyMoneyObject::emptyId(void)
+{
+ return m_emptyId;
+}
+
+void MyMoneyObject::writeBaseXML(QDomDocument& document, QDomElement& el) const
+{
+ Q_UNUSED(document);
+
+ el.setAttribute("id", m_id);
+}
diff --git a/kmymoney2/mymoney/mymoneyobject.h b/kmymoney2/mymoney/mymoneyobject.h
new file mode 100644
index 0000000..d07296b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobject.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ mymoneyobject.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYOBJECT_H
+#define MYMONEYOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdom.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents the base class of all MyMoney objects.
+ */
+class KMYMONEY_EXPORT MyMoneyObject
+{
+public:
+ /**
+ * This is the constructor for the MyMoneyObject object
+ */
+ MyMoneyObject();
+
+ /**
+ * This is the destructor for the MyMoneyObject object
+ */
+ virtual ~MyMoneyObject();
+
+ /**
+ * This method retrieves the id of the object
+ *
+ * @return ID of object
+ */
+ const QString& id(void) const { return m_id; };
+
+ /**
+ * This method clears the id of the object
+ */
+ void clearId(void);
+
+ /**
+ * This method must be provided by all derived objects. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const = 0;
+
+ /**
+ * This method creates a QDomElement for the @p document
+ * under the parent node @p parent.
+ *
+ * @param document reference to QDomDocument
+ * @param parent reference to QDomElement parent node
+ */
+ virtual void writeXML(QDomDocument& document, QDomElement& parent) const = 0;
+
+ bool operator == (const MyMoneyObject& right) const;
+
+ static const QString& emptyId(void);
+
+protected:
+ /**
+ * This contructor assigns the id to the MyMoneyObject
+ *
+ * @param id ID of object
+ */
+ MyMoneyObject(const QString& id);
+
+ /**
+ * This contructor reads the id from the @p id attribute of the
+ * QDomElement.
+ *
+ * @param node const reference to the QDomElement from which to
+ * obtain the id of the object
+ * @param forceId flag to be able to suppress enforcement of an id
+ * defaults to true which requires the node to have an
+ * attribute with name @p id. If it does not contain such
+ * an attribute, an exception will be thrown. If @p forceId
+ * is false, no check for an id is performed. This will be
+ * used by objects, which are stored w/o id (eg. splits,
+ * transactions within schedules)
+ */
+ MyMoneyObject(const QDomElement& node, const bool forceId = true);
+
+ void setId(const QString& id) /* __attribute__ ((deprecated)) */;
+
+ /**
+ * This method writes out the members contained in this object.
+ */
+ void writeBaseXML(QDomDocument& document, QDomElement& el) const;
+
+protected:
+ QString m_id;
+ static const QString m_emptyId;
+};
+
+#endif
+
diff --git a/kmymoney2/mymoney/mymoneyobjectcontainer.cpp b/kmymoney2/mymoney/mymoneyobjectcontainer.cpp
new file mode 100644
index 0000000..666da3b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobjectcontainer.cpp
@@ -0,0 +1,218 @@
+/***************************************************************************
+ mymoneyobjectcontainer.cpp
+ -------------------
+ copyright : (C) 2006 by Thomas Baumagrt
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyobjectcontainer.h>
+
+MyMoneyObjectContainer::MyMoneyObjectContainer()
+{
+}
+
+MyMoneyObjectContainer::~MyMoneyObjectContainer()
+{
+ clear();
+}
+
+void MyMoneyObjectContainer::clear(IMyMoneyStorage* storage)
+{
+ // delete all objects
+ QMap<QString, MyMoneyObject const *>::const_iterator it;
+ for(it = m_map.begin(); it != m_map.end(); ++it) {
+ delete (*it);
+ }
+
+ // then delete the pointers to them
+ m_map.clear();
+
+ if(storage)
+ m_storage = storage;
+}
+
+void MyMoneyObjectContainer::clear(const QString& id)
+{
+ QMap<QString, MyMoneyObject const *>::iterator it;
+ it = m_map.find(id);
+ if(it != m_map.end()) {
+ delete (*it);
+ m_map.erase(it);
+ }
+}
+
+#define listMethod(a, T) \
+void MyMoneyObjectContainer::a(QValueList<T>& list) \
+{ \
+ QMap<QString, const MyMoneyObject*>::const_iterator it; \
+ for(it = m_map.begin(); it != m_map.end(); ++it) { \
+ const T* node = dynamic_cast<const T*>(*it); \
+ if(node) { \
+ list.append(*node); \
+ } \
+ } \
+}
+
+#define preloadListMethod(a, T) \
+void MyMoneyObjectContainer::preload##a(const QValueList<T>& list) \
+{ \
+ QValueList<T>::const_iterator it; \
+ for(it = list.begin(); it != list.end(); ++it) { \
+ delete m_map[(*it).id()]; \
+ m_map[(*it).id()] = new T(*it); \
+ } \
+}
+
+#define preloadMethod(a, T) \
+void MyMoneyObjectContainer::preload##a(const T& obj) \
+{ \
+ delete m_map[obj.id()]; \
+ m_map[obj.id()] = new T(obj); \
+}
+
+#define objectAccessMethod(a, T) \
+const T& MyMoneyObjectContainer::a(const QString& id) \
+{ \
+ static T nullElement; \
+ if(id.isEmpty()) \
+ return nullElement; \
+ QMap<QString, MyMoneyObject const *>::const_iterator it; \
+ it = m_map.find(id); \
+ if(it == m_map.end()) { \
+ /* not found, need to load from engine */ \
+ T x = m_storage->a(id); \
+ m_map[id] = new T(x); \
+ return dynamic_cast<const T&>(*m_map[id]); \
+ } \
+ return dynamic_cast<const T&>(*(*it)); \
+}
+
+void MyMoneyObjectContainer::account(QValueList<MyMoneyAccount>& list)
+{
+ QMap<QString, const MyMoneyObject*>::const_iterator it;
+ for(it = m_map.begin(); it != m_map.end(); ++it) {
+ const MyMoneyAccount* node = dynamic_cast<const MyMoneyAccount*>(*it);
+ if(node) {
+ assignFraction(const_cast<MyMoneyAccount*>(node));
+ list.append(*node);
+ }
+ }
+}
+
+const MyMoneyAccount& MyMoneyObjectContainer::account(const QString& id)
+{
+ static MyMoneyAccount nullElement;
+ if(id.isEmpty())
+ return nullElement;
+ QMap<QString, MyMoneyObject const *>::iterator it;
+ it = m_map.find(id);
+ if(it == m_map.end()) {
+ /* not found, need to load from engine */
+ MyMoneyAccount x = m_storage->account(id);
+ MyMoneyAccount* item = new MyMoneyAccount(x);
+ assignFraction(dynamic_cast<MyMoneyAccount*>(item));
+ m_map[id] = item;
+ return dynamic_cast<const MyMoneyAccount&>(*m_map[id]);
+ }
+ assignFraction(dynamic_cast<MyMoneyAccount*> (const_cast<MyMoneyObject*>(*it)));
+ return dynamic_cast<const MyMoneyAccount&>(*(*it));
+}
+
+void MyMoneyObjectContainer::assignFraction(MyMoneyAccount* acc)
+{
+ if(acc != 0 && acc->m_fraction == -1) {
+ const MyMoneySecurity& sec = security(acc->currencyId());
+ acc->fraction(sec);
+ }
+}
+
+const MyMoneyAccount& MyMoneyObjectContainer::accountByName(const QString& name) const
+{
+ static MyMoneyAccount nullElement;
+ QMap<QString, MyMoneyObject const *>::const_iterator it;
+ for(it = m_map.begin(); it != m_map.end(); ++it) {
+ const MyMoneyAccount* node = dynamic_cast<const MyMoneyAccount *>(*it);
+ if(node) {
+ if(node->name() == name)
+ return dynamic_cast<const MyMoneyAccount &>(*(*it));
+ }
+ }
+ return nullElement;
+}
+
+void MyMoneyObjectContainer::refresh(const QString& id)
+{
+ if(id.isEmpty())
+ return;
+
+ QMap<QString, MyMoneyObject const *>::const_iterator it;
+ it = m_map.find(id);
+ if(it != m_map.end()) {
+ const MyMoneyAccount* account = dynamic_cast<const MyMoneyAccount *>(*it);
+ const MyMoneyPayee* payee = dynamic_cast<const MyMoneyPayee *>(*it);
+ const MyMoneySecurity* security = dynamic_cast<const MyMoneySecurity *>(*it);
+ const MyMoneyInstitution* institution = dynamic_cast<const MyMoneyInstitution *>(*it);
+ const MyMoneySchedule* schedule = dynamic_cast<const MyMoneySchedule *>(*it);
+ delete *it;
+ if(account) {
+ const MyMoneyAccount& a = m_storage->account(id);
+ m_map[id] = new MyMoneyAccount(a);
+ } else if(security) {
+ const MyMoneySecurity& s = m_storage->security(id);
+ if(s.id().isEmpty()) {
+ const MyMoneySecurity& c = m_storage->currency(id);
+ m_map[id] = new MyMoneySecurity(c);
+ } else {
+ m_map[id] = new MyMoneySecurity(s);
+ }
+ } else if(payee) {
+ const MyMoneyPayee& p = m_storage->payee(id);
+ m_map[id] = new MyMoneyPayee(p);
+ } else if(institution) {
+ const MyMoneyInstitution& i = m_storage->institution(id);
+ m_map[id] = new MyMoneyInstitution(i);
+ } else if(schedule) {
+ const MyMoneySchedule& s = m_storage->schedule(id);
+ m_map[id] = new MyMoneySchedule(s);
+ } else {
+ qWarning("Ooops, should preload an unknown object with id '%s'", id.data());
+ }
+ return;
+ }
+}
+
+objectAccessMethod(schedule, MyMoneySchedule)
+objectAccessMethod(payee, MyMoneyPayee)
+objectAccessMethod(security, MyMoneySecurity)
+objectAccessMethod(institution, MyMoneyInstitution)
+
+preloadListMethod(Account, MyMoneyAccount)
+preloadListMethod(Payee, MyMoneyPayee)
+preloadListMethod(Institution, MyMoneyInstitution)
+preloadListMethod(Security, MyMoneySecurity)
+preloadListMethod(Schedule, MyMoneySchedule)
+
+preloadMethod(Account, MyMoneyAccount)
+preloadMethod(Security, MyMoneySecurity)
+preloadMethod(Payee, MyMoneyPayee)
+preloadMethod(Institution, MyMoneyInstitution)
+
+listMethod(payee, MyMoneyPayee)
+listMethod(institution, MyMoneyInstitution)
+
+#include "mymoneyobjectcontainer.moc"
diff --git a/kmymoney2/mymoney/mymoneyobjectcontainer.h b/kmymoney2/mymoney/mymoneyobjectcontainer.h
new file mode 100644
index 0000000..1f3b598
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobjectcontainer.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ mymoneyobjectcontainer.h
+ -------------------
+ copyright : (C) 2006 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYOBJECTCONTAINER_H
+#define MYMONEYOBJECTCONTAINER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/imymoneystorage.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents a generic container for all MyMoneyObject derived objects.
+ */
+class KMYMONEY_EXPORT MyMoneyObjectContainer : public QObject
+{
+ Q_OBJECT
+public:
+ MyMoneyObjectContainer();
+ ~MyMoneyObjectContainer();
+
+ const MyMoneyAccount& account(const QString& id);
+ const MyMoneyPayee& payee(const QString& id);
+ const MyMoneySecurity& security(const QString& id);
+ const MyMoneyInstitution& institution(const QString& id);
+ const MyMoneySchedule& schedule(const QString& id);
+
+ void account(QValueList<MyMoneyAccount>& list);
+ void payee(QValueList<MyMoneyPayee>& list);
+ void institution(QValueList<MyMoneyInstitution>& list);
+
+ void preloadAccount(const QValueList<MyMoneyAccount>& list);
+ void preloadPayee(const QValueList<MyMoneyPayee>& list);
+ void preloadInstitution(const QValueList<MyMoneyInstitution>& list);
+ void preloadSecurity(const QValueList<MyMoneySecurity>& list);
+ void preloadSchedule(const QValueList<MyMoneySchedule>& list);
+
+ void preloadAccount(const MyMoneyAccount& account);
+ void preloadSecurity(const MyMoneySecurity& security);
+ void preloadPayee(const MyMoneyPayee& payee);
+ void preloadInstitution(const MyMoneyInstitution& institution);
+
+ void clear(const QString& id);
+ void clear(IMyMoneyStorage* storage = 0);
+
+ const MyMoneyAccount& accountByName(const QString& name) const;
+
+ /**
+ * This method refreshes an already existing object in the container
+ * with a copy from the engine. The object is identified by its @a id.
+ * If the object is unknown or the @a id is empty, nothing is done.
+ */
+ void refresh(const QString& id);
+
+private:
+ void assignFraction(MyMoneyAccount* acc);
+
+private:
+ QMap<QString, MyMoneyObject const *> m_map;
+ IMyMoneyStorage* m_storage;
+};
+
+#endif
+
+
diff --git a/kmymoney2/mymoney/mymoneyobjecttest.cpp b/kmymoney2/mymoney/mymoneyobjecttest.cpp
new file mode 100644
index 0000000..f7201a9
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobjecttest.cpp
@@ -0,0 +1,73 @@
+/***************************************************************************
+ mymoneyobjecttest.cpp
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyobjecttest.h"
+#include "mymoneyaccount.h"
+
+MyMoneyObjectTest::MyMoneyObjectTest()
+{
+}
+
+
+void MyMoneyObjectTest::setUp () {
+}
+
+void MyMoneyObjectTest::tearDown () {
+}
+
+void MyMoneyObjectTest::testEmptyConstructor() {
+ MyMoneyAccount a;
+ CPPUNIT_ASSERT(a.id().isEmpty());
+}
+
+void MyMoneyObjectTest::testConstructor() {
+ MyMoneyAccount a(QString("thb"), MyMoneyAccount());
+
+ CPPUNIT_ASSERT(!a.id().isEmpty());
+ CPPUNIT_ASSERT(a.id() == QString("thb"));
+}
+
+void MyMoneyObjectTest::testClearId() {
+ MyMoneyAccount a(QString("thb"), MyMoneyAccount());
+
+ CPPUNIT_ASSERT(!a.id().isEmpty());
+ a.clearId();
+ CPPUNIT_ASSERT(a.id().isEmpty());
+}
+
+void MyMoneyObjectTest::testCopyConstructor() {
+ MyMoneyAccount a(QString("thb"), MyMoneyAccount());
+ MyMoneyAccount b(a);
+
+ CPPUNIT_ASSERT(a.MyMoneyObject::operator==(b));
+}
+
+void MyMoneyObjectTest::testAssignmentConstructor() {
+ MyMoneyAccount a(QString("thb"), MyMoneyAccount());
+ MyMoneyAccount b = a;
+
+ CPPUNIT_ASSERT(a.MyMoneyObject::operator==(b));
+}
+
+void MyMoneyObjectTest::testEquality() {
+ MyMoneyAccount a(QString("thb"), MyMoneyAccount());
+ MyMoneyAccount b(QString("thb"), MyMoneyAccount());
+ MyMoneyAccount c(QString("ace"), MyMoneyAccount());
+
+ CPPUNIT_ASSERT(a.MyMoneyObject::operator==(b));
+ CPPUNIT_ASSERT(!(a.MyMoneyObject::operator==(c)));
+}
+
diff --git a/kmymoney2/mymoney/mymoneyobjecttest.h b/kmymoney2/mymoney/mymoneyobjecttest.h
new file mode 100644
index 0000000..0b99671
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobjecttest.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ mymoneyobjecttest.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYOBJECTTEST_H__
+#define __MYMONEYOBJECTTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneyobject.h"
+#undef private
+
+class MyMoneyObjectTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyObjectTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST(testClearId);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testAssignmentConstructor);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+
+public:
+ MyMoneyObjectTest();
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testConstructor();
+ void testClearId();
+ void testCopyConstructor();
+ void testAssignmentConstructor();
+ void testEquality();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyobserver.cpp b/kmymoney2/mymoney/mymoneyobserver.cpp
new file mode 100644
index 0000000..f343003
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobserver.cpp
@@ -0,0 +1,30 @@
+/***************************************************************************
+ mymoneyobserver.cpp - description
+ -------------------
+ begin : Sat May 18 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyobserver.h"
+
+MyMoneyObserver::MyMoneyObserver()
+{
+}
+MyMoneyObserver::~MyMoneyObserver()
+{
+}
diff --git a/kmymoney2/mymoney/mymoneyobserver.h b/kmymoney2/mymoney/mymoneyobserver.h
new file mode 100644
index 0000000..3e6c922
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobserver.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ mymoneyobserver.h - description
+ -------------------
+ begin : Sat May 18 2002
+ copyright : (C) 2000-2005 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYOBSERVER_H
+#define MYMONEYOBSERVER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+class MyMoneySubject;
+class QString;
+
+/**
+ * This is the base class to be used to construct an
+ * observer for usage in a subject/observer relationship
+ *
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT MyMoneyObserver {
+public:
+ virtual ~MyMoneyObserver();
+ virtual void update(const QString& id) = 0;
+
+protected:
+ MyMoneyObserver();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyobservertest.h b/kmymoney2/mymoney/mymoneyobservertest.h
new file mode 100644
index 0000000..a806882
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyobservertest.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ mymoneyobservertest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYOBSERVERTEST_H__
+#define __MYMONEYOBSERVERTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class TestObserver : public MyMoneyObserver
+{
+public:
+ TestObserver() { m_updated = ""; }
+ void update(const QString& id) { m_updated = id; };
+ const QString& updated(void) { return m_updated; };
+ void reset(void) { m_updated = ""; };
+private:
+ QString m_updated;
+};
+
+class TestSubject : public MyMoneySubject
+{
+};
+
+class MyMoneyObserverTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyObserverTest);
+ CPPUNIT_TEST(testEmptySubject);
+ CPPUNIT_TEST(testAddObserver);
+ CPPUNIT_TEST(testRemoveObserver);
+ CPPUNIT_TEST(testNotifyObserver);
+ CPPUNIT_TEST(testNotifyMultipleObserver);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ TestSubject *subject;
+ TestObserver *observer1;
+ TestObserver *observer2;
+
+public:
+ MyMoneyObserverTest () {}
+
+
+void setUp () {
+ subject = new TestSubject;
+ observer1 = new TestObserver;
+ observer2 = new TestObserver;
+}
+
+void tearDown () {
+ delete observer1;
+ delete observer2;
+ delete subject;
+}
+
+void testEmptySubject() {
+ CPPUNIT_ASSERT(subject->m_observers.count() == 0);
+}
+
+void testAddObserver() {
+ subject->attach(observer1);
+ CPPUNIT_ASSERT(subject->m_observers.count() == 1);
+ CPPUNIT_ASSERT(subject->m_observers.at(0) == observer1);
+}
+
+void testRemoveObserver() {
+ testAddObserver();
+ subject->detach(observer1);
+ CPPUNIT_ASSERT(subject->m_observers.count() == 0);
+}
+
+void testNotifyObserver() {
+ testAddObserver();
+ CPPUNIT_ASSERT(observer1->updated() == "");
+ subject->notify("my id");
+ CPPUNIT_ASSERT(observer1->updated() == "my id");
+}
+
+void testNotifyMultipleObserver() {
+ testAddObserver();
+ subject->attach(observer2);
+ CPPUNIT_ASSERT(subject->m_observers.count() == 2);
+ CPPUNIT_ASSERT(subject->m_observers.at(0) == observer1);
+ CPPUNIT_ASSERT(subject->m_observers.at(1) == observer2);
+
+ CPPUNIT_ASSERT(observer1->updated() == "");
+ CPPUNIT_ASSERT(observer2->updated() == "");
+ subject->notify("my id");
+ CPPUNIT_ASSERT(observer1->updated() == "my id");
+ CPPUNIT_ASSERT(observer2->updated() == "my id");
+}
+
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneypayee.cpp b/kmymoney2/mymoney/mymoneypayee.cpp
new file mode 100644
index 0000000..cbfbbb7
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneypayee.cpp
@@ -0,0 +1,220 @@
+/***************************************************************************
+ mymoneypayee.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ (C) 2008 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneypayee.h"
+#include "mymoneyutils.h"
+#include <kmymoney/mymoneyexception.h>
+
+MyMoneyPayee MyMoneyPayee::null;
+
+MyMoneyPayee::MyMoneyPayee() :
+ m_matchingEnabled(false),
+ m_usingMatchKey(false),
+ m_matchKeyIgnoreCase(true)
+{
+}
+
+MyMoneyPayee::MyMoneyPayee(const QString& id, const MyMoneyPayee& payee) :
+ m_matchingEnabled(false),
+ m_usingMatchKey(false),
+ m_matchKeyIgnoreCase(true)
+{
+ *this = payee;
+ m_id = id;
+}
+
+MyMoneyPayee::MyMoneyPayee(const QString& name, const QString& address,
+ const QString& city, const QString& state, const QString& postcode,
+ const QString& telephone, const QString& email) :
+ m_matchingEnabled(false),
+ m_usingMatchKey(false),
+ m_matchKeyIgnoreCase(true)
+{
+ m_name = name;
+ m_address = address;
+ m_city = city;
+ m_state = state;
+ m_postcode = postcode;
+ m_telephone = telephone;
+ m_email = email;
+}
+
+MyMoneyPayee::MyMoneyPayee(const QDomElement& node) :
+ MyMoneyObject(node)
+{
+ if ("PAYEE" != node.tagName()) {
+ throw new MYMONEYEXCEPTION("Node was not PAYEE");
+ }
+
+ m_name = node.attribute("name");
+ m_reference = node.attribute("reference");
+ m_email = node.attribute("email");
+
+ m_matchingEnabled = node.attribute("matchingenabled","0").toUInt();
+ if ( m_matchingEnabled )
+ {
+ m_usingMatchKey = node.attribute("usingmatchkey","0").toUInt();
+ m_matchKeyIgnoreCase = node.attribute("matchignorecase","0").toUInt();
+ m_matchKey = node.attribute("matchkey");
+ }
+
+ if(node.hasAttribute("notes")) {
+ m_notes = node.attribute("notes");
+ }
+
+ if (node.hasAttribute("defaultaccountid")) {
+ m_defaultAccountId = node.attribute("defaultaccountid");
+ }
+
+ QDomNodeList nodeList = node.elementsByTagName("ADDRESS");
+ if(nodeList.count() == 0) {
+ QString msg = QString("No ADDRESS in payee %1").arg(m_name);
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ QDomElement addrNode = nodeList.item(0).toElement();
+ m_address = addrNode.attribute("street");
+ m_city = addrNode.attribute("city");
+ m_postcode = addrNode.attribute("postcode");
+ m_state = addrNode.attribute("state");
+ m_telephone = addrNode.attribute("telephone");
+}
+
+MyMoneyPayee::~MyMoneyPayee()
+{
+}
+
+MyMoneyPayee::MyMoneyPayee(const MyMoneyPayee& right) :
+ MyMoneyObject(right)
+{
+ *this = right;
+}
+
+bool MyMoneyPayee::operator == (const MyMoneyPayee& right) const
+{
+ return (MyMoneyObject::operator==(right) &&
+ ((m_name.length() == 0 && right.m_name.length() == 0) || (m_name == right.m_name)) &&
+ ((m_address.length() == 0 && right.m_address.length() == 0) || (m_address == right.m_address)) &&
+ ((m_city.length() == 0 && right.m_city.length() == 0) || (m_city == right.m_city)) &&
+ ((m_state.length() == 0 && right.m_state.length() == 0) || (m_state == right.m_state)) &&
+ ((m_postcode.length() == 0 && right.m_postcode.length() == 0) || (m_postcode == right.m_postcode)) &&
+ ((m_telephone.length() == 0 && right.m_telephone.length() == 0) || (m_telephone == right.m_telephone)) &&
+ ((m_email.length() == 0 && right.m_email.length() == 0) || (m_email == right.m_email)) &&
+ (m_matchingEnabled == right.m_matchingEnabled) &&
+ (m_usingMatchKey == right.m_usingMatchKey) &&
+ (m_matchKeyIgnoreCase == right.m_matchKeyIgnoreCase) &&
+ ((m_matchKey.length() == 0 && right.m_matchKey.length() == 0) || m_matchKey == right.m_matchKey) &&
+ ((m_reference.length() == 0 && right.m_reference.length() == 0) || (m_reference == right.m_reference)) &&
+ ((m_defaultAccountId.length() == 0 && right.m_defaultAccountId.length() == 0) || m_defaultAccountId == right.m_defaultAccountId) );
+}
+
+void MyMoneyPayee::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("PAYEE");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("name", m_name);
+ el.setAttribute("reference", m_reference);
+ el.setAttribute("email", m_email);
+ if(!m_notes.isEmpty())
+ el.setAttribute("notes", m_notes);
+
+ el.setAttribute("matchingenabled", m_matchingEnabled);
+ if ( m_matchingEnabled )
+ {
+ el.setAttribute("usingmatchkey", m_usingMatchKey);
+ el.setAttribute("matchignorecase", m_matchKeyIgnoreCase);
+ el.setAttribute("matchkey", m_matchKey);
+ }
+
+ if (!m_defaultAccountId.isEmpty()) {
+ el.setAttribute("defaultaccountid", m_defaultAccountId);
+ }
+
+ QDomElement address = document.createElement("ADDRESS");
+ address.setAttribute("street", m_address);
+ address.setAttribute("city", m_city);
+ address.setAttribute("postcode", m_postcode);
+ address.setAttribute("state", m_state);
+ address.setAttribute("telephone", m_telephone);
+
+ el.appendChild(address);
+
+ parent.appendChild(el);
+}
+
+bool MyMoneyPayee::hasReferenceTo(const QString& id) const
+{
+ return id == m_defaultAccountId;
+
+}
+
+MyMoneyPayee::payeeMatchType MyMoneyPayee::matchData(bool& ignorecase, QStringList& keys) const
+{
+ payeeMatchType type = matchDisabled;
+ keys.clear();
+ ignorecase = m_matchKeyIgnoreCase;
+
+ if ( m_matchingEnabled )
+ {
+ type = m_usingMatchKey ? matchKey : matchName;
+ if(type == matchKey)
+ keys = QStringList::split(";", m_matchKey);
+ }
+
+ return type;
+}
+
+MyMoneyPayee::payeeMatchType MyMoneyPayee::matchData(bool& ignorecase, QString& keyString) const
+{
+ QStringList keys;
+ payeeMatchType type = matchData(ignorecase, keys);
+ keyString = keys.join(";");
+ return type;
+}
+
+void MyMoneyPayee::setMatchData(payeeMatchType type, bool ignorecase, const QStringList& keys)
+{
+ m_matchingEnabled = (type != matchDisabled);
+ m_matchKeyIgnoreCase = ignorecase;
+ m_matchKey = QString();
+
+ if ( m_matchingEnabled )
+ {
+ m_usingMatchKey = (type == matchKey);
+ if ( m_usingMatchKey ) {
+ m_matchKey = keys.join(";");
+ }
+ }
+}
+
+void MyMoneyPayee::setMatchData(payeeMatchType type, bool ignorecase, const QString& keys)
+{
+ setMatchData(type, ignorecase, QStringList::split(";", keys));
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneypayee.h b/kmymoney2/mymoney/mymoneypayee.h
new file mode 100644
index 0000000..c2c711b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneypayee.h
@@ -0,0 +1,206 @@
+/***************************************************************************
+ mymoneypayee.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ 2005 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYPAYEE_H
+#define MYMONEYPAYEE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+class QStringList;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneyobject.h>
+
+/**
+ * This class represents a payee or receiver within the MyMoney engine.
+ * Since it is not payee-specific, it is also used as a generic address
+ * book entry.
+ *
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT MyMoneyPayee : public MyMoneyObject
+{
+private:
+ // Simple fields
+ QString m_name;
+ QString m_address;
+ QString m_city;
+ QString m_state;
+ QString m_postcode;
+ QString m_telephone;
+ QString m_email;
+ QString m_notes;
+
+ // Transaction matching fields
+ bool m_matchingEnabled; //< Whether this payee should be matched at all
+ bool m_usingMatchKey; //< If so, whether a m_matchKey list is used (true), or just m_name is used (false)
+ bool m_matchKeyIgnoreCase; //< Whether to ignore the case of the match key or name
+
+ /**
+ * Semicolon separated list of matching keys used when trying to find a suitable
+ * payee for imported transactions.
+ */
+ QString m_matchKey;
+
+ // Category (account) matching fields
+ QString m_defaultAccountId;
+
+ /**
+ * This member keeps a reference to an external database
+ * (e.g. kaddressbook). It is the responsability of the
+ * application to format the reference string
+ * (e.g. encoding the name of the external database into the
+ * reference string).
+ * If no external database is available it should be kept
+ * empty by the application.
+ */
+ QString m_reference;
+
+public:
+ typedef enum {
+ matchDisabled = 0,
+ matchName,
+ matchKey
+ } payeeMatchType;
+
+ MyMoneyPayee();
+ MyMoneyPayee(const QString& id, const MyMoneyPayee& payee);
+ MyMoneyPayee(const QString& name,
+ const QString& address=QString::null,
+ const QString& city=QString::null,
+ const QString& state=QString::null,
+ const QString& postcode=QString::null,
+ const QString& telephone=QString::null,
+ const QString& email=QString::null);
+ /**
+ * This is the constructor for a payee that is described by a
+ * QDomElement (e.g. from a file).
+ *
+ * @param el const reference to the QDomElement from which to
+ * create the object
+ */
+ MyMoneyPayee(const QDomElement& el);
+
+ ~MyMoneyPayee();
+
+ // Simple get operations
+ QString name(void) const { return m_name; }
+ QString address(void) const { return m_address; }
+ QString city(void) const { return m_city; }
+ QString state(void) const { return m_state; }
+ QString postcode(void) const { return m_postcode; }
+ QString telephone(void) const { return m_telephone; }
+ QString email(void) const { return m_email; }
+ QString notes(void) const { return m_notes; }
+
+ const QString id(void) const { return m_id; };
+ const QString reference(void) const { return m_reference; };
+
+ // Simple set operations
+ void setName(const QString& val) { m_name = val; }
+ void setAddress(const QString& val) { m_address = val; }
+ void setCity(const QString& val) { m_city = val; }
+ void setState(const QString& val) { m_state = val; }
+ void setPostcode(const QString& val) { m_postcode = val; }
+ void setTelephone(const QString& val) { m_telephone = val; }
+ void setEmail(const QString& val) { m_email = val; }
+ void setNotes(const QString& val) { m_notes = val; }
+ void setReference(const QString& ref) { m_reference = ref; }
+
+ /**
+ * Get all match data in one call
+ *
+ * @param ignorecase Bool which will be replaced to indicate whether the match is
+ * case-sensitive (false) or case-insensitive (true)
+ * @param keys List of strings which will be replaced by the match key to use for this payee
+ *
+ * @return the matching type (see payeeMatchType for details)
+ */
+ payeeMatchType matchData(bool& ignorecase, QStringList& keys) const;
+
+ /**
+ * Set all match data in one call
+ *
+ * @param type matching type (see payeeMatchType for details)
+ * @param ignorecase Whether case should be ignored for the key/name match
+ * @param keys A list of keys themselves, if applicable
+ */
+ void setMatchData(payeeMatchType type, bool ignorecase, const QStringList& keys);
+
+ /**
+ * Get all match data in one call (overloaded version for database module)
+ *
+ * @param ignorecase Bool which will be replaced to indicate whether the match is
+ * case-sensitive (false) or case-insensitive (true)
+ * @param keyString A list of keys in single-string format, if applicable
+ *
+ * @return the matching type (see payeeMatchType for details)
+ */
+ payeeMatchType matchData(bool& ignorecase, QString& keyString) const;
+
+ /**
+ * Set all match data in one call (overloaded version for database module)
+ *
+ * @param type matching type (see payeeMatchType for details)
+ * @param ignorecase Whether case should be ignored for the key/name match
+ * @param keys A list of keys in single-string format, if applicable
+ */
+ void setMatchData(payeeMatchType type, bool ignorecase, const QString& keys);
+
+
+ bool defaultAccountEnabled() const { return !m_defaultAccountId.isEmpty(); }
+ const QString& defaultAccountId() const { return m_defaultAccountId; }
+ void setDefaultAccountId(const QString& id = QString()) {
+ m_defaultAccountId = id;
+ }
+
+ // Copy constructors
+ MyMoneyPayee(const MyMoneyPayee&);
+
+ // Equality operator
+ bool operator == (const MyMoneyPayee &) const;
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ static MyMoneyPayee null;
+};
+
+inline bool operator==(const MyMoneyPayee& lhs, const QString& rhs) { return lhs.id() == rhs; }
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneypayeetest.cpp b/kmymoney2/mymoney/mymoneypayeetest.cpp
new file mode 100644
index 0000000..601679c
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneypayeetest.cpp
@@ -0,0 +1,76 @@
+/***************************************************************************
+ mymoneypayeetest.cpp
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneypayeetest.h"
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+MyMoneyPayeeTest:: MyMoneyPayeeTest () {
+}
+
+void MyMoneyPayeeTest::setUp () {
+}
+
+void MyMoneyPayeeTest::tearDown () {
+}
+
+void MyMoneyPayeeTest::testXml(){
+ QDomDocument doc;
+ QDomElement parent = doc.createElement("Test");
+ doc.appendChild(parent);
+ MyMoneyPayee payee1;
+ payee1.m_id = "some random id";//if the ID isn't set, w ethrow an exception
+ payee1.writeXML(doc,parent);
+ QString temp1 = "Account1";
+ payee1.setDefaultAccountId(temp1);
+ payee1.writeXML(doc,parent);
+ QString temp2 = "Account2";
+ payee1.setDefaultAccountId(temp2);
+ payee1.writeXML(doc,parent);
+ payee1.setDefaultAccountId();
+ payee1.writeXML(doc,parent);
+ QDomElement el = parent.firstChild().toElement();
+ CPPUNIT_ASSERT(!el.isNull());
+ MyMoneyPayee payee2(el);
+ CPPUNIT_ASSERT(!payee2.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee2.defaultAccountId().isEmpty());
+ el = el.nextSibling().toElement();
+ CPPUNIT_ASSERT(!el.isNull());
+ MyMoneyPayee payee3(el);
+ CPPUNIT_ASSERT(payee3.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee3.defaultAccountId()==temp1);
+ el = el.nextSibling().toElement();
+ CPPUNIT_ASSERT(!el.isNull());
+ MyMoneyPayee payee4(el);
+ CPPUNIT_ASSERT(payee4.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee4.defaultAccountId()==temp2);
+ el = el.nextSibling().toElement();
+ CPPUNIT_ASSERT(!el.isNull());
+ MyMoneyPayee payee5(el);
+ CPPUNIT_ASSERT(!payee5.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee5.defaultAccountId().isEmpty());
+}
+
+void MyMoneyPayeeTest::testDefaultAccount(){
+ MyMoneyPayee payee;
+ CPPUNIT_ASSERT(!payee.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee.defaultAccountId().isEmpty());
+ QString temp = "Account1";
+ payee.setDefaultAccountId(temp);
+ CPPUNIT_ASSERT(payee.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee.defaultAccountId()==temp);
+ payee.setDefaultAccountId();
+ CPPUNIT_ASSERT(!payee.defaultAccountEnabled());
+ CPPUNIT_ASSERT(payee.defaultAccountId().isEmpty());
+}
diff --git a/kmymoney2/mymoney/mymoneypayeetest.h b/kmymoney2/mymoney/mymoneypayeetest.h
new file mode 100644
index 0000000..baef561
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneypayeetest.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ mymoneypayeetest.h
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYPAYEETEST_H__
+#define __MYMONEYPAYEETEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "autotest.h"
+
+#define private public
+#define protected public
+#include "mymoneypayee.h"
+#undef private
+#undef protected
+
+class MyMoneyPayeeTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyPayeeTest);
+ CPPUNIT_TEST(testXml);
+ CPPUNIT_TEST(testDefaultAccount);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ MyMoneyPayeeTest ();
+
+ void setUp ();
+ void tearDown ();
+ void testXml();
+ void testDefaultAccount();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneyprice.cpp b/kmymoney2/mymoney/mymoneyprice.cpp
new file mode 100644
index 0000000..b674776
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyprice.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+ mymoneyprice - description
+ -------------------
+ begin : Sun Nov 21 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+/**
+ * @author Thomas Baumgart
+ */
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyprice.h"
+#include "mymoneyexception.h"
+
+MyMoneyPrice::MyMoneyPrice() :
+ m_date(QDate())
+{
+}
+
+MyMoneyPrice::MyMoneyPrice(const QString& from, const QString& to, const QDomElement& node)
+{
+ if("PRICE" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not PRICE");
+
+ m_fromSecurity = from;
+ m_toSecurity = to;
+
+ m_date = QDate::fromString(node.attribute("date"), Qt::ISODate);
+ m_rate = MyMoneyMoney(node.attribute("price"));
+ m_source = node.attribute("source");
+
+ if(!m_rate.isZero())
+ m_invRate = MyMoneyMoney(1,1) / m_rate;
+ else
+ qDebug("Price with zero value loaded");
+}
+
+MyMoneyPrice::MyMoneyPrice(const QString& from, const QString& to, const QDate& date, const MyMoneyMoney& rate, const QString& source) :
+ m_fromSecurity(from),
+ m_toSecurity(to),
+ m_date(date),
+ m_rate(rate),
+ m_source(source)
+{
+ if(!m_rate.isZero())
+ m_invRate = MyMoneyMoney(1,1) / m_rate;
+ else
+ qDebug("Price with zero value created");
+}
+
+MyMoneyPrice::~MyMoneyPrice()
+{
+}
+
+const MyMoneyMoney MyMoneyPrice::rate(const QString& id) const
+{
+ static MyMoneyMoney dummyPrice(1,1);
+
+ if(!isValid())
+ return dummyPrice;
+
+ if(id.isEmpty() || id == m_toSecurity)
+ return m_rate;
+ if(id == m_fromSecurity)
+ return m_invRate;
+
+ QString msg = QString("Unknown security id %1 for price info %2/%3.").arg(id).arg(m_fromSecurity).arg(m_toSecurity);
+ throw new MYMONEYEXCEPTION(msg);
+}
+
+bool MyMoneyPrice::isValid(void) const
+{
+ return (m_date.isValid() && !m_fromSecurity.isEmpty() && !m_toSecurity.isEmpty());
+}
+
+// Equality operator
+bool MyMoneyPrice::operator == (const MyMoneyPrice &right) const
+{
+ return ((m_date == right.m_date) &&
+ (m_rate == right.m_rate) &&
+ ((m_fromSecurity.length() == 0 && right.m_fromSecurity.length() == 0) || (m_fromSecurity == right.m_fromSecurity)) &&
+ ((m_toSecurity.length() == 0 && right.m_toSecurity.length() == 0) || (m_toSecurity == right.m_toSecurity)) &&
+ ((m_source.length() == 0 && right.m_source.length() == 0) || (m_source == right.m_source)));
+}
+
+bool MyMoneyPrice::hasReferenceTo(const QString& id) const
+{
+ return (id == m_fromSecurity) || (id == m_toSecurity);
+}
diff --git a/kmymoney2/mymoney/mymoneyprice.h b/kmymoney2/mymoney/mymoneyprice.h
new file mode 100644
index 0000000..faf6454
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyprice.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ mymoneyprice - description
+ -------------------
+ begin : Sun Nov 21 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYPRICE_H
+#define MYMONEYPRICE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qpair.h>
+#include <qmap.h>
+#include <qdom.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/export.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents an exchange rate of a security, currency or commodity
+ * based on another security, currency or commodity for a specific date.
+ * The term security is used in this class as a placeholder for all
+ * those previously mentioned items.
+ * In general, the other security is a currency.
+ *
+ * The securities and the rate form the following equation:
+ *
+ * @code
+ *
+ * toSecurity = rate * fromSecurity
+ *
+ * @endcode
+ *
+ * Using the @p rate() member function, one can retrieve the conversion rate based
+ * upon the @p toSecurity or the @p fromSecurity.
+ */
+class KMYMONEY_EXPORT MyMoneyPrice
+{
+public:
+ MyMoneyPrice();
+ MyMoneyPrice(const QString& from, const QString& to, const QDomElement& node);
+ MyMoneyPrice(const QString& from, const QString& to, const QDate& date, const MyMoneyMoney& rate, const QString& source = QString());
+ virtual ~MyMoneyPrice();
+
+ /**
+ * This method returns the price information based on the
+ * security referenced by @p id. If @p id is empty (default), the
+ * price is returned based on the toSecurity. If this price
+ * object is invalid (see isValid()) MyMoneyMoney(1,1) is returned.
+ *
+ * @param id return price to be the factor to be used to convert a value into
+ * the correcponding value in security @p id.
+ *
+ * @return returns the exchange rate (price) as MyMoneyMoney object.
+ *
+ * If @p id is not empty and does not match either security ids of this price
+ * an exception will be thrown.
+ *
+ * Example:
+ * Assume the following code, where you have a price object and
+ * and you wish to convert from an amount in GBP (@p valGBP) to ADF (@p valADF).
+ * Then your code will look like this:
+ *
+ * @code
+ *
+ * MyMoneyPrice price("ADF", "GBP", QDate(2005,9,20), MyMoneyMoney(1,3), "User");
+ * MyMoneyMoney valADF, valGBP(100,1);
+ *
+ * valADF = valGBP * price.rate("ADF");
+ *
+ * @endcode
+ *
+ * valADF will contain the value 300 after the assignment operation, because @p price.rate("ADF") returned
+ * @p 3/1 even though the price information kept with the object was @p 1/3, but based on the other
+ * conversion direction (from ADF to GBP).
+ */
+ const MyMoneyMoney rate(const QString& id) const;
+
+ const QDate& date(void) const { return m_date; };
+ const QString& source(void) const { return m_source; };
+ const QString& from(void) const { return m_fromSecurity; };
+ const QString& to(void) const { return m_toSecurity; };
+
+ /**
+ * Check whether the object is valid or not. A MyMoneyPrice object
+ * is valid if the date is valid and both security ids are set. In case
+ * of an invalid object, price() always returns 1.
+ *
+ * @retval true if price object is valid
+ * @retval false if price object is not valid
+ */
+ bool isValid(void) const;
+
+ // Equality operator
+ bool operator == (const MyMoneyPrice &) const;
+
+ // Inequality operator
+ bool operator != (const MyMoneyPrice &right) const { return !(operator == (right)); };
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ bool hasReferenceTo(const QString& id) const;
+
+private:
+ QString m_fromSecurity;
+ QString m_toSecurity;
+ QDate m_date;
+ MyMoneyMoney m_rate;
+ MyMoneyMoney m_invRate;
+ QString m_source;
+};
+
+
+typedef QPair<QString, QString> MyMoneySecurityPair;
+typedef QMap<QDate, MyMoneyPrice> MyMoneyPriceEntries;
+typedef QMap<MyMoneySecurityPair, MyMoneyPriceEntries> MyMoneyPriceList;
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneypricetest.cpp b/kmymoney2/mymoney/mymoneypricetest.cpp
new file mode 100644
index 0000000..203e9ca
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneypricetest.cpp
@@ -0,0 +1,90 @@
+/***************************************************************************
+ mymoneypricetest.cpp
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneypricetest.h"
+#include "mymoneyexception.h"
+
+MyMoneyPriceTest::MyMoneyPriceTest()
+{
+}
+
+
+void MyMoneyPriceTest::setUp()
+{
+ m = new MyMoneyPrice();
+}
+
+void MyMoneyPriceTest::tearDown()
+{
+ delete m;
+}
+
+void MyMoneyPriceTest::testDefaultConstructor()
+{
+ CPPUNIT_ASSERT(m->isValid() == false);
+}
+
+void MyMoneyPriceTest::testConstructor()
+{
+ MyMoneyPrice n(QString("from"), QString("to"), QDate(2005,9,23), MyMoneyMoney(1,3), QString("MySource"));
+
+ CPPUNIT_ASSERT(n.isValid() == true);
+ CPPUNIT_ASSERT(n.from() == QString("from"));
+ CPPUNIT_ASSERT(n.to() == QString("to"));
+ CPPUNIT_ASSERT(n.date() == QDate(2005,9,23));
+ CPPUNIT_ASSERT(n.source() == QString("MySource"));
+ CPPUNIT_ASSERT(n.rate("to") == MyMoneyMoney(1,3));
+}
+
+void MyMoneyPriceTest::testValidity()
+{
+ QString emptyId;
+ MyMoneyPrice n1(emptyId, QString("to"), QDate(2005,9,23), MyMoneyMoney(1,3), QString("MySource"));
+ MyMoneyPrice n2(QString("from"), emptyId, QDate(2005,9,23), MyMoneyMoney(1,3), QString("MySource"));
+ MyMoneyPrice n3(QString("from"), QString("to"), QDate(), MyMoneyMoney(1,3), QString("MySource"));
+ MyMoneyPrice n4(QString("from"), QString("to"), QDate(2005,9,23), MyMoneyMoney(1,3), QString("MySource"));
+
+ CPPUNIT_ASSERT(n1.isValid() == false);
+ CPPUNIT_ASSERT(n2.isValid() == false);
+ CPPUNIT_ASSERT(n3.isValid() == false);
+ CPPUNIT_ASSERT(n4.isValid() == true);
+}
+
+void MyMoneyPriceTest::testRate()
+{
+ MyMoneyPrice n1(QString("from"), QString("to"), QDate(2005,9,23), MyMoneyMoney(1,3), QString("MySource"));
+ MyMoneyPrice n2(QString("from"), QString("to"), QDate(), MyMoneyMoney(1,3), QString("MySource"));
+
+ try {
+ CPPUNIT_ASSERT(n1.rate("to") == MyMoneyMoney(1,3));
+ CPPUNIT_ASSERT(n1.rate("from") == MyMoneyMoney(3,1));
+ CPPUNIT_ASSERT(n1.rate(QString()) == MyMoneyMoney(1,3));
+
+ CPPUNIT_ASSERT(n2.isValid() == false);
+ CPPUNIT_ASSERT(n2.rate("to") == MyMoneyMoney(1,1));
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+
+ try {
+ n1.rate("unknown");
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
diff --git a/kmymoney2/mymoney/mymoneypricetest.h b/kmymoney2/mymoney/mymoneypricetest.h
new file mode 100644
index 0000000..a153a94
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneypricetest.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ mymoneypricetest.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYPRICETEST_H__
+#define __MYMONEYPRICETEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneyprice.h"
+#undef private
+
+class MyMoneyPriceTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyPriceTest);
+ CPPUNIT_TEST(testDefaultConstructor);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST(testValidity);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyPrice* m;
+
+public:
+ MyMoneyPriceTest();
+
+ void setUp();
+ void tearDown();
+
+ void testDefaultConstructor();
+ void testConstructor();
+ void testValidity();
+ void testRate();
+
+};
+#endif
diff --git a/kmymoney2/mymoney/mymoneyreport.cpp b/kmymoney2/mymoney/mymoneyreport.cpp
new file mode 100644
index 0000000..63c4ca7
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyreport.cpp
@@ -0,0 +1,787 @@
+/***************************************************************************
+ mymoneyreport.cpp
+ -------------------
+ begin : Sun July 4 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdom.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyfile.h"
+#include "mymoneyreport.h"
+
+const QStringList MyMoneyReport::kRowTypeText = QStringList::split ( ",", "none,assetliability,expenseincome,category,topcategory,account,payee,month,week,topaccount,topaccount-account,equitytype,accounttype,institution,budget,budgetactual,schedule,accountinfo,accountloaninfo,accountreconcile,cashflow", true );
+const QStringList MyMoneyReport::kColumnTypeText = QStringList::split ( ",", "none,months,bimonths,quarters,4,5,6,weeks,8,9,10,11,years", true );
+
+// if you add names here, don't forget to update the bitmap for EQueryColumns
+// and shift the bit for eQCend one position to the left
+const QStringList MyMoneyReport::kQueryColumnsText = QStringList::split ( ",", "none,number,payee,category,memo,account,reconcileflag,action,shares,price,performance,loan,balance", true );
+
+const MyMoneyReport::EReportType MyMoneyReport::kTypeArray[] = { eNoReport, ePivotTable, ePivotTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, ePivotTable, ePivotTable, eInfoTable, eInfoTable, eInfoTable, eQueryTable, eQueryTable, eNoReport };
+const QStringList MyMoneyReport::kDetailLevelText = QStringList::split ( ",", "none,all,top,group,total,invalid", true );
+const QStringList MyMoneyReport::kChartTypeText = QStringList::split ( ",", "none,line,bar,pie,ring,stackedbar,invalid", true );
+
+// This should live in mymoney/mymoneytransactionfilter.h
+static const QStringList kTypeText = QStringList::split ( ",", "all,payments,deposits,transfers,none" );
+static const QStringList kStateText = QStringList::split ( ",", "all,notreconciled,cleared,reconciled,frozen,none" );
+static const QStringList kDateLockText = QStringList::split ( ",", "alldates,untiltoday,currentmonth,currentyear,monthtodate,yeartodate,yeartomonth,lastmonth,lastyear,last7days,last30days,last3months,last6months,last12months,next7days,next30days,next3months,next6months,next12months,userdefined,last3tonext3months,last11Months,currentQuarter,lastQuarter,nextQuarter,currentFiscalYear,lastFiscalYear,today" );
+static const QStringList kAccountTypeText = QStringList::split ( ",", "unknown,checkings,savings,cash,creditcard,loan,certificatedep,investment,moneymarket,asset,liability,currency,income,expense,assetloan,stock,equity,invalid" );
+
+MyMoneyReport::MyMoneyReport() :
+ m_name ( "Unconfigured Pivot Table Report" ),
+ m_detailLevel ( eDetailNone ),
+ m_convertCurrency ( true ),
+ m_favorite ( false ),
+ m_tax ( false ),
+ m_investments ( false ),
+ m_loans ( false ),
+ m_reportType ( kTypeArray[eExpenseIncome] ),
+ m_rowType ( eExpenseIncome ),
+ m_columnType ( eMonths ),
+ m_columnsAreDays ( false ),
+ m_queryColumns ( eQCnone ),
+ m_dateLock ( userDefined ),
+ m_accountGroupFilter ( false ),
+ m_chartType ( eChartLine ),
+ m_chartDataLabels ( true ),
+ m_chartGridLines ( true ),
+ m_chartByDefault ( false ),
+ m_chartLineWidth ( 2 ),
+ m_includeSchedules ( false ),
+ m_includeTransfers ( false ),
+ m_includeBudgetActuals ( false ),
+ m_includeUnusedAccounts ( false ),
+ m_showRowTotals ( false ),
+ m_includeForecast ( false ),
+ m_includeMovingAverage ( false ),
+ m_includePrice ( false ),
+ m_includeAveragePrice ( false )
+{
+}
+
+MyMoneyReport::MyMoneyReport ( const QString& id, const MyMoneyReport& right ) :
+ MyMoneyObject ( id )
+{
+ *this = right;
+ setId ( id );
+}
+
+MyMoneyReport::MyMoneyReport ( ERowType _rt, unsigned _ct, dateOptionE _dl, EDetailLevel _ss, const QString& _name, const QString& _comment ) :
+ m_name ( _name ),
+ m_comment ( _comment ),
+ m_detailLevel ( _ss ),
+ m_convertCurrency ( true ),
+ m_favorite ( false ),
+ m_tax ( false ),
+ m_investments ( false ),
+ m_loans ( false ),
+ m_reportType ( kTypeArray[_rt] ),
+ m_rowType ( _rt ),
+ m_columnsAreDays ( false ),
+ m_dateLock ( _dl ),
+ m_accountGroupFilter ( false ),
+ m_chartType ( eChartLine ),
+ m_chartDataLabels ( true ),
+ m_chartGridLines ( true ),
+ m_chartByDefault ( false ),
+ m_chartLineWidth ( 2 ),
+ m_includeSchedules ( false ),
+ m_includeTransfers ( false ),
+ m_includeBudgetActuals ( false ),
+ m_includeUnusedAccounts ( false ),
+ m_showRowTotals ( false ),
+ m_includeForecast ( false ),
+ m_includeMovingAverage ( false ),
+ m_includePrice ( false ),
+ m_includeAveragePrice ( false )
+{
+ if ( m_reportType == ePivotTable )
+ m_columnType = static_cast<EColumnType> ( _ct );
+ if ( m_reportType == eQueryTable )
+ m_queryColumns = static_cast<EQueryColumns> ( _ct );
+ setDateFilter ( _dl );
+
+ if ( ( _rt > static_cast<ERowType> ( sizeof ( kTypeArray ) / sizeof ( kTypeArray[0] ) ) )
+ || ( m_reportType == eNoReport ) )
+ throw new MYMONEYEXCEPTION ( "Invalid report type" );
+
+ if ( _rt == MyMoneyReport::eAssetLiability )
+ {
+ addAccountGroup ( MyMoneyAccount::Asset );
+ addAccountGroup ( MyMoneyAccount::Liability );
+ m_showRowTotals = true;
+ }
+ if ( _rt == MyMoneyReport::eExpenseIncome )
+ {
+ addAccountGroup ( MyMoneyAccount::Expense );
+ addAccountGroup ( MyMoneyAccount::Income );
+ m_showRowTotals = true;
+ }
+ //FIXME take this out once we have sorted out all issues regarding budget of assets and liabilities -- asoliverez@gmail.com
+ if ( _rt == MyMoneyReport::eBudget || _rt == MyMoneyReport::eBudgetActual )
+ {
+ addAccountGroup ( MyMoneyAccount::Expense );
+ addAccountGroup ( MyMoneyAccount::Income );
+ }
+ if ( _rt == MyMoneyReport::eAccountInfo )
+ {
+ addAccountGroup ( MyMoneyAccount::Asset );
+ addAccountGroup ( MyMoneyAccount::Liability );
+ }
+ //cash flow reports show splits for all account groups
+ if ( _rt == MyMoneyReport::eCashFlow )
+ {
+ addAccountGroup ( MyMoneyAccount::Expense );
+ addAccountGroup ( MyMoneyAccount::Income );
+ addAccountGroup ( MyMoneyAccount::Asset );
+ addAccountGroup ( MyMoneyAccount::Liability );
+ }
+}
+
+MyMoneyReport::MyMoneyReport ( const QDomElement& node ) :
+ MyMoneyObject ( node )
+{
+ if ( !read ( node ) )
+ clearId();
+}
+
+void MyMoneyReport::clear ( void )
+{
+ m_accountGroupFilter = false;
+ m_accountGroups.clear();
+
+ MyMoneyTransactionFilter::clear();
+}
+
+void MyMoneyReport::validDateRange ( QDate& _db, QDate& _de )
+{
+ _db = fromDate();
+ _de = toDate();
+
+ // if either begin or end date are invalid we have one of the following
+ // possible date filters:
+ //
+ // a) begin date not set - first transaction until given end date
+ // b) end date not set - from given date until last transaction
+ // c) both not set - first transaction until last transaction
+ //
+ // If there is no transaction in the engine at all, we use the current
+ // year as the filter criteria.
+
+ if ( !_db.isValid() || !_de.isValid() ) {
+ QValueList<MyMoneyTransaction> list = MyMoneyFile::instance()->transactionList ( *this );
+ QDate tmpBegin, tmpEnd;
+
+ if ( !list.isEmpty() ) {
+ qHeapSort ( list );
+ tmpBegin = list.front().postDate();
+ tmpEnd = list.back().postDate();
+ } else {
+ tmpBegin = QDate ( QDate::currentDate().year(), 1, 1 ); // the first date in the file
+ tmpEnd = QDate ( QDate::currentDate().year(), 12, 31 );// the last date in the file
+ }
+ if ( !_db.isValid() )
+ _db = tmpBegin;
+ if ( !_de.isValid() )
+ _de = tmpEnd;
+ }
+ if ( _db > _de )
+ _db = _de;
+}
+
+void MyMoneyReport::setRowType ( ERowType _rt )
+{
+ m_rowType = _rt;
+ m_reportType = kTypeArray[_rt];
+
+ m_accountGroupFilter = false;
+ m_accountGroups.clear();
+
+ if ( _rt == MyMoneyReport::eAssetLiability )
+ {
+ addAccountGroup ( MyMoneyAccount::Asset );
+ addAccountGroup ( MyMoneyAccount::Liability );
+ }
+ if ( _rt == MyMoneyReport::eExpenseIncome )
+ {
+ addAccountGroup ( MyMoneyAccount::Expense );
+ addAccountGroup ( MyMoneyAccount::Income );
+ }
+}
+
+bool MyMoneyReport::accountGroups(QValueList<MyMoneyAccount::accountTypeE>& list) const
+
+{
+ bool result = m_accountGroupFilter;
+
+ if ( result )
+ {
+ QValueList<MyMoneyAccount::accountTypeE>::const_iterator it_group = m_accountGroups.begin();
+ while ( it_group != m_accountGroups.end() )
+ {
+ list += ( *it_group );
+ ++it_group;
+ }
+ }
+ return result;
+}
+
+void MyMoneyReport::addAccountGroup ( MyMoneyAccount::accountTypeE type )
+{
+ if ( !m_accountGroups.isEmpty() && type != MyMoneyAccount::UnknownAccountType ) {
+ if ( m_accountGroups.contains ( type ) )
+ return;
+ }
+ m_accountGroupFilter = true;
+ if ( type != MyMoneyAccount::UnknownAccountType )
+ m_accountGroups.push_back ( type );
+}
+
+bool MyMoneyReport::includesAccountGroup( MyMoneyAccount::accountTypeE type ) const
+{
+ bool result = ( ! m_accountGroupFilter )
+ || ( isIncludingTransfers() && m_rowType == MyMoneyReport::eExpenseIncome )
+ || m_accountGroups.contains ( type );
+
+ return result;
+}
+
+bool MyMoneyReport::includes( const MyMoneyAccount& acc ) const
+{
+ bool result = false;
+
+ if ( includesAccountGroup ( acc.accountGroup() ) )
+ {
+ switch ( acc.accountGroup() )
+ {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ if ( isTax() )
+ result = ( acc.value ( "Tax" ) == "Yes" ) && includesCategory ( acc.id() );
+ else
+ result = includesCategory ( acc.id() );
+ break;
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ if ( isLoansOnly() )
+ result = acc.isLoan() && includesAccount ( acc.id() );
+ else if ( isInvestmentsOnly() )
+ result = acc.isInvest() && includesAccount ( acc.id() );
+ else if ( isIncludingTransfers() && m_rowType == MyMoneyReport::eExpenseIncome )
+ // If transfers are included, ONLY include this account if it is NOT
+ // included in the report itself!!
+ result = ! includesAccount ( acc.id() );
+ else
+ result = includesAccount ( acc.id() );
+ break;
+ default:
+ result = includesAccount ( acc.id() );
+ }
+ }
+ return result;
+}
+
+void MyMoneyReport::write ( QDomElement& e, QDomDocument *doc, bool anonymous ) const
+{
+ // No matter what changes, be sure to have a 'type' attribute. Only change
+ // the major type if it becomes impossible to maintain compatability with
+ // older versions of the program as new features are added to the reports.
+ // Feel free to change the minor type every time a change is made here.
+
+ writeBaseXML ( *doc, e );
+
+ if ( anonymous )
+ {
+ e.setAttribute ( "name", m_id );
+ e.setAttribute ( "comment", QString ( m_comment ).fill ( 'x' ) );
+ }
+ else
+ {
+ e.setAttribute ( "name", m_name );
+ e.setAttribute ( "comment", m_comment );
+ }
+ e.setAttribute ( "group", m_group );
+ e.setAttribute ( "convertcurrency", m_convertCurrency );
+ e.setAttribute ( "favorite", m_favorite );
+ e.setAttribute ( "tax", m_tax );
+ e.setAttribute ( "investments", m_investments );
+ e.setAttribute ( "loans", m_loans );
+ e.setAttribute ( "rowtype", kRowTypeText[m_rowType] );
+ e.setAttribute ( "datelock", kDateLockText[m_dateLock] );
+ e.setAttribute ( "includeschedules", m_includeSchedules );
+ e.setAttribute ( "columnsaredays", m_columnsAreDays );
+ e.setAttribute ( "includestransfers", m_includeTransfers );
+ if ( !m_budgetId.isEmpty() )
+ e.setAttribute ( "budget", m_budgetId );
+ e.setAttribute ( "includesactuals", m_includeBudgetActuals );
+ e.setAttribute ( "includeunused", m_includeUnusedAccounts );
+ e.setAttribute ( "includesforecast", m_includeForecast );
+ e.setAttribute ( "includesprice", m_includePrice );
+ e.setAttribute ( "includesaverageprice", m_includeAveragePrice );
+ e.setAttribute ( "includesmovingaverage", m_includeMovingAverage );
+ if( m_includeMovingAverage )
+ e.setAttribute ( "movingaveragedays", m_movingAverageDays );
+
+ e.setAttribute ( "charttype", kChartTypeText[m_chartType] );
+ e.setAttribute ( "chartdatalabels", m_chartDataLabels );
+ e.setAttribute ( "chartgridlines", m_chartGridLines );
+ e.setAttribute ( "chartbydefault", m_chartByDefault );
+ e.setAttribute ( "chartlinewidth", m_chartLineWidth );
+
+ if ( m_reportType == ePivotTable )
+ {
+ e.setAttribute ( "type", "pivottable 1.15" );
+ e.setAttribute ( "detail", kDetailLevelText[m_detailLevel] );
+ e.setAttribute ( "columntype", kColumnTypeText[m_columnType] );
+ e.setAttribute ( "showrowtotals", m_showRowTotals );
+ }
+ else if ( m_reportType == eQueryTable )
+ {
+ e.setAttribute ( "type", "querytable 1.14" );
+
+ QStringList columns;
+ unsigned qc = m_queryColumns;
+ unsigned it_qc = eQCbegin;
+ unsigned index = 1;
+ while ( it_qc != eQCend )
+ {
+ if ( qc & it_qc )
+ columns += kQueryColumnsText[index];
+ it_qc *= 2;
+ index++;
+ }
+ e.setAttribute ( "querycolumns", columns.join ( "," ) );
+ }
+ else if ( m_reportType == eInfoTable )
+ {
+ e.setAttribute ( "type", "infotable 1.0" );
+ e.setAttribute ( "detail", kDetailLevelText[m_detailLevel] );
+ e.setAttribute ( "showrowtotals", m_showRowTotals );
+ }
+
+ //
+ // Text Filter
+ //
+
+ QRegExp textfilter;
+ if ( textFilter ( textfilter ) )
+ {
+ QDomElement f = doc->createElement ( "TEXT" );
+ f.setAttribute ( "pattern", textfilter.pattern() );
+ f.setAttribute ( "casesensitive", textfilter.caseSensitive() );
+ f.setAttribute ( "regex", !textfilter.wildcard() );
+ f.setAttribute ( "inverttext", m_invertText );
+ e.appendChild ( f );
+ }
+
+ //
+ // Type & State Filters
+ //
+ QValueList<int> typelist;
+ if ( types ( typelist ) && ! typelist.empty() )
+ {
+ // iterate over payees, and add each one
+ QValueList<int>::const_iterator it_type = typelist.begin();
+ while ( it_type != typelist.end() )
+ {
+ QDomElement p = doc->createElement ( "TYPE" );
+ p.setAttribute ( "type", kTypeText[*it_type] );
+ e.appendChild ( p );
+
+ ++it_type;
+ }
+ }
+
+ QValueList<int> statelist;
+ if ( states ( statelist ) && ! statelist.empty() )
+ {
+ // iterate over payees, and add each one
+ QValueList<int>::const_iterator it_state = statelist.begin();
+ while ( it_state != statelist.end() )
+ {
+ QDomElement p = doc->createElement ( "STATE" );
+ p.setAttribute ( "state", kStateText[*it_state] );
+ e.appendChild ( p );
+
+ ++it_state;
+ }
+ }
+ //
+ // Number Filter
+ //
+
+ QString nrFrom, nrTo;
+ if ( numberFilter ( nrFrom, nrTo ) )
+ {
+ QDomElement f = doc->createElement ( "NUMBER" );
+ f.setAttribute ( "from", nrFrom );
+ f.setAttribute ( "to", nrTo );
+ e.appendChild ( f );
+ }
+
+ //
+ // Amount Filter
+ //
+
+ MyMoneyMoney from, to;
+ if ( amountFilter ( from, to ) ) // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&);
+ {
+ QDomElement f = doc->createElement ( "AMOUNT" );
+ f.setAttribute ( "from", from.toString() );
+ f.setAttribute ( "to", to.toString() );
+ e.appendChild ( f );
+ }
+
+ //
+ // Payees Filter
+ //
+
+ QStringList payeelist;
+ if ( payees ( payeelist ) )
+ {
+ if ( payeelist.empty() )
+ {
+ QDomElement p = doc->createElement ( "PAYEE" );
+ e.appendChild ( p );
+ }
+ else
+ {
+ // iterate over payees, and add each one
+ QStringList::const_iterator it_payee = payeelist.begin();
+ while ( it_payee != payeelist.end() )
+ {
+ QDomElement p = doc->createElement ( "PAYEE" );
+ p.setAttribute ( "id", *it_payee );
+ e.appendChild ( p );
+
+ ++it_payee;
+ }
+ }
+ }
+
+ //
+ // Account Groups Filter
+ //
+
+ QValueList<MyMoneyAccount::accountTypeE> accountgrouplist;
+ if ( accountGroups ( accountgrouplist ) )
+ {
+ // iterate over accounts, and add each one
+ QValueList<MyMoneyAccount::accountTypeE>::const_iterator it_group = accountgrouplist.begin();
+ while ( it_group != accountgrouplist.end() )
+ {
+ QDomElement p = doc->createElement ( "ACCOUNTGROUP" );
+ p.setAttribute ( "group", kAccountTypeText[*it_group] );
+ e.appendChild ( p );
+
+ ++it_group;
+ }
+ }
+
+ //
+ // Accounts Filter
+ //
+
+ QStringList accountlist;
+ if ( accounts ( accountlist ) )
+ {
+ // iterate over accounts, and add each one
+ QStringList::const_iterator it_account = accountlist.begin();
+ while ( it_account != accountlist.end() )
+ {
+ QDomElement p = doc->createElement ( "ACCOUNT" );
+ p.setAttribute ( "id", *it_account );
+ e.appendChild ( p );
+
+ ++it_account;
+ }
+ }
+
+ //
+ // Categories Filter
+ //
+
+ accountlist.clear();
+ if ( categories ( accountlist ) )
+ {
+ // iterate over accounts, and add each one
+ QStringList::const_iterator it_account = accountlist.begin();
+ while ( it_account != accountlist.end() )
+ {
+ QDomElement p = doc->createElement ( "CATEGORY" );
+ p.setAttribute ( "id", *it_account );
+ e.appendChild ( p );
+
+ ++it_account;
+ }
+ }
+
+ //
+ // Date Filter
+ //
+
+ if ( m_dateLock == userDefined )
+ {
+ QDate dateFrom, dateTo;
+ if ( dateFilter ( dateFrom, dateTo ) )
+ {
+ QDomElement f = doc->createElement ( "DATES" );
+ if ( dateFrom.isValid() )
+ f.setAttribute ( "from", dateFrom.toString ( Qt::ISODate ) );
+ if ( dateTo.isValid() )
+ f.setAttribute ( "to", dateTo.toString ( Qt::ISODate ) );
+ e.appendChild ( f );
+ }
+ }
+}
+
+bool MyMoneyReport::read ( const QDomElement& e )
+{
+ // The goal of this reading method is 100% backward AND 100% forward
+ // compatability. Any report ever created with any version of KMyMoney
+ // should be able to be loaded by this method (as long as it's one of the
+ // report types supported in this version, of course)
+
+ bool result = false;
+
+ if (
+ "REPORT" == e.tagName()
+ &&
+ (
+ ( e.attribute ( "type" ).find ( "pivottable 1." ) == 0 )
+ ||
+ ( e.attribute ( "type" ).find ( "querytable 1." ) == 0 )
+ ||
+ ( e.attribute ( "type" ).find ( "infotable 1." ) == 0 )
+ )
+ )
+ {
+ result = true;
+ clear();
+
+ int i;
+ m_name = e.attribute ( "name" );
+ m_comment = e.attribute ( "comment", "Extremely old report" );
+
+ //set report type
+ if(!e.attribute ( "type" ).find ( "pivottable" )) {
+ m_reportType = MyMoneyReport::ePivotTable;
+ } else if(!e.attribute ( "type" ).find ( "querytable" )) {
+ m_reportType = MyMoneyReport::eQueryTable;
+ } else if(!e.attribute ( "type" ).find ( "infotable" )) {
+ m_reportType = MyMoneyReport::eInfoTable;
+ } else {
+ m_reportType = MyMoneyReport::eNoReport;
+ }
+
+ // Removed the line that screened out loading reports that are called
+ // "Default Report". It's possible for the user to change the comment
+ // to this, and we'd hate for it to break as a result.
+ m_group = e.attribute ( "group" );
+ m_id = e.attribute ( "id" );
+
+ //check for reports with older settings which didn't have the detail attribute
+ if ( e.hasAttribute ( "detail" ) )
+ {
+ i = kDetailLevelText.findIndex ( e.attribute ( "detail", "all" ) );
+ if ( i != -1 )
+ m_detailLevel = static_cast<EDetailLevel> ( i );
+ } else if ( e.attribute ( "showsubaccounts", "0" ).toUInt() ) {
+ //set to show all accounts
+ m_detailLevel = eDetailAll;
+ } else {
+ //set to show the top level account instead
+ m_detailLevel = eDetailTop;
+ }
+
+ m_convertCurrency = e.attribute ( "convertcurrency", "1" ).toUInt();
+ m_favorite = e.attribute ( "favorite", "0" ).toUInt();
+ m_tax = e.attribute ( "tax", "0" ).toUInt();
+ m_investments = e.attribute ( "investments", "0" ).toUInt();
+ m_loans = e.attribute ( "loans", "0" ).toUInt();
+ m_includeSchedules = e.attribute ( "includeschedules", "0" ).toUInt();
+ m_columnsAreDays = e.attribute ( "columnsaredays", "0" ).toUInt();
+ m_includeTransfers = e.attribute ( "includestransfers", "0" ).toUInt();
+ if ( e.hasAttribute ( "budget" ) )
+ m_budgetId = e.attribute ( "budget" );
+ m_includeBudgetActuals = e.attribute ( "includesactuals", "0" ).toUInt();
+ m_includeUnusedAccounts = e.attribute ( "includeunused", "0" ).toUInt();
+ m_includeForecast = e.attribute ( "includesforecast", "0" ).toUInt();
+ m_includePrice = e.attribute ( "includesprice", "0" ).toUInt();
+ m_includeAveragePrice = e.attribute ( "includesaverageprice", "0" ).toUInt();
+ m_includeMovingAverage = e.attribute ( "includesmovingaverage", "0" ).toUInt();
+ if( m_includeMovingAverage )
+ m_movingAverageDays = e.attribute ( "movingaveragedays", "1" ).toUInt();
+
+ //only load chart data if it is a pivot table
+ if ( m_reportType == ePivotTable ) {
+ i = kChartTypeText.findIndex ( e.attribute ( "charttype" ) );
+
+ if ( i != -1 )
+ m_chartType = static_cast<EChartType> ( i );
+
+ //if it is invalid, set to first type
+ if (m_chartType == eChartEnd)
+ m_chartType = eChartLine;
+
+ m_chartDataLabels = e.attribute ( "chartdatalabels", "1" ).toUInt();
+ m_chartGridLines = e.attribute ( "chartgridlines", "1" ).toUInt();
+ m_chartByDefault = e.attribute ( "chartbydefault", "0" ).toUInt();
+ m_chartLineWidth = e.attribute ( "chartlinewidth", "2" ).toUInt();
+ } else {
+ m_chartType = static_cast<EChartType> ( 0 );
+ m_chartDataLabels = true;
+ m_chartGridLines = true;
+ m_chartByDefault = false;
+ m_chartLineWidth = 1;
+ }
+
+ QString datelockstr = e.attribute ( "datelock", "userdefined" );
+ // Handle the pivot 1.2/query 1.1 case where the values were saved as
+ // numbers
+ bool ok = false;
+ i = datelockstr.toUInt ( &ok );
+ if ( !ok )
+ {
+ i = kDateLockText.findIndex ( datelockstr );
+ if ( i == -1 )
+ i = userDefined;
+ }
+ setDateFilter ( static_cast<dateOptionE> ( i ) );
+
+ i = kRowTypeText.findIndex ( e.attribute ( "rowtype", "expenseincome" ) );
+ if ( i != -1 )
+ {
+ setRowType ( static_cast<ERowType> ( i ) );
+ // recent versions of KMyMoney always showed a total column for
+ // income/expense reports. We turn it on for backward compatability
+ // here. If the total column is turned off, the flag will be reset
+ // in the next step
+ if ( i == eExpenseIncome )
+ m_showRowTotals = true;
+ }
+ if ( e.hasAttribute ( "showrowtotals" ) )
+ m_showRowTotals = e.attribute ( "showrowtotals" ).toUInt();
+
+ i = kColumnTypeText.findIndex ( e.attribute ( "columntype", "months" ) );
+ if ( i != -1 )
+ setColumnType ( static_cast<EColumnType> ( i ) );
+
+ unsigned qc = 0;
+ QStringList columns = QStringList::split ( ",", e.attribute ( "querycolumns", "none" ) );
+ QStringList::const_iterator it_column = columns.begin();
+ while ( it_column != columns.end() )
+ {
+ i = kQueryColumnsText.findIndex ( *it_column );
+ if ( i > 0 )
+ qc |= ( 1 << ( i - 1 ) );
+
+ ++it_column;
+ }
+ setQueryColumns ( static_cast<EQueryColumns> ( qc ) );
+
+ QDomNode child = e.firstChild();
+ while ( !child.isNull() && child.isElement() )
+ {
+ QDomElement c = child.toElement();
+ if ( "TEXT" == c.tagName() && c.hasAttribute ( "pattern" ) )
+ {
+ setTextFilter ( QRegExp ( c.attribute ( "pattern" ), c.attribute ( "casesensitive", "1" ).toUInt(), !c.attribute ( "regex", "1" ).toUInt() ), c.attribute ( "inverttext", "0" ).toUInt() );
+ }
+ if ( "TYPE" == c.tagName() && c.hasAttribute ( "type" ) )
+ {
+ i = kTypeText.findIndex ( c.attribute ( "type" ) );
+ if ( i != -1 )
+ addType ( i );
+ }
+ if ( "STATE" == c.tagName() && c.hasAttribute ( "state" ) )
+ {
+ i = kStateText.findIndex ( c.attribute ( "state" ) );
+ if ( i != -1 )
+ addState ( i );
+ }
+ if ( "NUMBER" == c.tagName() )
+ {
+ setNumberFilter ( c.attribute ( "from" ), c.attribute ( "to" ) );
+ }
+ if ( "AMOUNT" == c.tagName() )
+ {
+ setAmountFilter ( MyMoneyMoney ( c.attribute ( "from", "0/100" ) ), MyMoneyMoney ( c.attribute ( "to", "0/100" ) ) );
+ }
+ if ( "DATES" == c.tagName() )
+ {
+ QDate from, to;
+ if ( c.hasAttribute ( "from" ) )
+ from = QDate::fromString ( c.attribute ( "from" ), Qt::ISODate );
+ if ( c.hasAttribute ( "to" ) )
+ to = QDate::fromString ( c.attribute ( "to" ), Qt::ISODate );
+ MyMoneyTransactionFilter::setDateFilter ( from, to );
+ }
+ if ( "PAYEE" == c.tagName() )
+ {
+ addPayee ( c.attribute ( "id" ) );
+ }
+ if ( "CATEGORY" == c.tagName() && c.hasAttribute ( "id" ) )
+ {
+ addCategory ( c.attribute ( "id" ) );
+ }
+ if ( "ACCOUNT" == c.tagName() && c.hasAttribute ( "id" ) )
+ {
+ addAccount ( c.attribute ( "id" ) );
+ }
+ if ( "ACCOUNTGROUP" == c.tagName() && c.hasAttribute ( "group" ) )
+ {
+ i = kAccountTypeText.findIndex ( c.attribute ( "group" ) );
+ if ( i != -1 )
+ addAccountGroup ( static_cast<MyMoneyAccount::accountTypeE> ( i ) );
+ }
+ child = child.nextSibling();
+ }
+ }
+ return result;
+}
+
+void MyMoneyReport::writeXML ( QDomDocument& document, QDomElement& parent ) const
+{
+ QDomElement el = document.createElement ( "REPORT" );
+ write ( el, &document, false );
+ parent.appendChild ( el );
+}
+
+bool MyMoneyReport::hasReferenceTo ( const QString& id ) const
+{
+ QStringList list;
+
+ // collect all ids
+ accounts ( list );
+ categories ( list );
+ payees ( list );
+
+ return ( list.contains ( id ) > 0 );
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneyreport.h b/kmymoney2/mymoney/mymoneyreport.h
new file mode 100644
index 0000000..e467179
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyreport.h
@@ -0,0 +1,497 @@
+/***************************************************************************
+ mymoneyreport.h
+ -------------------
+ begin : Sun July 4 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYREPORT_H
+#define MYMONEYREPORT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qmap.h>
+#include <qvaluelist.h>
+#include <qstring.h>
+class QDomElement;
+class QDomDocument;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransactionfilter.h>
+#include <kmymoney/export.h>
+
+/**
+ * This class defines a report within the MyMoneyEngine. The report class
+ * contains all the configuration parameters needed to run a report, plus
+ * XML serialization.
+ *
+ * A report is a transactionfilter, so any report can specify which
+ * transactions it's interested down to the most minute level of detail.
+ * It extends the transactionfilter by providing identification (name,
+ * comments, group type, etc) as well as layout information (what kind
+ * of layout should be used, how the rows & columns should be presented,
+ * currency converted, etc.)
+ *
+ * As noted above, this class only provides a report DEFINITION. The
+ * generation and presentation of the report itself are left to higher
+ * level classes.
+ *
+ * @author Ace Jones <acejones@users.sourceforge.net>
+ */
+
+class KMYMONEY_EXPORT MyMoneyReport: public MyMoneyObject, public MyMoneyTransactionFilter
+{
+public:
+ // When adding a new row type, be sure to add a corresponding entry in kTypeArray
+ enum ERowType { eNoRows = 0, eAssetLiability, eExpenseIncome, eCategory, eTopCategory, eAccount, ePayee, eMonth, eWeek, eTopAccount, eAccountByTopAccount, eEquityType, eAccountType, eInstitution, eBudget, eBudgetActual, eSchedule, eAccountInfo, eAccountLoanInfo, eAccountReconcile, eCashFlow};
+ enum EReportType { eNoReport = 0, ePivotTable, eQueryTable, eInfoTable };
+ enum EColumnType { eNoColumns = 0, eDays = 1, eMonths = 1, eBiMonths = 2, eQuarters = 3, eWeeks = 7, eYears = 12 };
+
+ // if you add bits to this bitmask, start with the value currently assigned to eQCend and update its value afterwards
+ // also don't forget to add column names to kQueryColumnsText in mymoneyreport.cpp
+ enum EQueryColumns { eQCnone = 0x0, eQCbegin = 0x1, eQCnumber = 0x1, eQCpayee = 0x2, eQCcategory = 0x4, eQCmemo = 0x8, eQCaccount = 0x10, eQCreconciled = 0x20, eQCaction = 0x40, eQCshares = 0x80, eQCprice = 0x100, eQCperformance = 0x200, eQCloan = 0x400, eQCbalance = 0x800, eQCend = 0x1000 };
+
+ enum EDetailLevel { eDetailNone = 0, eDetailAll, eDetailTop, eDetailGroup, eDetailTotal, eDetailEnd };
+ enum EChartType { eChartNone = 0, eChartLine, eChartBar, eChartPie, eChartRing, eChartStackedBar, eChartEnd };
+
+ static const QStringList kRowTypeText;
+ static const QStringList kColumnTypeText;
+ static const QStringList kQueryColumnsText;
+ static const QStringList kDetailLevelText;
+ static const QStringList kChartTypeText;
+ static const EReportType kTypeArray[];
+
+public:
+ MyMoneyReport(void);
+ MyMoneyReport(ERowType _rt, unsigned _ct, dateOptionE _dl, EDetailLevel _ss, const QString& _name, const QString& _comment );
+ MyMoneyReport(const QString& id, const MyMoneyReport& right);
+
+ /**
+ * This constructor creates an object based on the data found in the
+ * QDomElement referenced by @p node. If problems arise, the @p id of
+ * the object is cleared (see MyMoneyObject::clearId()).
+ */
+ MyMoneyReport(const QDomElement& node);
+
+ // Simple get operations
+ const QString& name(void) const { return m_name; }
+ bool isShowingRowTotals(void) const { return (m_showRowTotals); }
+ EReportType reportType(void) const { return m_reportType; }
+ ERowType rowType(void) const { return m_rowType; }
+ EColumnType columnType(void) const { return m_columnType; }
+ bool isRunningSum(void) const { return (m_rowType==eAssetLiability); }
+ bool isConvertCurrency(void) const { return m_convertCurrency; }
+ unsigned columnPitch(void) const { return static_cast<unsigned>(m_columnType); }
+ bool isShowingColumnTotals(void) const { return m_convertCurrency; }
+ const QString& comment( void ) const { return m_comment; }
+ EQueryColumns queryColumns(void) const { return m_queryColumns; }
+ const QString& group( void ) const { return m_group; }
+ bool isFavorite(void) const { return m_favorite; }
+ bool isTax(void) const { return m_tax; }
+ bool isInvestmentsOnly(void) const { return m_investments; }
+ bool isLoansOnly(void) const { return m_loans; }
+ EDetailLevel detailLevel(void) const { return m_detailLevel; }
+ EChartType chartType(void) const { return m_chartType; }
+ bool isChartDataLabels(void) const { return m_chartDataLabels; }
+ bool isChartGridLines(void) const { return m_chartGridLines; }
+ bool isChartByDefault(void) const { return m_chartByDefault; }
+ uint chartLineWidth(void) const { return m_chartLineWidth; }
+ bool isIncludingSchedules(void) const { return m_includeSchedules; }
+ bool isColumnsAreDays(void) const { return m_columnsAreDays; }
+ bool isIncludingTransfers(void) const { return m_includeTransfers; }
+ bool isIncludingUnusedAccounts(void) const { return m_includeUnusedAccounts; }
+ bool hasBudget(void) const { return !m_budgetId.isEmpty(); }
+ const QString& budget(void) const { return m_budgetId; }
+ bool isIncludingBudgetActuals(void) const { return m_includeBudgetActuals; }
+ bool isIncludingForecast(void) const { return m_includeForecast; }
+ bool isIncludingMovingAverage(void) const { return m_includeMovingAverage; }
+ int movingAverageDays(void) const { return m_movingAverageDays; }
+ bool isIncludingPrice(void) const { return m_includePrice; }
+ bool isIncludingAveragePrice(void) const { return m_includeAveragePrice; }
+ bool isUserDefined(void) const { return m_dateLock == userDefined; }
+
+ // Simple set operations
+ void setName(const QString& _s) { m_name = _s; }
+ void setConvertCurrency(bool _f) { m_convertCurrency = _f; }
+ void setRowType(ERowType _rt);
+ void setColumnType(EColumnType _ct) { m_columnType = _ct; }
+ void setComment( const QString& _comment ) { m_comment = _comment; }
+ void setGroup( const QString& _group ) { m_group = _group; }
+ void setFavorite(bool _f) { m_favorite = _f; }
+ void setQueryColumns( EQueryColumns _qc ) { m_queryColumns = _qc; }
+ void setTax(bool _f) { m_tax = _f; }
+ void setInvestmentsOnly(bool _f) { m_investments = _f; if (_f) m_loans = false; }
+ void setLoansOnly(bool _f) { m_loans = _f; if (_f) m_investments = false; }
+ void setDetailLevel( EDetailLevel _detail ) { m_detailLevel = _detail; }
+ void setChartType ( EChartType _type ) { m_chartType = _type; }
+ void setChartDataLabels ( bool _f ) { m_chartDataLabels = _f; }
+ void setChartGridLines ( bool _f ) { m_chartGridLines = _f; }
+ void setChartByDefault ( bool _f ) { m_chartByDefault = _f; }
+ void setChartLineWidth ( uint _f ) { m_chartLineWidth = _f; }
+ void setIncludingSchedules( bool _f ) { m_includeSchedules = _f; }
+ void setColumnsAreDays( bool _f ) { m_columnsAreDays = _f; }
+ void setIncludingTransfers( bool _f ) { m_includeTransfers = _f; }
+ void setIncludingUnusedAccounts( bool _f ) { m_includeUnusedAccounts = _f; }
+ void setShowingRowTotals( bool _f ) { m_showRowTotals = _f; }
+ void setIncludingBudgetActuals( bool _f ) { m_includeBudgetActuals = _f; }
+ void setIncludingForecast( bool _f ) { m_includeForecast = _f; }
+ void setIncludingMovingAverage( bool _f ) { m_includeMovingAverage = _f; }
+ void setMovingAverageDays( int _days ) { m_movingAverageDays = _days; }
+ void setIncludingPrice( bool _f ) { m_includePrice = _f; }
+ void setIncludingAveragePrice( bool _f ) { m_includeAveragePrice = _f; }
+
+ /**
+ * Sets the budget used for this report
+ *
+ * @param _budget The ID of the budget to use, or an empty string
+ * to indicate a budget is NOT included
+ * @param _fa Whether to display actual data alongside the budget.
+ * Setting to false means the report displays ONLY the budget itself.
+ * @warning For now, the budget ID is ignored. The budget id is
+ * simply checked for any non-empty string, and if so, hasBudget()
+ * will return true.
+ */
+ void setBudget( const QString& _budget, bool _fa = true ) { m_budgetId = _budget; m_includeBudgetActuals=_fa; }
+
+ /**
+ * This method allows you to clear the underlying transaction filter
+ */
+ void clear(void);
+
+ /**
+ * This method allows you to set the underlying transaction filter
+ *
+ * @param _filter The filter which should replace the existing transaction
+ * filter.
+ */
+ void assignFilter(const MyMoneyTransactionFilter& _filter) { MyMoneyTransactionFilter::operator=(_filter); }
+
+ /**
+ * Set the underlying date filter and LOCK that filter to the specified
+ * range. For example, if @p _u is "CurrentMonth", this report should always
+ * be updated to the current month no matter when the report is run.
+ *
+ * This updating is not entirely automatic, you should update it yourself by
+ * calling updateDateFilter.
+ *
+ * @param _u The date range constant (MyMoneyTransactionFilter::dateRangeE)
+ * which this report should be locked to.
+ */
+
+ void setDateFilter(dateOptionE _u)
+ {
+ m_dateLock = _u;
+ if (_u != userDefined)
+ MyMoneyTransactionFilter::setDateFilter( _u );
+ }
+
+ /**
+ * Set the underlying date filter using the start and end dates provided.
+ * Note that this does not LOCK to any range like setDateFilter(unsigned)
+ * above. It is just a reimplementation of the MyMoneyTransactionFilter
+ * version.
+ *
+ * @param _db The inclusive begin date of the date range
+ * @param _de The inclusive end date of the date range
+ */
+
+ void setDateFilter(const QDate& _db,const QDate& _de) { MyMoneyTransactionFilter::setDateFilter( _db,_de ); }
+
+ /**
+ * Set the underlying date filter using the 'date lock' property.
+ *
+ * Always call this function before executing the report to be sure that
+ * the date filters properly match the plain-language 'date lock'.
+ *
+ * For example, if the report is date-locked to "Current Month", and the
+ * last time you loaded or ran the report was in August, but it's now
+ * September, this function will update the date range to be September,
+ * as is proper.
+ */
+ void updateDateFilter(void) { if (m_dateLock != userDefined) MyMoneyTransactionFilter::setDateFilter(m_dateLock); }
+
+ /**
+ * Retrieves a VALID beginning & ending date for this report.
+ *
+ * The underlying date filter can return en empty QDate() for either the
+ * begin or end date or both. This is typically unacceptable for reports,
+ * which need the REAL begin and end date.
+ *
+ * This function gets the underlying date filter range, and if either is
+ * an empty QDate(), it determines the missing date from looking at all
+ * the transactions which match the underlying filter, and returning the
+ * date of the first or last transaction (as appropriate).
+ *
+ * @param _db The inclusive begin date of the date range
+ * @param _de The inclusive end date of the date range
+ */
+ void validDateRange(QDate& _db, QDate& _de);
+
+ /**
+ * This method turns on the account group filter and adds the
+ * @p type to the list of allowed groups.
+ *
+ * Note that account group filtering is handled differently
+ * than all the filters of the underlying class. This filter
+ * is meant to be applied to individual splits of matched
+ * transactions AFTER the underlying filter is used to find
+ * the matching transactions.
+ *
+ * @param type the account group to add to the allowed groups list
+ */
+ void addAccountGroup(MyMoneyAccount::accountTypeE type);
+
+ /**
+ * This method returns whether an account group filter has been set,
+ * and if so, it returns all the account groups set in the filter.
+ *
+ * @param list list to append account groups into
+ * @return return true if an account group filter has been set
+ */
+ bool accountGroups(QValueList<MyMoneyAccount::accountTypeE>& list) const;
+
+ /**
+ * This method returns whether the specified account group
+ * is allowed by the account groups filter.
+ *
+ * @param type group to append account groups into
+ * @return return true if an account group filter has been set
+ */
+ bool includesAccountGroup( MyMoneyAccount::accountTypeE type ) const;
+
+ /**
+ * This method is used to test whether a specific account
+ * passes the accountGroup test and either the Account or
+ * Category test, depending on which sort of Account it is.
+ *
+ * The m_tax and m_investments properties are also considered.
+ *
+ * @param acc the account in question
+ * @return true if account is in filter set, false otherwise
+ */
+ bool includes( const MyMoneyAccount& acc ) const;
+
+ /**
+ * This method writes this report to the DOM element @p e,
+ * within the DOM document @p doc.
+ *
+ * @param e The element which should be populated with info from this report
+ * @param doc The document which we can use to create new sub-elements
+ * if needed
+ * @param anonymous Whether the sensitive parts of the report should be
+ * masked
+ */
+ void write(QDomElement& e, QDomDocument *doc, bool anonymous=false) const;
+
+ /**
+ * This method reads a report from the DOM element @p e, and
+ * populates this report with the results.
+ *
+ * @param e The element from which the report should be read
+ *
+ * @return bool True if a report was successfully loaded from the
+ * element @p e. If false is returned, the contents of this report
+ * object are undefined.
+ */
+ bool read(const QDomElement& e);
+
+ /**
+ * This method creates a QDomElement for the @p document
+ * under the parent node @p parent. (This version overwrites the
+ * MMObject base class.)
+ *
+ * @param document reference to QDomDocument
+ * @param parent reference to QDomElement parent node
+ */
+ virtual void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+private:
+ /**
+ * The user-assigned name of the report
+ */
+ QString m_name;
+ /**
+ * The user-assigned comment for the report, in case they want to make
+ * additional notes for themselves about the report.
+ */
+ QString m_comment;
+ /**
+ * Where to group this report amongst the others in the UI view. This
+ * should be assigned by the UI system.
+ */
+ QString m_group;
+ /**
+ * How much detail to show in the accounts
+ */
+ enum EDetailLevel m_detailLevel;
+ /**
+ * Whether to convert all currencies to the base currency of the file (true).
+ * If this is false, it's up to the report generator to decide how to handle
+ * the currency.
+ */
+ bool m_convertCurrency;
+ /**
+ * Whether this is one of the users' favorite reports
+ */
+ bool m_favorite;
+ /**
+ * Whether this report should only include categories marked as "Tax"="Yes"
+ */
+ bool m_tax;
+ /**
+ * Whether this report should only include investment accounts
+ */
+ bool m_investments;
+ /**
+ * Whether this report should only include loan accounts
+ * Applies only to querytable reports. Mutually exclusive with
+ * m_investments.
+ */
+ bool m_loans;
+ /**
+ * What sort of algorithm should be used to run the report
+ */
+ enum EReportType m_reportType;
+ /**
+ * What sort of values should show up on the ROWS of this report
+ */
+ enum ERowType m_rowType;
+ /**
+ * What sort of values should show up on the COLUMNS of this report,
+ * in the case of a 'PivotTable' report. Really this is used more as a
+ * QUANTITY of months or days. Whether it's months or days is determiend
+ * by m_columnsAreDays.
+ */
+ enum EColumnType m_columnType;
+ /**
+ * Whether the base unit of columns of this report is days. Only applies to
+ * 'PivotTable' reports. If false, then columns are months or multiples thereof.
+ */
+ bool m_columnsAreDays;
+ /**
+ * What sort of values should show up on the COLUMNS of this report,
+ * in the case of a 'QueryTable' report
+ */
+ enum EQueryColumns m_queryColumns;
+
+ /**
+ * The plain-language description of what the date range should be locked
+ * to. 'userDefined' means NO locking, in any other case, the report
+ * will be adjusted to match the date lock. So if the date lock is
+ * 'currentMonth', the start and end dates of the underlying filter will
+ * be updated to whatever the current month is. This updating happens
+ * automatically when the report is loaded, and should also be done
+ * manually by calling updateDateFilter() before generating the report
+ */
+ dateOptionE m_dateLock;
+ /**
+ * Which account groups should be included in the report. This filter
+ * is applied to the individual splits AFTER a transaction has been
+ * matched using the underlying filter.
+ */
+ QValueList<MyMoneyAccount::accountTypeE> m_accountGroups;
+ /**
+ * Whether an account group filter has been set (see m_accountGroups)
+ */
+ bool m_accountGroupFilter;
+ /**
+ * What format should be used to draw this report as a chart
+ */
+ enum EChartType m_chartType;
+ /**
+ * Whether the value of individual data points should be drawn on the chart
+ */
+ bool m_chartDataLabels;
+ /**
+ * Whether grid lines should be drawn on the chart
+ */
+ bool m_chartGridLines;
+ /**
+ * Whether this report should be shown as a chart by default (otherwise it
+ * should be shown as a textual report)
+ */
+ bool m_chartByDefault;
+ /**
+ * Width of the chart lines
+ */
+ uint m_chartLineWidth;
+ /**
+ * Whether to include scheduled transactions
+ */
+ bool m_includeSchedules;
+ /**
+ * Whether to include transfers. Only applies to Income/Expense reports
+ */
+ bool m_includeTransfers;
+ /**
+ * The id of the budget associated with this report.
+ */
+ QString m_budgetId;
+ /**
+ * Whether this report should print the actual data to go along with
+ * the budget. This is only valid if the report has a budget.
+ */
+ bool m_includeBudgetActuals;
+ /**
+ * Whether this report should include all accounts and not only
+ * accounts with transactions.
+ */
+ bool m_includeUnusedAccounts;
+ /**
+ * Whether this report should include columns for row totals
+ */
+ bool m_showRowTotals;
+ /**
+ * Whether this report should include forecast balance
+ */
+ bool m_includeForecast;
+ /**
+ * Whether this report should include moving average
+ */
+ bool m_includeMovingAverage;
+ /**
+ * The amount of days that spans each moving average
+ */
+ int m_movingAverageDays;
+ /**
+ * Whether this report should include prices
+ */
+ bool m_includePrice;
+ /**
+ * Whether this report should include moving average prices
+ */
+ bool m_includeAveragePrice;
+
+
+
+};
+
+#endif // MYMONEYREPORT_H
diff --git a/kmymoney2/mymoney/mymoneyscheduled.cpp b/kmymoney2/mymoney/mymoneyscheduled.cpp
new file mode 100644
index 0000000..88b4c7b
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyscheduled.cpp
@@ -0,0 +1,1372 @@
+/***************************************************************************
+ mymoneyscheduled.cpp
+ -------------------
+ copyright : (C) 2000-2002 by Michael Edwardes
+ (C) 2007 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyscheduled.h"
+#include "mymoneyexception.h"
+#include "mymoneyfile.h"
+
+MyMoneySchedule::MyMoneySchedule() :
+ MyMoneyObject()
+{
+ // Set up the default values
+ m_occurence = OCCUR_ANY;
+ m_occurenceMultiplier = 1;
+ m_type = TYPE_ANY;
+ m_paymentType = STYPE_ANY;
+ m_fixed = false;
+ m_autoEnter = false;
+ m_startDate = QDate();
+ m_endDate = QDate();
+ m_lastPayment = QDate();
+ m_weekendOption = MoveNothing;
+}
+
+MyMoneySchedule::MyMoneySchedule(const QString& name, typeE type,
+ occurenceE occurence, int occurenceMultiplier,
+ paymentTypeE paymentType,
+ const QDate& /* startDate */,
+ const QDate& endDate,
+ bool fixed, bool autoEnter) :
+ MyMoneyObject()
+{
+ // Set up the default values
+ m_name = name;
+ m_occurence = occurence;
+ m_occurenceMultiplier = occurenceMultiplier;
+ simpleToCompoundOccurence(m_occurenceMultiplier,m_occurence);
+ m_type = type;
+ m_paymentType = paymentType;
+ m_fixed = fixed;
+ m_autoEnter = autoEnter;
+ m_startDate = QDate();
+ m_endDate = endDate;
+ m_lastPayment = QDate();
+ m_weekendOption = MoveNothing;
+}
+
+MyMoneySchedule::MyMoneySchedule(const QDomElement& node) :
+ MyMoneyObject(node)
+{
+ if("SCHEDULED_TX" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not SCHEDULED_TX");
+
+ m_name = node.attribute("name");
+ m_startDate = stringToDate(node.attribute("startDate"));
+ m_endDate = stringToDate(node.attribute("endDate"));
+ m_lastPayment = stringToDate(node.attribute("lastPayment"));
+
+ m_type = static_cast<MyMoneySchedule::typeE>(node.attribute("type").toInt());
+ m_paymentType = static_cast<MyMoneySchedule::paymentTypeE>(node.attribute("paymentType").toInt());
+ m_occurence = static_cast<MyMoneySchedule::occurenceE>(node.attribute("occurence").toInt());
+ m_occurenceMultiplier = node.attribute("occurenceMultiplier", "1").toInt();
+ // Convert to compound occurence
+ simpleToCompoundOccurence(m_occurenceMultiplier,m_occurence);
+ m_autoEnter = static_cast<bool>(node.attribute("autoEnter").toInt());
+ m_fixed = static_cast<bool>(node.attribute("fixed").toInt());
+ m_weekendOption = static_cast<MyMoneySchedule::weekendOptionE>(node.attribute("weekendOption").toInt());
+
+ // read in the associated transaction
+ QDomNodeList nodeList = node.elementsByTagName("TRANSACTION");
+ if(nodeList.count() == 0)
+ throw new MYMONEYEXCEPTION("SCHEDULED_TX has no TRANSACTION node");
+
+ setTransaction(MyMoneyTransaction(nodeList.item(0).toElement(), false), true);
+
+ // some old versions did not remove the entry date and post date fields
+ // in the schedule. So if this is the case, we deal with a very old transaction
+ // and can't use the post date field as next due date. Hence, we wipe it out here
+ if(m_transaction.entryDate().isValid()) {
+ m_transaction.setPostDate(QDate());
+ m_transaction.setEntryDate(QDate());
+ }
+
+ // readin the recorded payments
+ nodeList = node.elementsByTagName("PAYMENTS");
+ if(nodeList.count() > 0) {
+ nodeList = nodeList.item(0).toElement().elementsByTagName("PAYMENT");
+ for(unsigned int i = 0; i < nodeList.count(); ++i) {
+ m_recordedPayments << stringToDate(nodeList.item(i).toElement().attribute("date"));
+ }
+ }
+
+ // if the next due date is not set (comes from old version)
+ // then set it up the old way
+ if(!nextDueDate().isValid() && !m_lastPayment.isValid()) {
+ m_transaction.setPostDate(m_startDate);
+ // clear it, because the schedule has never been used
+ m_startDate = QDate();
+ }
+
+ // There are reports that lastPayment and nextDueDate are identical or
+ // that nextDueDate is older than lastPayment. This could
+ // be caused by older versions of the application. In this case, we just
+ // clear out the nextDueDate and let it calculate from the lastPayment.
+ if(nextDueDate().isValid() && nextDueDate() <= m_lastPayment) {
+ m_transaction.setPostDate(QDate());
+ }
+
+ if(!nextDueDate().isValid()) {
+ m_transaction.setPostDate(m_startDate);
+ m_transaction.setPostDate(nextPayment(m_lastPayment.addDays(1)));
+ }
+}
+
+MyMoneySchedule::MyMoneySchedule(const QString& id, const MyMoneySchedule& right) :
+ MyMoneyObject(id)
+{
+ *this = right;
+ setId(id);
+}
+
+MyMoneySchedule::occurenceE MyMoneySchedule::occurence(void) const
+{
+ MyMoneySchedule::occurenceE occ = m_occurence;
+ int mult = m_occurenceMultiplier;
+ compoundToSimpleOccurence(mult, occ);
+ return occ;
+}
+
+void MyMoneySchedule::setStartDate(const QDate& date)
+{
+ m_startDate = date;
+}
+
+void MyMoneySchedule::setPaymentType(paymentTypeE type)
+{
+ m_paymentType = type;
+}
+
+void MyMoneySchedule::setFixed(bool fixed)
+{
+ m_fixed = fixed;
+}
+
+void MyMoneySchedule::setTransaction(const MyMoneyTransaction& transaction)
+{
+ setTransaction(transaction, false);
+}
+
+void MyMoneySchedule::setTransaction(const MyMoneyTransaction& transaction, bool noDateCheck)
+{
+ MyMoneyTransaction t = transaction;
+ if(!noDateCheck) {
+ // don't allow a transaction that has no due date
+ // if we get something like that, then we use the
+ // the current next due date. If that is also invalid
+ // we can't help it.
+ if(!t.postDate().isValid()) {
+ t.setPostDate(m_transaction.postDate());
+ }
+
+ if(!t.postDate().isValid())
+ return;
+ }
+
+ // make sure to clear out some unused information in scheduled transactions
+ // we need to do this for the case that the transaction passed as argument
+ // is a matched or imported transaction.
+ QValueList<MyMoneySplit> splits = t.splits();
+ if(splits.count() > 0) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ MyMoneySplit s = *it_s;
+ // clear out the bankID
+ if(!(*it_s).bankID().isEmpty()) {
+ s.setBankID(QString());
+ t.modifySplit(s);
+ }
+
+ // only clear payees from second split onwards
+ if(it_s == splits.begin())
+ continue;
+
+ if(!(*it_s).payeeId().isEmpty()) {
+ // but only if the split references an income/expense category
+ MyMoneyFile* file = MyMoneyFile::instance();
+ // some unit tests don't have a storage attached, so we
+ // simply skip the test
+ // Don't check for accounts with an id of 'Phony-ID' which is used
+ // internally for non-existing accounts (during creation of accounts)
+ if(file->storageAttached() && s.accountId() != QString("Phony-ID")) {
+ MyMoneyAccount acc = file->account(s.accountId());
+ if(acc.isIncomeExpense()) {
+ s.setPayeeId(QString());
+ t.modifySplit(s);
+ }
+ }
+ }
+ }
+ }
+
+ m_transaction = t;
+ // make sure that the transaction does not have an id so that we can enter
+ // it into the engine
+ m_transaction.clearId();
+}
+
+void MyMoneySchedule::setEndDate(const QDate& date)
+{
+ m_endDate = date;
+}
+
+void MyMoneySchedule::setAutoEnter(bool autoenter)
+{
+ m_autoEnter = autoenter;
+}
+
+const QDate& MyMoneySchedule::startDate(void) const
+{
+ if(m_startDate.isValid())
+ return m_startDate;
+ return nextDueDate();
+}
+
+const QDate& MyMoneySchedule::nextDueDate(void) const
+{
+ return m_transaction.postDate();
+}
+
+QDate MyMoneySchedule::adjustedNextDueDate(void) const
+{
+ if(isFinished())
+ return QDate();
+
+ return adjustedDate(nextDueDate(), weekendOption());
+}
+
+QDate MyMoneySchedule::adjustedDate(QDate date, weekendOptionE option) const
+{
+ if (option == MyMoneySchedule::MoveNothing)
+ return date;
+
+ int step = 1;
+ if (option == MyMoneySchedule::MoveFriday)
+ step = -1;
+
+ while (date.dayOfWeek() > 5)
+ date = date.addDays(step);
+
+ return date;
+}
+
+void MyMoneySchedule::setNextDueDate(const QDate& date)
+{
+ if(date.isValid()) {
+ m_transaction.setPostDate(date);
+ m_startDate = date;
+ }
+}
+
+void MyMoneySchedule::setLastPayment(const QDate& date)
+{
+ // Delete all payments older than date
+ QValueList<QDate>::Iterator it;
+ QValueList<QDate> delList;
+
+ for (it=m_recordedPayments.begin(); it!=m_recordedPayments.end(); ++it)
+ {
+ if (*it < date || !date.isValid())
+ delList.append(*it);
+ }
+
+ for (it=delList.begin(); it!=delList.end(); ++it)
+ {
+ m_recordedPayments.remove(*it);
+ }
+
+ m_lastPayment = date;
+ if(!m_startDate.isValid())
+ m_startDate = date;
+}
+
+void MyMoneySchedule::setName(const QString& nm)
+{
+ m_name = nm;
+}
+
+void MyMoneySchedule::setOccurence(occurenceE occ)
+{
+ MyMoneySchedule::occurenceE occ2 = occ;
+ int mult = 1;
+ simpleToCompoundOccurence(mult, occ2);
+ setOccurencePeriod( occ2 );
+ setOccurenceMultiplier( mult );
+}
+
+void MyMoneySchedule::setOccurencePeriod(occurenceE occ)
+{
+ m_occurence = occ;
+}
+
+void MyMoneySchedule::setOccurenceMultiplier(int occmultiplier)
+{
+ m_occurenceMultiplier = occmultiplier < 1 ? 1 : occmultiplier;
+}
+
+void MyMoneySchedule::setType(typeE type)
+{
+ m_type = type;
+}
+
+void MyMoneySchedule::validate(bool id_check) const
+{
+ /* Check the supplied instance is valid...
+ *
+ * To be valid it must not have the id set and have the following fields set:
+ *
+ * m_occurence
+ * m_type
+ * m_startDate
+ * m_paymentType
+ * m_transaction
+ * the transaction must contain at least one split (two is better ;-) )
+ */
+ if (id_check && !m_id.isEmpty())
+ throw new MYMONEYEXCEPTION("ID for schedule not empty when required");
+
+ if(m_occurence == OCCUR_ANY)
+ throw new MYMONEYEXCEPTION("Invalid occurence type for schedule");
+
+ if(m_type == TYPE_ANY)
+ throw new MYMONEYEXCEPTION("Invalid type for schedule");
+
+ if(!nextDueDate().isValid())
+ throw new MYMONEYEXCEPTION("Invalid next due date for schedule");
+
+ if(m_paymentType == STYPE_ANY)
+ throw new MYMONEYEXCEPTION("Invalid payment type for schedule");
+
+ if(m_transaction.splitCount() == 0)
+ throw new MYMONEYEXCEPTION("Scheduled transaction does not contain splits");
+
+ // Check the payment types
+ switch (m_type)
+ {
+ case TYPE_BILL:
+ if (m_paymentType == STYPE_DIRECTDEPOSIT || m_paymentType == STYPE_MANUALDEPOSIT)
+ throw new MYMONEYEXCEPTION("Invalid payment type for bills");
+ break;
+
+ case TYPE_DEPOSIT:
+ if (m_paymentType == STYPE_DIRECTDEBIT || m_paymentType == STYPE_WRITECHEQUE)
+ throw new MYMONEYEXCEPTION("Invalid payment type for deposits");
+ break;
+
+ case TYPE_ANY:
+ throw new MYMONEYEXCEPTION("Invalid type ANY");
+ break;
+
+ case TYPE_TRANSFER:
+// if (m_paymentType == STYPE_DIRECTDEPOSIT || m_paymentType == STYPE_MANUALDEPOSIT)
+// return false;
+ break;
+
+ case TYPE_LOANPAYMENT:
+ break;
+ }
+}
+
+QDate MyMoneySchedule::adjustedNextPayment(const QDate& refDate) const
+{
+ QDate date(nextPayment(refDate));
+ return date.isValid() ? adjustedDate(date, weekendOption()) : date;
+}
+
+QDate MyMoneySchedule::nextPayment(const QDate& refDate) const
+{
+ // if the enddate is valid and it is before the reference date,
+ // then there will be no more payments.
+ if(m_endDate.isValid() && m_endDate < refDate) {
+ return QDate();
+ }
+
+ QDate paymentDate(nextDueDate());
+
+ if(refDate >= paymentDate) {
+ switch (m_occurence)
+ {
+ case OCCUR_ONCE:
+ // if the lastPayment is already set, then there will be no more payments
+ // otherwise, the start date is the payment date
+ if(m_lastPayment.isValid())
+ return QDate();
+ // if the only payment should have been prior to the reference date,
+ // then don't show it
+ if(paymentDate < refDate)
+ return QDate();
+ break;
+
+ case OCCUR_DAILY:
+ paymentDate = refDate.addDays(m_occurenceMultiplier);
+ break;
+
+ case OCCUR_WEEKLY:
+ {
+ int step = 7*m_occurenceMultiplier;
+ do {
+ paymentDate = paymentDate.addDays(step);
+ }
+ while (paymentDate <= refDate);
+ }
+ break;
+
+ case OCCUR_EVERYHALFMONTH:
+ do
+ {
+ paymentDate = addHalfMonths(paymentDate,m_occurenceMultiplier);
+ }
+ while (paymentDate <= refDate);
+ break;
+
+ case OCCUR_MONTHLY:
+ do {
+ paymentDate = paymentDate.addMonths(m_occurenceMultiplier);
+ fixDate(paymentDate);
+ }
+ while (paymentDate <= refDate);
+ break;
+
+ case OCCUR_YEARLY:
+ do {
+ paymentDate = paymentDate.addYears(m_occurenceMultiplier);
+ fixDate(paymentDate);
+ }
+ while (paymentDate <= refDate);
+ break;
+
+ case OCCUR_ANY:
+ default:
+ paymentDate = QDate();
+ break;
+ }
+ }
+ if(paymentDate.isValid()) {
+ if(m_endDate.isValid() && paymentDate > m_endDate)
+ paymentDate = QDate();
+ }
+
+ if (paymentDate.isValid() && m_recordedPayments.contains(paymentDate))
+ paymentDate = nextPayment(paymentDate);
+
+ return paymentDate;
+}
+
+QValueList<QDate> MyMoneySchedule::paymentDates(const QDate& _startDate, const QDate& _endDate) const
+{
+ QDate paymentDate(nextDueDate());
+ QValueList<QDate> theDates;
+
+ QDate endDate(_endDate);
+ if ( willEnd() && m_endDate < endDate )
+ endDate = m_endDate;
+
+ weekendOptionE option(weekendOption());
+ QDate start_date(adjustedDate(startDate(), option));
+ // if the period specified by the parameters and the period
+ // defined for this schedule don't overlap, then the list remains empty
+ if ((willEnd() && m_endDate < _startDate)
+ || start_date > endDate)
+ return theDates;
+
+ QDate date(adjustedDate(paymentDate, option));
+
+ switch (m_occurence)
+ {
+ case OCCUR_ONCE:
+ if (start_date >= _startDate && start_date <= endDate)
+ theDates.append(start_date);
+ break;
+
+ case OCCUR_DAILY:
+ while (date.isValid() && (date <= endDate))
+ {
+ if (date >= _startDate)
+ theDates.append(date);
+ paymentDate = paymentDate.addDays(m_occurenceMultiplier);
+ date = adjustedDate(paymentDate, option);
+ }
+ break;
+
+ case OCCUR_WEEKLY:
+ {
+ int step = 7*m_occurenceMultiplier;
+ while (date.isValid() && (date <= endDate))
+ {
+ if (date >= _startDate)
+ theDates.append(date);
+ paymentDate = paymentDate.addDays(step);
+ date = adjustedDate(paymentDate, option);
+ }
+ }
+ break;
+
+ case OCCUR_EVERYHALFMONTH:
+ while (date.isValid() && (date <= endDate))
+ {
+ if (date >= _startDate)
+ theDates.append(date);
+ paymentDate = addHalfMonths(paymentDate,m_occurenceMultiplier);
+ date = adjustedDate(paymentDate, option);
+ }
+ break;
+
+ case OCCUR_MONTHLY:
+ while (date.isValid() && (date <= endDate))
+ {
+ if (date >= _startDate)
+ theDates.append(date);
+ paymentDate = paymentDate.addMonths(m_occurenceMultiplier);
+ fixDate(paymentDate);
+ date = adjustedDate(paymentDate, option);
+ }
+ break;
+
+ case OCCUR_YEARLY:
+ while (date.isValid() && (date <= endDate))
+ {
+ if (date >= _startDate)
+ theDates.append(date);
+ paymentDate = paymentDate.addYears(m_occurenceMultiplier);
+ fixDate(paymentDate);
+ date = adjustedDate(paymentDate, option);
+ }
+ break;
+
+ case OCCUR_ANY:
+ default:
+ break;
+ }
+
+ return theDates;
+}
+
+bool MyMoneySchedule::operator <(const MyMoneySchedule& right) const
+{
+ return adjustedNextDueDate() < right.adjustedNextDueDate();
+}
+
+bool MyMoneySchedule::operator ==(const MyMoneySchedule& right) const
+{
+ if ( MyMoneyObject::operator==(right) &&
+ m_occurence == right.m_occurence &&
+ m_occurenceMultiplier == right.m_occurenceMultiplier &&
+ m_type == right.m_type &&
+ m_startDate == right.m_startDate &&
+ m_paymentType == right.m_paymentType &&
+ m_fixed == right.m_fixed &&
+ m_transaction == right.m_transaction &&
+ m_endDate == right.m_endDate &&
+ m_autoEnter == right.m_autoEnter &&
+ m_lastPayment == right.m_lastPayment &&
+ ((m_name.length() == 0 && right.m_name.length() == 0) || (m_name == right.m_name)))
+ return true;
+ return false;
+}
+
+int MyMoneySchedule::transactionsRemaining(void) const
+{
+ int counter=0;
+
+ if (m_endDate.isValid())
+ {
+ QValueList<QDate> dates = paymentDates(m_lastPayment, m_endDate);
+ // Dont include the last payment so -1
+ counter = dates.count();
+ }
+ return counter;
+}
+
+MyMoneyAccount MyMoneySchedule::account(int cnt) const
+{
+ QValueList<MyMoneySplit> splits = m_transaction.splits();
+ QValueList<MyMoneySplit>::ConstIterator it;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount acc;
+
+ // search the first asset or liability account
+ for(it = splits.begin(); it != splits.end() && (acc.id().isEmpty() || cnt); ++it) {
+ try {
+ acc = file->account((*it).accountId());
+ if(acc.isAssetLiability())
+ --cnt;
+
+ if(!cnt)
+ return acc;
+ } catch(MyMoneyException *e) {
+ qWarning("Schedule '%s' references unknown account '%s'", id().data(), (*it).accountId().data());
+ delete e;
+ return MyMoneyAccount();
+ }
+ }
+
+ return MyMoneyAccount();
+}
+
+QDate MyMoneySchedule::dateAfter(int transactions) const
+{
+ int counter=1;
+ QDate paymentDate(startDate());
+
+ if (transactions<=0)
+ return paymentDate;
+
+ switch (m_occurence)
+ {
+ case OCCUR_ONCE:
+ break;
+
+ case OCCUR_DAILY:
+ while (counter++ < transactions)
+ paymentDate = paymentDate.addDays(m_occurenceMultiplier);
+ break;
+
+ case OCCUR_WEEKLY:
+ {
+ int step = 7 * m_occurenceMultiplier;
+ while (counter++ < transactions)
+ paymentDate = paymentDate.addDays(step);
+ }
+ break;
+
+ case OCCUR_EVERYHALFMONTH:
+ paymentDate = addHalfMonths(paymentDate,m_occurenceMultiplier*(transactions-1));
+ break;
+
+ case OCCUR_MONTHLY:
+ while (counter++ < transactions)
+ paymentDate = paymentDate.addMonths(m_occurenceMultiplier);
+ break;
+
+ case OCCUR_YEARLY:
+ while (counter++ < transactions)
+ paymentDate = paymentDate.addYears(m_occurenceMultiplier);
+ break;
+
+ case OCCUR_ANY:
+ default:
+ break;
+ }
+
+ return paymentDate;
+}
+
+bool MyMoneySchedule::isOverdue() const
+{
+ if (isFinished())
+ return false;
+
+ if(adjustedNextDueDate() >= QDate::currentDate())
+ return false;
+
+ return true;
+}
+
+bool MyMoneySchedule::isFinished() const
+{
+ if(!m_lastPayment.isValid())
+ return false;
+
+ if (m_endDate.isValid()) {
+ if(m_lastPayment >= m_endDate
+ || !nextDueDate().isValid()
+ || nextDueDate() > m_endDate)
+ return true;
+ }
+
+ // Check to see if its a once off payment
+ if (m_occurence == MyMoneySchedule::OCCUR_ONCE)
+ return true;
+
+ return false;
+}
+
+bool MyMoneySchedule::hasRecordedPayment(const QDate& date) const
+{
+ // m_lastPayment should always be > recordedPayments()
+ if (m_lastPayment.isValid() && m_lastPayment >= date)
+ return true;
+
+ if (m_recordedPayments.contains(date))
+ return true;
+
+ return false;
+}
+
+void MyMoneySchedule::recordPayment(const QDate& date)
+{
+ m_recordedPayments.append(date);
+}
+
+void MyMoneySchedule::setWeekendOption(const weekendOptionE option)
+{
+ // make sure only valid values are used. Invalid defaults to MoveNothing.
+ switch(option) {
+ case MoveFriday:
+ case MoveMonday:
+ m_weekendOption = option;
+ break;
+
+ default:
+ m_weekendOption = MoveNothing;
+ break;
+ }
+}
+
+void MyMoneySchedule::fixDate(QDate& date) const
+{
+ QDate fixDate(m_startDate);
+ if(fixDate.isValid()
+ && date.day() != fixDate.day()
+ && QDate::isValid(date.year(), date.month(), fixDate.day())) {
+ date.setYMD(date.year(), date.month(), fixDate.day());
+ }
+}
+
+void MyMoneySchedule::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("SCHEDULED_TX");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("name", m_name);
+ el.setAttribute("type", m_type);
+ el.setAttribute("occurence", m_occurence);
+ el.setAttribute("occurenceMultiplier", m_occurenceMultiplier);
+ el.setAttribute("paymentType", m_paymentType);
+ el.setAttribute("startDate", dateToString(m_startDate));
+ el.setAttribute("endDate", dateToString(m_endDate));
+ el.setAttribute("fixed", m_fixed);
+ el.setAttribute("autoEnter", m_autoEnter);
+ el.setAttribute("lastPayment", dateToString(m_lastPayment));
+ el.setAttribute("weekendOption", m_weekendOption);
+
+ //store the payment history for this scheduled task.
+ QValueList<QDate> payments = recordedPayments();
+ QValueList<QDate>::ConstIterator it;
+ QDomElement paymentsElement = document.createElement("PAYMENTS");
+ for (it=payments.begin(); it!=payments.end(); ++it) {
+ QDomElement paymentEntry = document.createElement("PAYMENT");
+ paymentEntry.setAttribute("date", dateToString(*it));
+ paymentsElement.appendChild(paymentEntry);
+ }
+ el.appendChild(paymentsElement);
+
+ //store the transaction data for this task.
+ m_transaction.writeXML(document, el);
+
+ parent.appendChild(el);
+}
+
+bool MyMoneySchedule::hasReferenceTo(const QString& id) const
+{
+ return m_transaction.hasReferenceTo(id);
+}
+
+QString MyMoneySchedule::occurenceToString() const
+{
+ return occurenceToString( occurenceMultiplier(), occurencePeriod() );
+}
+
+QString MyMoneySchedule::occurenceToString(occurenceE occurence)
+{
+ QString occurenceString = I18N_NOOP("Any");
+
+ if(occurence == MyMoneySchedule::OCCUR_ONCE)
+ occurenceString = I18N_NOOP("Once");
+ else if(occurence == MyMoneySchedule::OCCUR_DAILY)
+ occurenceString = I18N_NOOP("Daily");
+ else if(occurence == MyMoneySchedule::OCCUR_WEEKLY)
+ occurenceString = I18N_NOOP("Weekly");
+ else if(occurence == MyMoneySchedule::OCCUR_FORTNIGHTLY)
+ occurenceString = I18N_NOOP("Fortnightly");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYOTHERWEEK)
+ occurenceString = I18N_NOOP("Every other week");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
+ occurenceString = I18N_NOOP("Every half month");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS)
+ occurenceString = I18N_NOOP("Every three weeks");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYFOURWEEKS)
+ occurenceString = I18N_NOOP("Every four weeks");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS)
+ occurenceString = I18N_NOOP("Every thirty days");
+ else if(occurence == MyMoneySchedule::OCCUR_MONTHLY)
+ occurenceString = I18N_NOOP("Monthly");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS)
+ occurenceString = I18N_NOOP("Every eight weeks");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYOTHERMONTH)
+ occurenceString = I18N_NOOP("Every two months");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS)
+ occurenceString = I18N_NOOP("Every three months");
+ else if(occurence == MyMoneySchedule::OCCUR_QUARTERLY)
+ occurenceString = I18N_NOOP("Quarterly");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYFOURMONTHS)
+ occurenceString = I18N_NOOP("Every four months");
+ else if(occurence == MyMoneySchedule::OCCUR_TWICEYEARLY)
+ occurenceString = I18N_NOOP("Twice yearly");
+ else if(occurence == MyMoneySchedule::OCCUR_YEARLY)
+ occurenceString = I18N_NOOP("Yearly");
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYOTHERYEAR)
+ occurenceString = I18N_NOOP("Every other year");
+ return occurenceString;
+}
+
+QString MyMoneySchedule::occurenceToString(int mult, occurenceE type)
+{
+ QString occurenceString = I18N_NOOP("Any");
+
+ if (type == MyMoneySchedule::OCCUR_ONCE)
+ switch (mult)
+ {
+ case 1: occurenceString = I18N_NOOP("Once"); break;
+ default: occurenceString = I18N_NOOP(static_cast<QString>("%1 times").arg(mult));
+ }
+ else if(type == MyMoneySchedule::OCCUR_DAILY)
+ switch (mult)
+ {
+ case 1: occurenceString = I18N_NOOP("Daily"); break;
+ case 30: occurenceString = I18N_NOOP("Every thirty days"); break;
+ default: occurenceString = I18N_NOOP(static_cast<QString>("Every %1 days").arg(mult));
+ }
+ else if(type == MyMoneySchedule::OCCUR_WEEKLY)
+ switch (mult)
+ {
+ case 1: occurenceString = I18N_NOOP("Weekly"); break;
+ case 2: occurenceString = I18N_NOOP("Every other week"); break;
+ case 3: occurenceString = I18N_NOOP("Every three weeks"); break;
+ case 4: occurenceString = I18N_NOOP("Every four weeks"); break;
+ case 8: occurenceString = I18N_NOOP("Every eight weeks"); break;
+ default: occurenceString = I18N_NOOP(static_cast<QString>("Every %1 weeks").arg(mult));
+ }
+ else if(type == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
+ switch (mult)
+ {
+ case 1: occurenceString = I18N_NOOP("Every half month"); break;
+ default: occurenceString = I18N_NOOP(static_cast<QString>("Every %1 half months").arg(mult));
+ }
+ else if(type == MyMoneySchedule::OCCUR_MONTHLY)
+ switch (mult)
+ {
+ case 1: occurenceString = I18N_NOOP("Monthly"); break;
+ case 2: occurenceString = I18N_NOOP("Every two months"); break;
+ case 3: occurenceString = I18N_NOOP("Every three months"); break;
+ case 4: occurenceString = I18N_NOOP("Every four months"); break;
+ case 6: occurenceString = I18N_NOOP("Twice yearly"); break;
+ default: occurenceString = I18N_NOOP(static_cast<QString>("Every %1 months").arg(mult));
+ }
+ else if(type == MyMoneySchedule::OCCUR_YEARLY)
+ switch (mult)
+ {
+ case 1: occurenceString = I18N_NOOP("Yearly"); break;
+ case 2: occurenceString = I18N_NOOP("Every other year"); break;
+ default: occurenceString = I18N_NOOP(static_cast<QString>("Every %1 years").arg(mult));
+ }
+ return occurenceString;
+}
+
+QString MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::occurenceE type)
+{
+ QString occurenceString = I18N_NOOP("Any");
+
+ if(type == MyMoneySchedule::OCCUR_ONCE)
+ occurenceString = I18N_NOOP("Once");
+ else if(type == MyMoneySchedule::OCCUR_DAILY)
+ occurenceString = I18N_NOOP("Day");
+ else if(type == MyMoneySchedule::OCCUR_WEEKLY)
+ occurenceString = I18N_NOOP("Week");
+ else if(type == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
+ occurenceString = I18N_NOOP("Half-month");
+ else if(type == MyMoneySchedule::OCCUR_MONTHLY)
+ occurenceString = I18N_NOOP("Month");
+ else if(type == MyMoneySchedule::OCCUR_YEARLY)
+ occurenceString = I18N_NOOP("Year");
+ return occurenceString;
+}
+
+QString MyMoneySchedule::scheduleTypeToString(MyMoneySchedule::typeE type)
+{
+ QString text;
+
+ switch (type) {
+ case MyMoneySchedule::TYPE_BILL:
+ text = I18N_NOOP("Bill");
+ break;
+ case MyMoneySchedule::TYPE_DEPOSIT:
+ text = I18N_NOOP("Deposit");
+ break;
+ case MyMoneySchedule::TYPE_TRANSFER:
+ text = I18N_NOOP("Transfer");
+ break;
+ case MyMoneySchedule::TYPE_LOANPAYMENT:
+ text = I18N_NOOP("Loan payment");
+ break;
+ case MyMoneySchedule::TYPE_ANY:
+ default:
+ text = I18N_NOOP("Unknown");
+ }
+ return text;
+}
+
+
+QString MyMoneySchedule::paymentMethodToString(MyMoneySchedule::paymentTypeE paymentType)
+{
+ QString text;
+
+ switch (paymentType) {
+ case MyMoneySchedule::STYPE_DIRECTDEBIT:
+ text = I18N_NOOP("Direct debit");
+ break;
+ case MyMoneySchedule::STYPE_DIRECTDEPOSIT:
+ text = I18N_NOOP("Direct deposit");
+ break;
+ case MyMoneySchedule::STYPE_MANUALDEPOSIT:
+ text = I18N_NOOP("Manual deposit");
+ break;
+ case MyMoneySchedule::STYPE_OTHER:
+ text = I18N_NOOP("Other");
+ break;
+ case MyMoneySchedule::STYPE_WRITECHEQUE:
+ text = I18N_NOOP("Write check");
+ break;
+ case MyMoneySchedule::STYPE_STANDINGORDER:
+ text = I18N_NOOP("Standing order");
+ break;
+ case MyMoneySchedule::STYPE_BANKTRANSFER:
+ text = I18N_NOOP("Bank transfer");
+ break;
+ case MyMoneySchedule::STYPE_ANY:
+ text = I18N_NOOP("Any (Error)");
+ break;
+ }
+ return text;
+}
+
+QString MyMoneySchedule::weekendOptionToString(MyMoneySchedule::weekendOptionE weekendOption)
+{
+ QString text;
+
+ switch (weekendOption) {
+ case MyMoneySchedule::MoveFriday:
+ text = I18N_NOOP("Change the date to the previous Friday");
+ break;
+ case MyMoneySchedule::MoveMonday:
+ text = I18N_NOOP("Change the date to the next Monday");
+ break;
+ case MyMoneySchedule::MoveNothing:
+ text = I18N_NOOP("Do Nothing");
+ break;
+ }
+ return text;
+}
+
+// until we don't have the means to store the value
+// of the variation, we default to 10% in case this
+// scheduled transaction is marked 'not fixed'.
+//
+// ipwizard 2009-04-18
+
+int MyMoneySchedule::variation(void) const
+{
+ int rc = 0;
+ if(!isFixed()) {
+ rc = 10;
+#if 0
+ QString var = value("kmm-variation");
+ if(!var.isEmpty())
+ rc = var.toInt();
+#endif
+ }
+ return rc;
+}
+
+void MyMoneySchedule::setVariation(int var)
+{
+#if 0
+ deletePair("kmm-variation");
+ if(var != 0)
+ setValue("kmm-variation", QString("%1").arg(var));
+#endif
+}
+
+int MyMoneySchedule::eventsPerYear(MyMoneySchedule::occurenceE occurence)
+{
+ int rc = 0;
+
+ switch(occurence) {
+ case MyMoneySchedule::OCCUR_DAILY:
+ rc = 365;
+ break;
+ case MyMoneySchedule::OCCUR_WEEKLY:
+ rc = 52;
+ break;
+ case MyMoneySchedule::OCCUR_FORTNIGHTLY:
+ rc = 26;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYOTHERWEEK:
+ rc = 26;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYHALFMONTH:
+ rc = 24;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYTHREEWEEKS:
+ rc = 17;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYFOURWEEKS:
+ rc = 13;
+ break;
+ case MyMoneySchedule::OCCUR_MONTHLY:
+ case MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS:
+ rc = 12;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS:
+ rc = 6;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYOTHERMONTH:
+ rc = 6;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYTHREEMONTHS:
+ case MyMoneySchedule::OCCUR_QUARTERLY:
+ rc = 4;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYFOURMONTHS:
+ rc = 3;
+ break;
+ case MyMoneySchedule::OCCUR_TWICEYEARLY:
+ rc = 2;
+ break;
+ case MyMoneySchedule::OCCUR_YEARLY:
+ rc = 1;
+ break;
+ default:
+ qWarning("Occurence not supported by financial calculator");
+ }
+
+ return rc;
+}
+
+int MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::occurenceE occurence)
+{
+ int rc = 0;
+
+ switch(occurence) {
+ case MyMoneySchedule::OCCUR_DAILY:
+ rc = 1;
+ break;
+ case MyMoneySchedule::OCCUR_WEEKLY:
+ rc = 7;
+ break;
+ case MyMoneySchedule::OCCUR_FORTNIGHTLY:
+ rc = 14;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYOTHERWEEK:
+ rc = 14;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYHALFMONTH:
+ rc = 15;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYTHREEWEEKS:
+ rc = 21;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYFOURWEEKS:
+ rc = 28;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS:
+ rc = 30;
+ break;
+ case MyMoneySchedule::OCCUR_MONTHLY:
+ rc = 30;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS:
+ rc = 56;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYOTHERMONTH:
+ rc = 60;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYTHREEMONTHS:
+ case MyMoneySchedule::OCCUR_QUARTERLY:
+ rc = 90;
+ break;
+ case MyMoneySchedule::OCCUR_EVERYFOURMONTHS:
+ rc = 120;
+ break;
+ case MyMoneySchedule::OCCUR_TWICEYEARLY:
+ rc = 180;
+ break;
+ case MyMoneySchedule::OCCUR_YEARLY:
+ rc = 360;
+ break;
+ default:
+ qWarning("Occurence not supported by financial calculator");
+ }
+
+ return rc;
+}
+
+QDate MyMoneySchedule::addHalfMonths( QDate date, int mult ) const
+{
+ QDate newdate = date;
+ int d, dm;
+ if ( mult > 0 )
+ {
+ d = newdate.day();
+ if ( d <= 12 )
+ {
+ if ( mult % 2 == 0 )
+ newdate = newdate.addMonths(mult>>1);
+ else
+ newdate = newdate.addMonths(mult>>1).addDays(15);
+ }
+ else
+ for ( int i = 0; i < mult; i++ )
+ {
+ if ( d <= 13 )
+ newdate = newdate.addDays(15);
+ else
+ {
+ dm = newdate.daysInMonth();
+ if ( d == 14 )
+ newdate = newdate.addDays(( dm < 30 ) ? dm - d : 15);
+ else if ( d == 15 )
+ newdate = newdate.addDays(dm - d);
+ else if ( d == dm )
+ newdate = newdate.addDays(15 - d).addMonths(1);
+ else
+ newdate = newdate.addDays(-15).addMonths(1);
+ }
+ d = newdate.day();
+ }
+ }
+ else if ( mult < 0 ) // Go backwards
+ for ( int i = 0; i > mult; i-- )
+ {
+ d = newdate.day();
+ dm = newdate.daysInMonth();
+ if ( d > 15 )
+ {
+ dm = newdate.daysInMonth();
+ newdate = newdate.addDays( (d == dm) ? 15 - dm : -15);
+ }
+ else if ( d <= 13 )
+ newdate = newdate.addMonths(-1).addDays(15);
+ else if ( d == 15 )
+ newdate = newdate.addDays(-15);
+ else // 14
+ {
+ newdate = newdate.addMonths(-1);
+ dm = newdate.daysInMonth();
+ newdate = newdate.addDays(( dm < 30 ) ? dm - d : 15 );
+ }
+ }
+ return newdate;
+}
+
+MyMoneySchedule::occurenceE MyMoneySchedule::stringToOccurence(const QString& text)
+{
+ MyMoneySchedule::occurenceE occurence = MyMoneySchedule::OCCUR_ANY;
+ QString tmp = text.lower();
+
+ if(tmp == i18n("Once").lower())
+ occurence = MyMoneySchedule::OCCUR_ONCE;
+ else if(tmp == i18n("Daily").lower())
+ occurence = MyMoneySchedule::OCCUR_DAILY;
+ else if(tmp == i18n("Weekly").lower())
+ occurence = MyMoneySchedule::OCCUR_WEEKLY;
+ else if(tmp == i18n("Fortnightly").lower())
+ occurence = MyMoneySchedule::OCCUR_FORTNIGHTLY;
+ else if(tmp == i18n("Every other week").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYOTHERWEEK;
+ else if(tmp == i18n("Every half month").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYHALFMONTH;
+ else if(tmp == i18n("Every three weeks").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYTHREEWEEKS;
+ else if(tmp == i18n("Every four weeks").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYFOURWEEKS;
+ else if(tmp == i18n("Every thirty days").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS;
+ else if(tmp == i18n("Monthly").lower())
+ occurence = MyMoneySchedule::OCCUR_MONTHLY;
+ else if(tmp == i18n("Every eight weeks").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS;
+ else if(tmp == i18n("Every two months").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYOTHERMONTH;
+ else if(tmp == i18n("Every three months").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYTHREEMONTHS;
+ else if(tmp == i18n("Quarterly").lower())
+ occurence = MyMoneySchedule::OCCUR_QUARTERLY;
+ else if(tmp == i18n("Every four months").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYFOURMONTHS;
+ else if(tmp == i18n("Twice yearly").lower())
+ occurence = MyMoneySchedule::OCCUR_TWICEYEARLY;
+ else if(tmp == i18n("Yearly").lower())
+ occurence = MyMoneySchedule::OCCUR_YEARLY;
+ else if(tmp == i18n("Every other year").lower())
+ occurence = MyMoneySchedule::OCCUR_EVERYOTHERYEAR;
+
+ return occurence;
+}
+
+/**
+ * Helper method to convert simple occurence to compound occurence + multiplier
+ *
+ * @param multiplier Returned by reference. Adjusted multiplier
+ * @param occurence Returned by reference. Occurence type
+ */
+void MyMoneySchedule::simpleToCompoundOccurence(int& multiplier,occurenceE& occurence)
+{
+ occurenceE newOcc = occurence;
+ int newMulti = 1;
+ if (occurence == MyMoneySchedule::OCCUR_ONCE ||
+ occurence == MyMoneySchedule::OCCUR_DAILY ||
+ occurence == MyMoneySchedule::OCCUR_WEEKLY ||
+ occurence == MyMoneySchedule::OCCUR_EVERYHALFMONTH ||
+ occurence == MyMoneySchedule::OCCUR_MONTHLY ||
+ occurence == MyMoneySchedule::OCCUR_YEARLY )
+ { // Already a base occurence and multiplier
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_FORTNIGHTLY ||
+ occurence == MyMoneySchedule::OCCUR_EVERYOTHERWEEK)
+ {
+ newOcc = MyMoneySchedule::OCCUR_WEEKLY;
+ newMulti = 2;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS)
+ {
+ newOcc = MyMoneySchedule::OCCUR_WEEKLY;
+ newMulti = 3;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYFOURWEEKS)
+ {
+ newOcc = MyMoneySchedule::OCCUR_WEEKLY;
+ newMulti = 4;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS)
+ {
+ newOcc = MyMoneySchedule::OCCUR_DAILY;
+ newMulti = 30;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS)
+ {
+ newOcc = MyMoneySchedule::OCCUR_WEEKLY;
+ newMulti = 8;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYOTHERMONTH)
+ {
+ newOcc = MyMoneySchedule::OCCUR_MONTHLY;
+ newMulti = 2;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS ||
+ occurence == MyMoneySchedule::OCCUR_QUARTERLY )
+ {
+ newOcc = MyMoneySchedule::OCCUR_MONTHLY;
+ newMulti = 3;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYFOURMONTHS)
+ {
+ newOcc = MyMoneySchedule::OCCUR_MONTHLY;
+ newMulti = 4;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_TWICEYEARLY)
+ {
+ newOcc = MyMoneySchedule::OCCUR_MONTHLY;
+ newMulti = 6;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYOTHERYEAR)
+ {
+ newOcc = MyMoneySchedule::OCCUR_YEARLY;
+ newMulti = 2;
+ }
+ else // Unknown
+ {
+ newOcc = MyMoneySchedule::OCCUR_ANY;
+ newMulti = 1;
+ }
+ if (newOcc != occurence)
+ {
+ occurence = newOcc;
+ multiplier = newMulti == 1 ? multiplier : newMulti * multiplier;
+ }
+}
+
+/**
+ * Helper method to convert compound occurence + multiplier to simple occurence
+ *
+ * @param multiplier Returned by reference. Adjusted multiplier
+ * @param occurence Returned by reference. Occurence type
+ */
+void MyMoneySchedule::compoundToSimpleOccurence(int& multiplier,occurenceE& occurence)
+{
+ occurenceE newOcc = occurence;
+ if(occurence == MyMoneySchedule::OCCUR_ONCE)
+ { // Nothing to do
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_DAILY)
+ {
+ switch (multiplier)
+ {
+ case 1: break;
+ case 30: newOcc = MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS; break;
+ }
+ }
+ else if(newOcc == MyMoneySchedule::OCCUR_WEEKLY)
+ {
+ switch (multiplier)
+ {
+ case 1: break;
+ case 2: newOcc = MyMoneySchedule::OCCUR_EVERYOTHERWEEK; break;
+ case 3: newOcc = MyMoneySchedule::OCCUR_EVERYTHREEWEEKS; break;
+ case 4: newOcc = MyMoneySchedule::OCCUR_EVERYFOURWEEKS; break;
+ case 8: newOcc = MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS; break;
+ }
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_MONTHLY)
+ switch (multiplier)
+ {
+ case 1: break;
+ case 2: newOcc = MyMoneySchedule::OCCUR_EVERYOTHERMONTH; break;
+ case 3: newOcc = MyMoneySchedule::OCCUR_EVERYTHREEMONTHS; break;
+ case 4: newOcc = MyMoneySchedule::OCCUR_EVERYFOURMONTHS; break;
+ case 6: newOcc = MyMoneySchedule::OCCUR_TWICEYEARLY; break;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
+ switch (multiplier)
+ {
+ case 1: break;
+ }
+ else if(occurence == MyMoneySchedule::OCCUR_YEARLY)
+ {
+ switch (multiplier)
+ {
+ case 1: break;
+ case 2: newOcc = MyMoneySchedule::OCCUR_EVERYOTHERYEAR; break;
+ }
+ }
+ if (occurence != newOcc ) // Changed to derived type
+ {
+ occurence = newOcc;
+ multiplier = 1;
+ }
+}
diff --git a/kmymoney2/mymoney/mymoneyscheduled.h b/kmymoney2/mymoney/mymoneyscheduled.h
new file mode 100644
index 0000000..46303b2
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyscheduled.h
@@ -0,0 +1,695 @@
+/***************************************************************************
+ mymoneyscheduled.h
+ -------------------
+ copyright : (C) 2000-2002 by Michael Edwardes
+ (C) 2007 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSCHEDULED_H
+#define MYMONEYSCHEDULED_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qdatetime.h>
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneytransaction.h"
+#include "mymoneyaccount.h"
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneyobject.h>
+
+class MyMoneyStorageANON;
+
+/**
+ * @author Michael Edwardes
+ */
+
+/**
+ * This class represents a schedule. (A series of bills, deposits or
+ * transfers).
+ *
+ * @short A class to represent a schedule.
+ * @see MyMoneyScheduled
+ */
+class KMYMONEY_EXPORT MyMoneySchedule : public MyMoneyObject
+{
+ friend class MyMoneyStorageANON;
+public:
+ /**
+ * This enum is used to describe all the possible schedule frequencies.
+ * The special entry, OCCUR_ANY, is used to combine all the other types.
+ */
+ enum occurenceE { OCCUR_ANY=0, OCCUR_ONCE=1, OCCUR_DAILY=2, OCCUR_WEEKLY=4, OCCUR_FORTNIGHTLY=8,
+ OCCUR_EVERYOTHERWEEK=16,
+ OCCUR_EVERYHALFMONTH=18,
+ OCCUR_EVERYTHREEWEEKS=20,
+ OCCUR_EVERYTHIRTYDAYS=30,
+ OCCUR_MONTHLY=32, OCCUR_EVERYFOURWEEKS=64,
+ OCCUR_EVERYEIGHTWEEKS=126,
+ OCCUR_EVERYOTHERMONTH=128, OCCUR_EVERYTHREEMONTHS=256,
+ OCCUR_TWICEYEARLY=1024, OCCUR_EVERYOTHERYEAR=2048, OCCUR_QUARTERLY=4096,
+ OCCUR_EVERYFOURMONTHS=8192, OCCUR_YEARLY=16384
+ };
+
+ /**
+ * This enum is used to describe the schedule type.
+ */
+ enum typeE { TYPE_ANY=0, TYPE_BILL=1, TYPE_DEPOSIT=2, TYPE_TRANSFER=4, TYPE_LOANPAYMENT=5 };
+
+ /**
+ * This enum is used to describe the schedule's payment type.
+ */
+ enum paymentTypeE { STYPE_ANY=0, STYPE_DIRECTDEBIT=1, STYPE_DIRECTDEPOSIT=2,
+ STYPE_MANUALDEPOSIT=4, STYPE_OTHER=8,
+ STYPE_WRITECHEQUE=16,
+ STYPE_STANDINGORDER=32,
+ STYPE_BANKTRANSFER=64 };
+
+ /**
+ * This enum is used by the auto-commit functionality.
+ *
+ * Depending upon the value of m_weekendOption the schedule can
+ * be entered on a different date
+ **/
+ enum weekendOptionE { MoveFriday=0, MoveMonday=1, MoveNothing=2 };
+
+ /**
+ * Standard constructor
+ */
+ MyMoneySchedule();
+
+ /**
+ * Constructor for initialising the object.
+ *
+ * Please note that the optional fields are not set and the transaction
+ * MUST be set before it can be used.
+ *
+ * @a startDate is not used anymore and internally set to QDate()
+ */
+ MyMoneySchedule(const QString& name, typeE type, occurenceE occurence, int occurenceMultiplier,
+ paymentTypeE paymentType, const QDate& startDate, const QDate& endDate, bool fixed, bool autoEnter);
+
+ MyMoneySchedule(const QDomElement& node);
+
+ MyMoneySchedule(const QString& id, const MyMoneySchedule& right);
+
+ /**
+ * Standard destructor
+ */
+ ~MyMoneySchedule() {}
+
+ /**
+ * Simple get method that returns the occurence frequency.
+ *
+ * @return occurenceE The instance frequency.
+ */
+ occurenceE occurence(void) const;
+
+ /**
+ * Simple get method that returns the occurence period
+ * multiplier and occurence
+ *
+ * @return occurenceE The instance period
+ *
+ */
+ occurenceE occurencePeriod(void) const { return m_occurence; }
+
+ /**
+ * Simple get method that returns the occurence period multiplier.
+ *
+ * @return int The frequency multiplier
+ */
+ int occurenceMultiplier(void) const { return m_occurenceMultiplier; }
+
+ /**
+ * Simple get method that returns the schedule type.
+ *
+ * @return typeE The instance type.
+ */
+ typeE type(void) const { return m_type; }
+
+ /**
+ * Simple get method that returns the schedule startDate. If
+ * the schedule has been executed once, the date of the first
+ * execution is returned. Otherwise, the next due date is
+ * returned.
+ *
+ * @return reference to QDate containing the start date.
+ */
+ const QDate& startDate(void) const;
+
+ /**
+ * Simple get method that returns the schedule paymentType.
+ *
+ * @return paymentTypeE The instance paymentType.
+ */
+ paymentTypeE paymentType(void) const { return m_paymentType; }
+
+ /**
+ * Simple get method that returns true if the schedule is fixed.
+ *
+ * @return bool To indicate whether the instance is fixed.
+ */
+ bool isFixed(void) const { return m_fixed; }
+
+ /**
+ * Simple get method that returns true if the schedule will end
+ * at some time.
+ *
+ * @return bool Indicates whether the instance will end.
+ */
+ bool willEnd(void) const { return m_endDate.isValid(); }
+
+ /**
+ * Simple get method that returns the number of transactions remaining.
+ *
+ * @return int The number of transactions remaining for the instance.
+ */
+ int transactionsRemaining(void) const;
+
+ /**
+ * Simple get method that returns the schedule end date.
+ *
+ * @return QDate The end date for the instance.
+ */
+ const QDate& endDate(void) const { return m_endDate; }
+
+ /**
+ * Simple get method that returns true if the transaction should be
+ * automatically entered into the register.
+ *
+ * @return bool Indicates whether the instance will be automatically entered.
+ */
+ bool autoEnter(void) const { return m_autoEnter; }
+
+ /**
+ * Simple get method that returns the transaction data for the schedule.
+ *
+ * @return MyMoneyTransaction The transaction data for the instance.
+ */
+ const MyMoneyTransaction& transaction(void) const { return m_transaction; }
+
+ /**
+ * Simple method that returns the schedules last payment. If the
+ * schedule has never been executed, QDate() will be returned.
+ *
+ * @return QDate The last payment for the schedule.
+ */
+ const QDate& lastPayment(void) const { return m_lastPayment; }
+
+ /**
+ * Simple method that returns the next due date for the schedule.
+ *
+ * @return reference to QDate containing the next due date.
+ *
+ * @note The date returned can represent a value that is past
+ * a possible end of the schedule. Make sure to consider
+ * the return value of isFinished() when using the value returned.
+ */
+ const QDate& nextDueDate(void) const;
+
+ /**
+ * This method adjusts returns the next due date adjusted
+ * according to the rules specified by the schedule's weekend option.
+ *
+ * @return QDate containing the adjusted next due date. If the
+ * schedule is finished (@sa isFinished()) then the method
+ * returns an invalid QDate.
+ *
+ * @sa weekendOption()
+ * @sa adjustedDate()
+ */
+ QDate adjustedNextDueDate(void) const;
+
+ /**
+ * This method adjusts returns the date adjusted according to the
+ * rules specified by the schedule's weekend option.
+ *
+ * @return QDate containing the adjusted date.
+ */
+ QDate adjustedDate(QDate date, weekendOptionE option) const;
+
+ /**
+ * Get the weekendOption that determines how the schedule check code
+ * will enter transactions that occur on a weekend.
+ *
+ * This not used by MyMoneySchedule but by the support code.
+ **/
+ weekendOptionE weekendOption(void) const { return m_weekendOption; }
+
+ /**
+ * Simple method that sets the frequency for the schedule.
+ *
+ * @param occ The new occurence (frequency).
+ * @return none
+ */
+ void setOccurence(occurenceE occ);
+
+ /**
+ * Simple method that sets the schedule period
+ *
+ * @param occ The new occurence period (frequency)
+ * @return none
+ */
+ void setOccurencePeriod(occurenceE occ);
+
+ /**
+ * Simple method that sets the frequency multiplier for the schedule.
+ *
+ * @param occmultiplier The new occurence (frequency) multiplier.
+ * @return none
+ */
+ void setOccurenceMultiplier(int occmultiplier);
+
+ /**
+ * Simple method that sets the type for the schedule.
+ *
+ * @param type The new type.
+ * @return none
+ */
+ void setType(typeE type);
+
+ /**
+ * Simple method that sets the start date for the schedule.
+ *
+ * @param date The new start date.
+ * @return none
+ */
+ void setStartDate(const QDate& date);
+
+ /**
+ * Simple method that sets the payment type for the schedule.
+ *
+ * @param type The new payment type.
+ * @return none
+ */
+ void setPaymentType(paymentTypeE type);
+
+ /**
+ * Simple method to set whether the schedule is fixed or not.
+ *
+ * @param fixed boolean to indicate whether the instance is fixed.
+ * @return none
+ */
+ void setFixed(bool fixed);
+
+ /**
+ * Simple method that sets the transaction for the schedule.
+ * The transaction must have a valid postDate set, otherwise
+ * it will not be accepted.
+ *
+ * @param transaction The new transaction.
+ * @return none
+ */
+ void setTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * Simple set method to set the end date for the schedule.
+ *
+ * @param date The new end date.
+ * @return none
+ */
+ void setEndDate(const QDate& date);
+
+ /**
+ * Simple set method to set whether this transaction should be automatically
+ * entered into the journal whenever it is due.
+ *
+ * @param autoenter boolean to indicate whether we need to automatically
+ * enter the transaction.
+ * @return none
+ */
+ void setAutoEnter(bool autoenter);
+
+ /**
+ * Simple set method to set the schedule's next payment date.
+ *
+ * @param date The next payment date.
+ * @return none
+ */
+ void setNextDueDate(const QDate& date);
+
+ /**
+ * Simple set method to set the schedule's last payment. If
+ * this method is called for the first time on the object,
+ * the @a m_startDate member will be set to @a date as well.
+ *
+ * This method should be called whenever a schedule is entered or skipped.
+ *
+ * @param date The last payment date.
+ * @return none
+ */
+ void setLastPayment(const QDate& date);
+
+ /**
+ * Set the weekendOption that determines how the schedule check code
+ * will enter transactions that occur on a weekend. The following values
+ * are valid:
+ *
+ * - MoveNothing: don't modify date
+ * - MoveFriday: modify the date to the previous friday
+ * - MoveMonday: modify the date to the following monday
+ *
+ * If an invalid option is given, the option is set to MoveNothing.
+ *
+ * @param option See list in description
+ * @return none
+ *
+ * @note This not used by MyMoneySchedule but by the support code.
+ **/
+ void setWeekendOption(const weekendOptionE option);
+
+ /**
+ * Validates the schedule instance.
+ *
+ * Makes sure the paymentType matches the type and that the required
+ * fields have been set.
+ *
+ * @param id_check if @p true, the method will check for an empty id.
+ * if @p false, this check is skipped. Default is @p true.
+ *
+ * @return If this method returns, all checks are passed. Otherwise,
+ * it will throw a MyMoneyException object.
+ *
+ * @exception MyMoneyException with detailed error information is thrown
+ * in case of failure of any check.
+ */
+ void validate(bool id_check=true) const;
+
+ /**
+ * Calculates the date of the next payment adjusted according to the
+ * rules specified by the schedule's weekend option.
+ *
+ * @param refDate The reference date from which the next payment
+ * date will be calculated (defaults to current date)
+ *
+ * @return QDate The adjusted date the next payment is due. This date is
+ * always past @a refDate. In case of an error or if there
+ * are no more payments then an empty/invalid QDate() will
+ * be returned.
+ */
+ QDate adjustedNextPayment(const QDate& refDate = QDate::currentDate()) const;
+
+ /**
+ * Calculates the date of the next payment.
+ *
+ * @param refDate The reference date from which the next payment
+ * date will be calculated (defaults to current date)
+ *
+ * @return QDate The date the next payment is due. This date is
+ * always past @a refDate. In case of an error or
+ * if there is no more payments then an empty/invalid QDate()
+ * will be returned.
+ */
+ QDate nextPayment(const QDate& refDate = QDate::currentDate()) const;
+
+ /**
+ * Calculates the dates of the payment over a certain period of time.
+ *
+ * An empty list is returned for no payments or error.
+ *
+ * @param startDate The start date for the range calculations
+ * @param endDate The end date for the range calculations.
+ * @return QValueList<QDate> The dates on which the payments are due.
+ */
+ QValueList<QDate> paymentDates(const QDate& startDate, const QDate& endDate) const;
+
+ /**
+ * Returns the instances name
+ *
+ * @return The name
+ */
+ const QString& name(void) const { return m_name; }
+
+ /**
+ * Changes the instance name
+ *
+ * @param nm The new name
+ * @return none
+ */
+ void setName(const QString& nm);
+
+ bool operator ==(const MyMoneySchedule& right) const;
+ bool operator !=(const MyMoneySchedule& right) const { return ! operator==(right); }
+
+ bool operator <(const MyMoneySchedule& right) const;
+
+ MyMoneyAccount account(int cnt = 1) const;
+ MyMoneyAccount transferAccount(void) const { return account(2); };
+ QDate dateAfter(int transactions) const;
+
+ bool isOverdue() const;
+ bool isFinished() const;
+ bool hasRecordedPayment(const QDate&) const;
+ void recordPayment(const QDate&);
+ QValueList<QDate> recordedPayments(void) const { return m_recordedPayments; }
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ /**
+ * Returns the human-readable format of Schedule's occurence
+ *
+ * @return QString representing the human readable format
+ */
+ QString occurenceToString() const;
+
+ /**
+ * This method is used to convert the occurence type from it's
+ * internal representation into a human readable format.
+ *
+ * @param type numerical representation of the MyMoneySchedule
+ * occurence type
+ *
+ * @return QString representing the human readable format
+ */
+ static QString occurenceToString(occurenceE type);
+
+ /**
+ * This method is used to convert a multiplier and base occurence type
+ * from it's internal representation into a human readable format.
+ * When multiplier * occurence is equivalent to a simple occurence
+ * the method returns the same as occurenceToString of the simple occurence
+ *
+ * @param mult occurence multiplier
+ * @param type occurence period
+ *
+ * @return QString representing the human readable format
+ */
+ static QString occurenceToString(int mult, occurenceE type);
+
+ /**
+ * This method is used to convert an occurence period from
+ * it's internal representation into a human-readable format.
+ *
+ * @param type numerical representation of the MyMoneySchedule
+ * occurence type
+ *
+ * @return QString representing the human readable format
+ */
+ static QString occurencePeriodToString(occurenceE type);
+
+ /**
+ * This method is used to convert the payment type from it's
+ * internal representation into a human readable format.
+ *
+ * @param paymentType numerical representation of the MyMoneySchedule
+ * payment type
+ *
+ * @return QString representing the human readable format
+ */
+ static QString paymentMethodToString(MyMoneySchedule::paymentTypeE paymentType);
+
+ /**
+ * This method is used to convert the schedule weekend option from it's
+ * internal representation into a human readable format.
+ *
+ * @param weekendOption numerical representation of the MyMoneySchedule
+ * weekend option
+ *
+ * @return QString representing the human readable format
+ */
+ static QString weekendOptionToString(MyMoneySchedule::weekendOptionE weekendOption);
+
+ /**
+ * This method is used to convert the schedule type from it's
+ * internal representation into a human readable format.
+ *
+ * @param type numerical representation of the MyMoneySchedule
+ * schedule type
+ *
+ * @return QString representing the human readable format
+ */
+ static QString scheduleTypeToString(MyMoneySchedule::typeE type);
+
+ int variation(void) const;
+ void setVariation(int var);
+
+ /**
+ *
+ * Convert an occurence to the maximum number of events possible during a single
+ * calendar year.
+ * A fortnight is treated as 15 days.
+ *
+ * @param occurence The occurence
+ *
+ * @return int Number of days between events
+ */
+ static int eventsPerYear(MyMoneySchedule::occurenceE occurence);
+
+ /**
+ *
+ * Convert an occurence to the number of days between events
+ * Treats a month as 30 days.
+ * Treats a fortnight as 15 days.
+ *
+ * @param occurence The occurence
+ *
+ * @return int Number of days between events
+ */
+ static int daysBetweenEvents(MyMoneySchedule::occurenceE occurence);
+
+ /**
+ * Helper method to convert simple occurence to compound occurence + multiplier
+ *
+ * @param multiplier Returned by reference. Adjusted multiplier
+ * @param occurence Returned by reference. Occurence type
+ */
+ static void simpleToCompoundOccurence(int& multiplier,occurenceE& occurence);
+
+ /**
+ * Helper method to convert compound occurence + multiplier to simple occurence
+ *
+ * @param multiplier Returned by reference. Adjusted multiplier
+ * @param occurence Returned by reference. Occurence type
+ */
+ static void compoundToSimpleOccurence(int& multiplier,occurenceE& occurence);
+
+ /**
+ * This method is used to convert the occurence type from the
+ * human readable form into it's internal representation.
+ *
+ * @param text reference to QString representing the human readable format
+ * @return numerical representation of the occurence
+ */
+ static MyMoneySchedule::occurenceE stringToOccurence(const QString& text);
+
+private:
+ /**
+ * This method forces the day of the passed @p date to
+ * be the day of the start date of this schedule kept
+ * in m_startDate. It is internally used when calculating
+ * the payment dates over several periods.
+ *
+ * @param date reference to QDate object to be checked and adjusted
+ */
+ void fixDate(QDate& date) const;
+
+ /**
+ * Simple method that sets the transaction for the schedule.
+ * The transaction must have a valid postDate set, otherwise
+ * it will not be accepted. This test is bypassed, if @a noDateCheck
+ * is set to true
+ *
+ * @param transaction The new transaction.
+ * @param noDateCheck if @a true, the date check is bypassed
+ * @return none
+ */
+ void setTransaction(const MyMoneyTransaction& transaction, bool noDateCheck);
+
+ /**
+ * This method adds a number of Half Months to the given Date.
+ * This is used for OCCUR_EVERYHALFMONTH occurences.
+ * The addition uses the following rules to add a half month:
+ * Day 1-13: add 15 days
+ * Day 14: add 15 days (except February: the last day of the month)
+ * Day 15: last day of the month
+ * Day 16-29 (not last day in February): subtract 15 days and add 1 month
+ * 30 and last day: 15th of next month
+ *
+ * This calculation pairs days 1 to 12 with 16 to 27.
+ * Day 15 is paired with the last day of every month.
+ * Repeated addition has issues in the following cases:
+ * - Days 13 to 14 are paired with 28 to 29 until addition hits the last day of February
+ * after which the (15,last) pair will be used.
+ * - Addition from Day 30 leads immediately to the (15th,last) day pair.
+ *
+ * @param date The date
+ * @param mult The number of half months to add. Default is 1.
+ *
+ * @return QDate date with mult half months added
+ */
+ QDate addHalfMonths( QDate date, int mult = 1 ) const;
+
+private:
+ /// Its occurence
+ occurenceE m_occurence;
+
+ /// Its occurence multiplier
+ int m_occurenceMultiplier;
+
+ /// Its type
+ typeE m_type;
+
+ /// The date the schedule commences
+ QDate m_startDate;
+
+ /// The payment type
+ paymentTypeE m_paymentType;
+
+ /// Can the amount vary
+ bool m_fixed;
+
+ /// The, possibly estimated, amount plus all other relevant details
+ MyMoneyTransaction m_transaction;
+
+ /// The last transaction date if the schedule does end at a fixed date
+ QDate m_endDate;
+
+ /// Enter the transaction into the register automatically
+ bool m_autoEnter;
+
+ /// Internal date used for calculations
+ QDate m_lastPayment;
+
+ /// The name
+ QString m_name;
+
+ /// The recorded payments
+ QValueList<QDate> m_recordedPayments;
+
+ /// The weekend option
+ weekendOptionE m_weekendOption;
+};
+#endif
diff --git a/kmymoney2/mymoney/mymoneyscheduletest.cpp b/kmymoney2/mymoney/mymoneyscheduletest.cpp
new file mode 100644
index 0000000..0a4a380
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyscheduletest.cpp
@@ -0,0 +1,1909 @@
+/***************************************************************************
+ mymoneyscheduletest.cpp
+ -------------------
+ copyright : (C) 2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+// Include internationalization
+#include <klocale.h>
+
+#include "mymoneyscheduletest.h"
+
+#include "mymoneysplit.h"
+#include "mymoneymoney.h"
+
+#include <iostream>
+
+MyMoneyScheduleTest::MyMoneyScheduleTest()
+{
+}
+
+
+void MyMoneyScheduleTest::setUp () {
+}
+
+void MyMoneyScheduleTest::tearDown () {
+}
+
+void MyMoneyScheduleTest::testEmptyConstructor() {
+ MyMoneySchedule s;
+
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ CPPUNIT_ASSERT(s.m_occurence == MyMoneySchedule::OCCUR_ANY);
+ CPPUNIT_ASSERT(s.m_type == MyMoneySchedule::TYPE_ANY);
+ CPPUNIT_ASSERT(s.m_paymentType == MyMoneySchedule::STYPE_ANY);
+ CPPUNIT_ASSERT(s.m_fixed == false);
+ CPPUNIT_ASSERT(!s.m_startDate.isValid());
+ CPPUNIT_ASSERT(!s.m_endDate.isValid());
+ CPPUNIT_ASSERT(!s.m_lastPayment.isValid());
+ CPPUNIT_ASSERT(s.m_autoEnter == false);
+ CPPUNIT_ASSERT(s.m_name.isEmpty());
+ CPPUNIT_ASSERT(s.willEnd() == false);
+}
+
+void MyMoneyScheduleTest::testConstructor() {
+ MyMoneySchedule s( "A Name",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate(),
+ QDate(),
+ true,
+ true);
+
+ CPPUNIT_ASSERT(s.type() == MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1 );
+ CPPUNIT_ASSERT(s.paymentType() == MyMoneySchedule::STYPE_DIRECTDEBIT);
+ CPPUNIT_ASSERT(s.startDate() == QDate());
+ CPPUNIT_ASSERT(s.willEnd() == false);
+ CPPUNIT_ASSERT(s.isFixed() == true);
+ CPPUNIT_ASSERT(s.autoEnter() == true);
+ CPPUNIT_ASSERT(s.name() == "A Name");
+ CPPUNIT_ASSERT(!s.m_endDate.isValid());
+ CPPUNIT_ASSERT(!s.m_lastPayment.isValid());
+}
+
+void MyMoneyScheduleTest::testSetFunctions() {
+ MyMoneySchedule s;
+
+ s.setId("SCHED001");
+ CPPUNIT_ASSERT(s.id() == "SCHED001");
+
+ s.setType(MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(s.type() == MyMoneySchedule::TYPE_BILL);
+
+ s.setEndDate(QDate::currentDate());
+ CPPUNIT_ASSERT(s.endDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(s.willEnd() == true);
+}
+
+void MyMoneyScheduleTest::testCopyConstructor() {
+ MyMoneySchedule s;
+
+ s.setId("SCHED001");
+ s.setType(MyMoneySchedule::TYPE_BILL);
+
+ MyMoneySchedule s2(s);
+
+ CPPUNIT_ASSERT(s.id() == s2.id());
+ CPPUNIT_ASSERT(s.type() == s2.type());
+}
+
+void MyMoneyScheduleTest::testAssignmentConstructor() {
+ MyMoneySchedule s;
+
+ s.setId("SCHED001");
+ s.setType(MyMoneySchedule::TYPE_BILL);
+
+ MyMoneySchedule s2 = s;
+
+ CPPUNIT_ASSERT(s.id() == s2.id());
+ CPPUNIT_ASSERT(s.type() == s2.type());
+}
+
+void MyMoneyScheduleTest::testSingleton() {
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ CPPUNIT_ASSERT(m->m_instance != NULL);
+ CPPUNIT_ASSERT(m->m_nextId == 1);
+*/
+}
+
+void MyMoneyScheduleTest::testAddSchedule()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try {
+
+ MyMoneySplit sp1;
+ sp1.setShares(MyMoneyMoney(1));
+ sp1.setValue(MyMoneyMoney(1));
+ sp1.setAccountId("MTE1");
+ sp1.setMemo("MTE1");
+ sp1.setPayeeId("MTE1");
+
+ MyMoneySplit sp2;
+ sp2.setShares(MyMoneyMoney(1));
+ sp2.setValue(MyMoneyMoney(1));
+ sp2.setAccountId("MTE2");
+ sp2.setMemo("MTE2");
+ sp2.setPayeeId("MTE2");
+
+ MyMoneyTransaction t;
+ t.addSplit(sp1);
+ t.addSplit(sp2);
+
+ MyMoneySchedule s1( "s1",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate(2001, 1, 1),
+ false,
+ true,
+ true);
+ s1.setTransaction(t);
+ MyMoneySchedule s2( "s2",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_MONTHLY, 1,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ QDate(2001, 2, 1),
+ false,
+ true,
+ true);
+ s2.setTransaction(t);
+ MyMoneySchedule s3( "s3",
+ MyMoneySchedule::TYPE_TRANSFER,
+ MyMoneySchedule::OCCUR_YEARLY, 1,
+ MyMoneySchedule::STYPE_WRITECHEQUE,
+ QDate(2001, 3, 1),
+ false,
+ true,
+ true);
+ s3.setTransaction(t);
+
+
+ m->addSchedule("A000001", s1);
+ m->addSchedule("A000001", s2);
+ m->addSchedule("A000001", s3);
+ } catch(MyMoneyException *e) {
+ char buf[256];
+ sprintf(buf, "Unexpected exception: %s", e->what().latin1());
+ CPPUNIT_FAIL(buf);
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->m_nextId == 4);
+ CPPUNIT_ASSERT(m->m_accountsScheduled["A000001"].size() == 3);
+*/
+}
+
+void MyMoneyScheduleTest::testAnyScheduled()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ // Successes
+ CPPUNIT_ASSERT(m->anyScheduled("A000001"));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_BILL));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_DEPOSIT));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_TRANSFER));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_MONTHLY));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_WEEKLY));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_YEARLY));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_DIRECTDEBIT));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT));
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_WRITECHEQUE));
+
+ // Failures
+ CPPUNIT_ASSERT(m->anyScheduled("A000001", MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_MONTHLY) == false);
+*/
+}
+
+void MyMoneyScheduleTest::testOverdue()
+{
+ MyMoneySchedule sch_overdue;
+ MyMoneySchedule sch_intime;
+
+ // the following checks only work correctly, if currentDate() is
+ // between the 1st and 27th. If it is between 28th and 31st
+ // we don't perform them. Note: this should be fixed.
+ if(QDate::currentDate().day() > 27 || QDate::currentDate().day() == 1) {
+ std::cout << std::endl << "testOverdue() skipped because current day is between 28th and 2nd" << std::endl;
+ return;
+ }
+
+ QDate startDate = QDate::currentDate().addDays(-1).addMonths(-23);
+ QDate lastPaymentDate = QDate::currentDate().addDays(-1).addMonths(-1);
+
+ QString ref = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"0\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"8\" endDate=\"\" type=\"5\" id=\"SCH0002\" name=\"A Name\" fixed=\"0\" occurenceMultiplier=\"1\" occurence=\"32\" >\n"
+ " <PAYMENTS>\n"
+ " <PAYMENT date=\"%3\" />\n"
+ " </PAYMENTS>\n"
+ " <TRANSACTION postdate=\"\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n");
+ QString ref_overdue = ref.arg(startDate.toString(Qt::ISODate))
+ .arg(lastPaymentDate.toString(Qt::ISODate))
+ .arg(lastPaymentDate.toString(Qt::ISODate));
+
+ QString ref_intime = ref.arg(startDate.addDays(1).toString(Qt::ISODate))
+ .arg(lastPaymentDate.addDays(1).toString(Qt::ISODate))
+ .arg(lastPaymentDate.addDays(1).toString(Qt::ISODate));
+
+ QDomDocument doc;
+ QDomElement node;
+
+ // std::cout << ref_intime << std::endl;
+ try {
+ doc.setContent(ref_overdue);
+ node = doc.documentElement().firstChild().toElement();
+ sch_overdue = MyMoneySchedule(node);
+ doc.setContent(ref_intime);
+ node = doc.documentElement().firstChild().toElement();
+ sch_intime = MyMoneySchedule(node);
+
+ CPPUNIT_ASSERT(sch_overdue.isOverdue() == true);
+ CPPUNIT_ASSERT(sch_intime.isOverdue() == false);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ CPPUNIT_ASSERT(m->anyOverdue("A000001"));
+ CPPUNIT_ASSERT(m->anyOverdue("A000001", MyMoneySchedule::TYPE_BILL));
+ CPPUNIT_ASSERT(m->anyOverdue("A000001", MyMoneySchedule::TYPE_TRANSFER));
+ CPPUNIT_ASSERT(m->anyOverdue("A000001", MyMoneySchedule::TYPE_DEPOSIT));
+ } catch(MyMoneyException *e) {
+ char buf[256];
+ sprintf(buf, "Unexpected exception: %s", e->what().latin1());
+ CPPUNIT_FAIL(buf);
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testGetSchedule()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ MyMoneySchedule s = m->getSchedule("A000001", "SCHED00002");
+
+ CPPUNIT_ASSERT(s.type() == MyMoneySchedule::TYPE_DEPOSIT);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.paymentType() == MyMoneySchedule::STYPE_MANUALDEPOSIT);
+ CPPUNIT_ASSERT(s.startDate() == QDate(2001, 2, 1));
+ CPPUNIT_ASSERT(s.willEnd() == false);
+ CPPUNIT_ASSERT(s.isFixed() == true);
+ CPPUNIT_ASSERT(s.autoEnter() == true);
+
+ MyMoneyTransaction t = s.transaction();
+ CPPUNIT_ASSERT(t.splitCount() == 2);
+
+ s = m->getSchedule("A000001", "SCHED00005");
+
+ CPPUNIT_FAIL("Exception expected while getting schedule SCHED00005");
+ } catch (MyMoneyException *e)
+ {
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testGetScheduled()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ QValueList<QString> testList;
+
+ testList = m->getScheduled("A000001");
+ CPPUNIT_ASSERT(testList.size() == 3);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00001");
+ CPPUNIT_ASSERT(testList[1] == "SCHED00002");
+ CPPUNIT_ASSERT(testList[2] == "SCHED00003");
+
+ testList = m->getScheduled("A000001", MyMoneySchedule::TYPE_DEPOSIT);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00002");
+
+ testList = m->getScheduled("A000001", MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00001");
+
+ testList = m->getScheduled("A000001", MyMoneySchedule::TYPE_TRANSFER);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00003");
+
+ testList = m->getScheduled("A000001", MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00002");
+
+ testList = m->getScheduled("A000001", QDate(2001, 1, 1), QDate(2001, 2, 1));
+ CPPUNIT_ASSERT(testList.size() == 2);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00001");
+ CPPUNIT_ASSERT(testList[1] == "SCHED00002");
+
+ } catch(MyMoneyException *e) {
+ char buf[256];
+ sprintf(buf, "Unexpected exception: %s", e->what().latin1());
+ CPPUNIT_FAIL(buf);
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testGetOverdue()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ QValueList<QString> testList;
+
+ testList = m->getOverdue("A000001");
+ CPPUNIT_ASSERT(testList.size() == 3);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00001");
+ CPPUNIT_ASSERT(testList[1] == "SCHED00002");
+ CPPUNIT_ASSERT(testList[2] == "SCHED00003");
+
+ testList = m->getOverdue("A000001", MyMoneySchedule::TYPE_DEPOSIT);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00002");
+
+ testList = m->getOverdue("A000001", MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00001");
+
+ testList = m->getOverdue("A000001", MyMoneySchedule::TYPE_TRANSFER);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00003");
+
+ testList = m->getOverdue("A000001", MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(testList.size() == 1);
+ CPPUNIT_ASSERT(testList[0] == "SCHED00002");
+ } catch(MyMoneyException *e) {
+ char buf[256];
+ sprintf(buf, "Unexpected exception: %s", e->what().latin1());
+ CPPUNIT_FAIL(buf);
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testNextPayment()
+/*
+ * Test for a schedule where a payment hasn't yet been made.
+ * First payment is in the future.
+*/
+{
+ MyMoneySchedule sch;
+ QString future_sched = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ "<SCHEDULED_TX startDate=\"2007-02-17\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH000058\" name=\"Car Tax\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"16384\" >\n"
+ " <PAYMENTS/>\n"
+ " <TRANSACTION postdate=\"\" memo=\"\" id=\"\" commodity=\"GBP\" entrydate=\"\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000044\" reconciledate=\"\" shares=\"-15000/100\" action=\"Withdrawal\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"-15000/100\" account=\"A000155\" />\n"
+ " <SPLIT payee=\"\" reconciledate=\"\" shares=\"15000/100\" action=\"Withdrawal\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"15000/100\" account=\"A000182\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS/>\n"
+ " </TRANSACTION>\n"
+ "</SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ );
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(future_sched);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ sch = MyMoneySchedule(node);
+ CPPUNIT_ASSERT(sch.nextPayment(QDate(2007,2,14)) == QDate(2007,2,17));
+ CPPUNIT_ASSERT(sch.nextPayment(QDate(2007,2,17)) == QDate(2008,2,17));
+ CPPUNIT_ASSERT(sch.nextPayment(QDate(2007,2,18)) == QDate(2008,2,17));
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ MyMoneySchedule s1 = m->getSchedule("A000001", "SCHED00001");
+ MyMoneySchedule s2 = m->getSchedule("A000001", "SCHED00002");
+ MyMoneySchedule s3 = m->getSchedule("A000001", "SCHED00003");
+
+ QDate nextPayment1 = s1.nextPayment();
+ QDate nextPayment2 = s2.nextPayment();
+ QDate nextPayment3 = s3.nextPayment();
+
+ CPPUNIT_ASSERT(nextPayment1.year() != 1900);
+ CPPUNIT_ASSERT(nextPayment2.year() != 1900);
+ CPPUNIT_ASSERT(nextPayment3.year() != 1900);
+ } catch (MyMoneyException *e)
+ {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testAddHalfMonths()
+{
+ // addHalfMonths is private
+ // Test a Schedule with occurence OCCUR_EVERYHALFMONTH using nextPayment
+ MyMoneySchedule s;
+ s.setStartDate(QDate(2007, 1, 1));
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ s.setNextDueDate(s.startDate());
+ s.setLastPayment(s.startDate());
+
+ QString format("yyyy-MM-dd");
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-16" );
+ s.setNextDueDate(QDate(2007, 1, 2));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-17" );
+ s.setNextDueDate(QDate(2007, 1, 3));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-18" );
+ s.setNextDueDate(QDate(2007, 1, 4));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-19" );
+ s.setNextDueDate(QDate(2007, 1, 5));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-20" );
+ s.setNextDueDate(QDate(2007, 1, 6));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-21" );
+ s.setNextDueDate(QDate(2007, 1, 7));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-22" );
+ s.setNextDueDate(QDate(2007, 1, 8));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-23" );
+ s.setNextDueDate(QDate(2007, 1, 9));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-24" );
+ s.setNextDueDate(QDate(2007, 1, 10));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-25" );
+ s.setNextDueDate(QDate(2007, 1, 11));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-26" );
+ s.setNextDueDate(QDate(2007, 1, 12));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-27" );
+ s.setNextDueDate(QDate(2007, 1, 13));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-28" );
+ s.setNextDueDate(QDate(2007, 1, 14));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-29" );
+ // 15 -> Last Day
+ s.setNextDueDate(QDate(2007, 1, 15));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-01-31" );
+ s.setNextDueDate(QDate(2007, 1, 16));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-01" );
+ s.setNextDueDate(QDate(2007, 1, 17));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-02" );
+ s.setNextDueDate(QDate(2007, 1, 18));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-03" );
+ s.setNextDueDate(QDate(2007, 1, 19));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-04" );
+ s.setNextDueDate(QDate(2007, 1, 20));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-05" );
+ s.setNextDueDate(QDate(2007, 1, 21));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-06" );
+ s.setNextDueDate(QDate(2007, 1, 22));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-07" );
+ s.setNextDueDate(QDate(2007, 1, 23));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-08" );
+ s.setNextDueDate(QDate(2007, 1, 24));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-09" );
+ s.setNextDueDate(QDate(2007, 1, 25));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-10" );
+ s.setNextDueDate(QDate(2007, 1, 26));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-11" );
+ s.setNextDueDate(QDate(2007, 1, 27));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-12" );
+ s.setNextDueDate(QDate(2007, 1, 28));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-13" );
+ s.setNextDueDate(QDate(2007, 1, 29));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-14" );
+ // 30th,31st -> 15th
+ s.setNextDueDate(QDate(2007, 1, 30));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-15" );
+ s.setNextDueDate(QDate(2007, 1, 31));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-02-15" );
+ // 30th (last day)
+ s.setNextDueDate(QDate(2007, 4, 30));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2007-05-15" );
+ // 28th of February (Last day): to 15th
+ s.setNextDueDate(QDate(1900, 2, 28));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "1900-03-15" );
+ // 28th of February (Leap year): to 13th
+ s.setNextDueDate(QDate(2000, 2, 28));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2000-03-13" );
+ // 29th of February (Leap year)
+ s.setNextDueDate(QDate(2000, 2, 29));
+ CPPUNIT_ASSERT( s.nextPayment(s.nextDueDate()).toString(format) == "2000-03-15" );
+ // Add multiple transactions
+ s.setStartDate(QDate(2007, 1, 1));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-01-16" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-01" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-02-16" );
+ s.setStartDate(QDate(2007, 1, 12));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-01-27" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-12" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-02-27" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-12" );
+ s.setStartDate(QDate(2007, 1, 13));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-01-28" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-13" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-15" );
+ s.setStartDate(QDate(2007, 1, 14));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-01-29" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-14" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-15" );
+ s.setStartDate(QDate(2007, 1, 15));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-01-31" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-15" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-15" );
+ s.setStartDate(QDate(2007, 1, 16));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-02-01" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-16" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-03-01" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-16" );
+ s.setStartDate(QDate(2007, 1, 27));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-02-12" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-27" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-03-12" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-27" );
+ s.setStartDate(QDate(2007, 1, 28));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-02-13" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-03-15" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-31" );
+ s.setStartDate(QDate(2007, 1, 29));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-02-14" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-03-15" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-31" );
+ s.setStartDate(QDate(2007, 1, 30));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-02-15" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-03-15" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-31" );
+ s.setStartDate(QDate(2007, 1, 31));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-02-15" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-02-28" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-03-15" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-03-31" );
+ s.setStartDate(QDate(2007, 4, 29));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-05-14" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-05-29" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-06-14" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-06-29" );
+ s.setStartDate(QDate(2007, 4, 30));
+ CPPUNIT_ASSERT( s.dateAfter(2).toString(format) == "2007-05-15" );
+ CPPUNIT_ASSERT( s.dateAfter(3).toString(format) == "2007-05-31" );
+ CPPUNIT_ASSERT( s.dateAfter(4).toString(format) == "2007-06-15" );
+ CPPUNIT_ASSERT( s.dateAfter(5).toString(format) == "2007-06-30" );
+}
+
+void MyMoneyScheduleTest::testPaymentDates()
+{
+ MyMoneySchedule sch;
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+
+ "<SCHEDULED_TX startDate=\"2003-12-31\" autoEnter=\"1\" weekendOption=\"0\" lastPayment=\"2006-01-31\" paymentType=\"2\" endDate=\"\" type=\"2\" id=\"SCH000032\" name=\"DSL\" fixed=\"0\" occurenceMultiplier=\"1\" occurence=\"32\" >\n"
+ " <PAYMENTS/>\n"
+ " <TRANSACTION postdate=\"2006-02-28\" memo=\"\" id=\"\" commodity=\"EUR\" entrydate=\"\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000076\" reconciledate=\"\" shares=\"1200/100\" action=\"Deposit\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"1200/100\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"\" reconciledate=\"\" shares=\"-1200/100\" action=\"Deposit\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"-1200/100\" account=\"A000009\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS/>\n"
+ " </TRANSACTION>\n"
+ "</SCHEDULED_TX>\n"
+
+ "</SCHEDULE-CONTAINER>\n"
+ );
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ QDate startDate(2006,1,28);
+ QDate endDate(2006,5,30);
+
+ try {
+ sch = MyMoneySchedule(node);
+ QDate nextPayment = sch.nextPayment(startDate);
+ QValueList<QDate> list = sch.paymentDates(nextPayment, endDate);
+ CPPUNIT_ASSERT(list.count() == 3);
+ CPPUNIT_ASSERT(list[0] == QDate(2006,2,28));
+ CPPUNIT_ASSERT(list[1] == QDate(2006,3,31));
+ // Would fall on a Sunday so gets moved back to 28th.
+ CPPUNIT_ASSERT(list[2] == QDate(2006,4,28));
+
+ // Add tests for each possible occurence.
+ // Check how paymentDates is meant to work
+ // Build a list of expected dates and compare
+ // MyMoneySchedule::OCCUR_ONCE
+ sch.setOccurence(MyMoneySchedule::OCCUR_ONCE);
+ startDate.setYMD(2009,1,1);
+ endDate.setYMD(2009,12,31);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0] == QDate(2009,1,1));
+ // MyMoneySchedule::OCCUR_DAILY
+ sch.setOccurence(MyMoneySchedule::OCCUR_DAILY);
+ startDate.setYMD(2009,1,1);
+ endDate.setYMD(2009,1,5);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 1, 1));
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 1, 2));
+ // Would fall on Saturday so gets moved to 2nd.
+ CPPUNIT_ASSERT(list[2] == QDate(2009, 1, 2));
+ // Would fall on Sunday so gets moved to 2nd.
+ CPPUNIT_ASSERT(list[3] == QDate(2009, 1, 2));
+ CPPUNIT_ASSERT(list[4] == QDate(2009, 1, 5));
+ // MyMoneySchedule::OCCUR_DAILY with multiplier 2
+ sch.setOccurenceMultiplier(2);
+ list = sch.paymentDates(startDate.addDays(1),endDate);
+ CPPUNIT_ASSERT(list.count() == 2);
+ // Would fall on Sunday so gets moved to 2nd.
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 1, 2));
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 1, 5));
+ sch.setOccurenceMultiplier(1);
+ // MyMoneySchedule::OCCUR_WEEKLY
+ sch.setOccurence(MyMoneySchedule::OCCUR_WEEKLY);
+ startDate.setYMD(2009,1,6);
+ endDate.setYMD(2009,2,4);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 1, 6));
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 1,13));
+ CPPUNIT_ASSERT(list[2] == QDate(2009, 1,20));
+ CPPUNIT_ASSERT(list[3] == QDate(2009, 1,27));
+ CPPUNIT_ASSERT(list[4] == QDate(2009, 2, 3));
+ // MyMoneySchedule::OCCUR_EVERYOTHERWEEK
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERWEEK);
+ startDate.setYMD(2009,2,5);
+ endDate.setYMD(2009,4,3);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 2, 5));
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 2,19));
+ CPPUNIT_ASSERT(list[2] == QDate(2009, 3, 5));
+ CPPUNIT_ASSERT(list[3] == QDate(2009, 3,19));
+ CPPUNIT_ASSERT(list[4] == QDate(2009, 4, 2));
+ // MyMoneySchedule::OCCUR_FORTNIGHTLY
+ sch.setOccurence(MyMoneySchedule::OCCUR_FORTNIGHTLY);
+ startDate.setYMD(2009,4,4);
+ endDate.setYMD(2009,5,31);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 4);
+ // First one would fall on a Saturday and would get moved
+ // to 3rd which is before start date so is not in list.
+ // Would fall on a Saturday so gets moved to 17th.
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 4,17));
+ // Would fall on a Saturday so gets moved to 1st.
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 5, 1));
+ // Would fall on a Saturday so gets moved to 15th.
+ CPPUNIT_ASSERT(list[2] == QDate(2009, 5,15));
+ // Would fall on a Saturday so gets moved to 29th.
+ CPPUNIT_ASSERT(list[3] == QDate(2009, 5,29));
+ // MyMoneySchedule::OCCUR_EVERYHALFMONTH
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ startDate.setYMD(2009,6,1);
+ endDate.setYMD(2009,8,11);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 6, 1));
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 6,16));
+ CPPUNIT_ASSERT(list[2] == QDate(2009, 7, 1));
+ CPPUNIT_ASSERT(list[3] == QDate(2009, 7,16));
+ // Would fall on a Saturday so gets moved to 31st.
+ CPPUNIT_ASSERT(list[4] == QDate(2009, 7, 31));
+ // MyMoneySchedule::OCCUR_EVERYTHREEWEEKS
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS);
+ startDate.setYMD(2009,8,12);
+ endDate.setYMD(2009,11,12);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2009, 8,12));
+ CPPUNIT_ASSERT(list[1] == QDate(2009, 9, 2));
+ CPPUNIT_ASSERT(list[2] == QDate(2009, 9,23));
+ CPPUNIT_ASSERT(list[3] == QDate(2009,10,14));
+ CPPUNIT_ASSERT(list[4] == QDate(2009,11, 4));
+ // MyMoneySchedule::OCCUR_EVERYFOURWEEKS
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYFOURWEEKS);
+ startDate.setYMD(2009,11,13);
+ endDate.setYMD(2010,3,13);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2009,11,13));
+ CPPUNIT_ASSERT(list[1] == QDate(2009,12,11));
+ CPPUNIT_ASSERT(list[2] == QDate(2010, 1, 8));
+ CPPUNIT_ASSERT(list[3] == QDate(2010, 2, 5));
+ CPPUNIT_ASSERT(list[4] == QDate(2010, 3, 5));
+ // MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS);
+ startDate.setYMD(2010,3,19);
+ endDate.setYMD(2010,7,19);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2010, 3,19));
+ // Would fall on a Sunday so gets moved to 16th.
+ CPPUNIT_ASSERT(list[1] == QDate(2010, 4,16));
+ CPPUNIT_ASSERT(list[2] == QDate(2010, 5,18));
+ CPPUNIT_ASSERT(list[3] == QDate(2010, 6,17));
+ // Would fall on a Saturday so gets moved to 16th.
+ CPPUNIT_ASSERT(list[4] == QDate(2010, 7,16));
+ // MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS);
+ startDate.setYMD(2010,7,26);
+ endDate.setYMD(2011,3,26);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2010, 7,26));
+ CPPUNIT_ASSERT(list[1] == QDate(2010, 9,20));
+ CPPUNIT_ASSERT(list[2] == QDate(2010,11,15));
+ CPPUNIT_ASSERT(list[3] == QDate(2011, 1,10));
+ CPPUNIT_ASSERT(list[4] == QDate(2011, 3, 7));
+ // MyMoneySchedule::OCCUR_EVERYOTHERMONTH
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERMONTH);
+ startDate.setYMD(2011,3,14);
+ endDate.setYMD(2011,11,20);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2011, 3,14));
+ // Would fall on a Saturday so gets moved to 13th.
+ CPPUNIT_ASSERT(list[1] == QDate(2011, 5,13));
+ CPPUNIT_ASSERT(list[2] == QDate(2011, 7,14));
+ CPPUNIT_ASSERT(list[3] == QDate(2011, 9,14));
+ CPPUNIT_ASSERT(list[4] == QDate(2011,11,14));
+ // MyMoneySchedule::OCCUR_EVERYTHREEMONTHS
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS);
+ startDate.setYMD(2011,11,15);
+ endDate.setYMD(2012,11,19);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2011,11,15));
+ CPPUNIT_ASSERT(list[1] == QDate(2012, 2,15));
+ CPPUNIT_ASSERT(list[2] == QDate(2012, 5,15));
+ CPPUNIT_ASSERT(list[3] == QDate(2012, 8,15));
+ CPPUNIT_ASSERT(list[4] == QDate(2012,11,15));
+ // MyMoneySchedule::OCCUR_QUARTERLY
+ sch.setOccurence(MyMoneySchedule::OCCUR_QUARTERLY);
+ startDate.setYMD(2012,11,20);
+ endDate.setYMD(2013,11,23);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2012,11,20));
+ CPPUNIT_ASSERT(list[1] == QDate(2013, 2,20));
+ CPPUNIT_ASSERT(list[2] == QDate(2013, 5,20));
+ CPPUNIT_ASSERT(list[3] == QDate(2013, 8,20));
+ CPPUNIT_ASSERT(list[4] == QDate(2013,11,20));
+ // MyMoneySchedule::OCCUR_EVERYFOURMONTHS
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYFOURMONTHS);
+ startDate.setYMD(2013,11,21);
+ endDate.setYMD(2015, 3,23);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2013,11,21));
+ CPPUNIT_ASSERT(list[1] == QDate(2014, 3,21));
+ CPPUNIT_ASSERT(list[2] == QDate(2014, 7,21));
+ CPPUNIT_ASSERT(list[3] == QDate(2014,11,21));
+ // Would fall on a Saturday so gets moved to 20th.
+ CPPUNIT_ASSERT(list[4] == QDate(2015, 3,20));
+ // MyMoneySchedule::OCCUR_TWICEYEARLY
+ sch.setOccurence(MyMoneySchedule::OCCUR_TWICEYEARLY);
+ startDate.setYMD(2015, 3,22);
+ endDate.setYMD(2017, 3,29);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 4);
+ // First date would fall on a Sunday which would get moved
+ // to 20th which is before start date so not in list.
+ CPPUNIT_ASSERT(list[0] == QDate(2015, 9,22));
+ CPPUNIT_ASSERT(list[1] == QDate(2016, 3,22));
+ CPPUNIT_ASSERT(list[2] == QDate(2016, 9,22));
+ CPPUNIT_ASSERT(list[3] == QDate(2017, 3,22));
+ // MyMoneySchedule::OCCUR_YEARLY
+ sch.setOccurence(MyMoneySchedule::OCCUR_YEARLY);
+ startDate.setYMD(2017, 3,23);
+ endDate.setYMD(2021, 3,29);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2017, 3,23));
+ CPPUNIT_ASSERT(list[1] == QDate(2018, 3,23));
+ // Would fall on a Saturday so gets moved to 22nd.
+ CPPUNIT_ASSERT(list[2] == QDate(2019, 3,22));
+ CPPUNIT_ASSERT(list[3] == QDate(2020, 3,23));
+ CPPUNIT_ASSERT(list[4] == QDate(2021, 3,23));
+ // MyMoneySchedule::OCCUR_EVERYOTHERYEAR
+ sch.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+ startDate.setYMD(2021, 3,24);
+ endDate.setYMD(2029, 3,30);
+ sch.setStartDate(startDate);
+ sch.setNextDueDate(startDate);
+ list = sch.paymentDates(startDate,endDate);
+ CPPUNIT_ASSERT(list.count() == 5);
+ CPPUNIT_ASSERT(list[0] == QDate(2021, 3,24));
+ CPPUNIT_ASSERT(list[1] == QDate(2023, 3,24));
+ CPPUNIT_ASSERT(list[2] == QDate(2025, 3,24));
+ CPPUNIT_ASSERT(list[3] == QDate(2027, 3,24));
+ // Would fall on a Saturday so gets moved to 23rd.
+ CPPUNIT_ASSERT(list[4] == QDate(2029, 3,23));
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ MyMoneySchedule s1 = m->getSchedule("A000001", "SCHED00001");
+ MyMoneySchedule s2 = m->getSchedule("A000001", "SCHED00002");
+ MyMoneySchedule s3 = m->getSchedule("A000001", "SCHED00003");
+
+ QValueList<QDate> payments1 = s1.paymentDates(QDate(2001, 1, 1), QDate(2001, 2, 1));
+ QValueList<QDate> payments2 = s2.paymentDates(QDate(2001, 2, 1), QDate(2001, 6, 1));
+ QValueList<QDate> payments3 = s3.paymentDates(QDate(2001, 3, 1), QDate(2005, 3, 1));
+
+ CPPUNIT_ASSERT(payments1.size() == 5);
+ CPPUNIT_ASSERT(payments2.size() == 5);
+ CPPUNIT_ASSERT(payments3.size() == 5);
+ } catch (MyMoneyException *e)
+ {
+ CPPUNIT_FAIL("Unexpected exception");
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testReplaceSchedule()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ MyMoneySchedule s = m->getSchedule("A000001", "SCHED00002");
+ CPPUNIT_ASSERT(s.type() == MyMoneySchedule::TYPE_DEPOSIT);
+ s.setType(MyMoneySchedule::TYPE_TRANSFER);
+ m->replaceSchedule("A000001", "SCHED00002", s);
+ s = m->getSchedule("A000001", "SCHED00002");
+ CPPUNIT_ASSERT(s.type() == MyMoneySchedule::TYPE_TRANSFER);
+
+ } catch(MyMoneyException *e) {
+ char buf[256];
+ sprintf(buf, "Unexpected exception: %s", e->what().latin1());
+ CPPUNIT_FAIL(buf);
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testRemoveSchedule()
+{
+/*
+ MyMoneyScheduled *m = MyMoneyScheduled::instance();
+ CPPUNIT_ASSERT(m!=NULL);
+
+ try
+ {
+ QValueList<QString> testList;
+
+ testList = m->getScheduled("A000001");
+ CPPUNIT_ASSERT(testList.size() == 3);
+
+ m->removeSchedule("A000001", "SCHED00002");
+
+ testList = m->getScheduled("A000001");
+ CPPUNIT_ASSERT(testList.size() == 2);
+
+ m->getSchedule("A000001", "SCHED00002");
+
+ CPPUNIT_FAIL("Exception expected while getting schedule SCHED00002");
+ } catch (MyMoneyException *e)
+ {
+ delete e;
+ }
+*/
+}
+
+void MyMoneyScheduleTest::testWriteXML() {
+ MyMoneySchedule sch( "A Name",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 123,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate(),
+ QDate(),
+ true,
+ true);
+
+ sch.setLastPayment(QDate::currentDate());
+ sch.recordPayment(QDate::currentDate());
+ sch.setId("SCH0001");
+
+ MyMoneyTransaction t;
+ t.setPostDate(QDate(2001,12,28));
+ t.setEntryDate(QDate(2003,9,29));
+ t.setId("T000000000000000001");
+ t.setMemo("Wohnung:Miete");
+ t.setCommodity("EUR");
+ t.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(MyMoneyMoney(96379, 100));
+ s.setValue(MyMoneyMoney(96379, 100));
+ s.setAccountId("A000076");
+ s.setBankID("SPID1");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ t.addSplit(s);
+
+ s.setPayeeId("P000001");
+ s.setShares(MyMoneyMoney(-96379, 100));
+ s.setValue(MyMoneyMoney(-96379, 100));
+ s.setAccountId("A000276");
+ s.setBankID("SPID2");
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ s.clearId();
+ t.addSplit(s);
+
+ sch.setTransaction(t);
+
+ QDomDocument doc("TEST");
+ QDomElement el = doc.createElement("SCHEDULE-CONTAINER");
+ doc.appendChild(el);
+ sch.writeXML(doc, el);
+
+ QString ref = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0001\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"123\" occurence=\"4\" >\n"
+ " <PAYMENTS>\n"
+ " <PAYMENT date=\"%3\" />\n"
+ " </PAYMENTS>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" id=\"S0001\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" id=\"S0002\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ ).arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate));
+
+ CPPUNIT_ASSERT(doc.toString() == ref);
+}
+
+void MyMoneyScheduleTest::testReadXML() {
+ MyMoneySchedule sch;
+
+ QString ref_ok1 = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n"
+ " <PAYMENTS>\n"
+ " <PAYMENT date=\"%3\" />\n"
+ " </PAYMENTS>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"SPID1\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"SPID2\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ ).arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate));
+
+ // diff to ref_ok1 is that we now have an empty entrydate
+ // in the transaction parameters
+ QString ref_ok2 = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n"
+ " <PAYMENTS>\n"
+ " <PAYMENT date=\"%3\" />\n"
+ " </PAYMENTS>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"SPID1\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"SPID2\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ ).arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate));
+
+ QString ref_false = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULE startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n"
+ " <PAYMENTS count=\"1\" >\n"
+ " <PAYMENT date=\"%3\" />\n"
+ " </PAYMENTS>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"SPID1\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"SPID2\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ ).arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate));
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_false);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ sch = MyMoneySchedule(node);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ doc.setContent(ref_ok1);
+ node = doc.documentElement().firstChild().toElement();
+
+
+ try {
+ sch = MyMoneySchedule(node);
+ CPPUNIT_ASSERT(sch.id() == "SCH0002");
+ CPPUNIT_ASSERT(sch.nextDueDate() == QDate::currentDate().addDays(7));
+ CPPUNIT_ASSERT(sch.startDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(sch.endDate() == QDate());
+ CPPUNIT_ASSERT(sch.autoEnter() == true);
+ CPPUNIT_ASSERT(sch.isFixed() == true);
+ CPPUNIT_ASSERT(sch.weekendOption() == MyMoneySchedule::MoveNothing);
+ CPPUNIT_ASSERT(sch.lastPayment() == QDate::currentDate());
+ CPPUNIT_ASSERT(sch.paymentType() == MyMoneySchedule::STYPE_DIRECTDEBIT);
+ CPPUNIT_ASSERT(sch.type() == MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(sch.name() == "A Name");
+ CPPUNIT_ASSERT(sch.occurence() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(sch.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(sch.nextDueDate() == sch.lastPayment().addDays(7));
+ CPPUNIT_ASSERT(sch.recordedPayments().count() == 1);
+ CPPUNIT_ASSERT(sch.recordedPayments()[0] == QDate::currentDate());
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ doc.setContent(ref_ok2);
+ node = doc.documentElement().firstChild().toElement();
+
+
+ try {
+ sch = MyMoneySchedule(node);
+ CPPUNIT_ASSERT(sch.id() == "SCH0002");
+ CPPUNIT_ASSERT(sch.nextDueDate() == QDate::currentDate().addDays(7));
+ CPPUNIT_ASSERT(sch.startDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(sch.endDate() == QDate());
+ CPPUNIT_ASSERT(sch.autoEnter() == true);
+ CPPUNIT_ASSERT(sch.isFixed() == true);
+ CPPUNIT_ASSERT(sch.weekendOption() == MyMoneySchedule::MoveNothing);
+ CPPUNIT_ASSERT(sch.lastPayment() == QDate::currentDate());
+ CPPUNIT_ASSERT(sch.paymentType() == MyMoneySchedule::STYPE_DIRECTDEBIT);
+ CPPUNIT_ASSERT(sch.type() == MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(sch.name() == "A Name");
+ CPPUNIT_ASSERT(sch.occurence() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(sch.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(sch.nextDueDate() == sch.lastPayment().addDays(7));
+ CPPUNIT_ASSERT(sch.recordedPayments().count() == 1);
+ CPPUNIT_ASSERT(sch.recordedPayments()[0] == QDate::currentDate());
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyScheduleTest::testHasReferenceTo()
+{
+ MyMoneySchedule sch;
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n"
+ " <PAYMENTS>\n"
+ " <PAYMENT date=\"%3\" />\n"
+ " </PAYMENTS>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ ).arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate))
+ .arg(QDate::currentDate().toString(Qt::ISODate));
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ sch = MyMoneySchedule(node);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ CPPUNIT_ASSERT(sch.hasReferenceTo("P000001") == true);
+ CPPUNIT_ASSERT(sch.hasReferenceTo("A000276") == true);
+ CPPUNIT_ASSERT(sch.hasReferenceTo("A000076") == true);
+ CPPUNIT_ASSERT(sch.hasReferenceTo("EUR") == true);
+}
+
+void MyMoneyScheduleTest::testAdjustedNextDueDate()
+{
+ MyMoneySchedule s;
+
+ QDate dueDate(2007,9,3); // start on a monday
+ for(int i = 0; i < 7; ++i) {
+ s.setNextDueDate(dueDate);
+ s.setWeekendOption(MyMoneySchedule::MoveNothing);
+ CPPUNIT_ASSERT(s.adjustedNextDueDate() == dueDate);
+
+ s.setWeekendOption(MyMoneySchedule::MoveFriday);
+ switch(i) {
+ case 5: // saturday
+ case 6: // sunday
+ break;
+ CPPUNIT_ASSERT(s.adjustedNextDueDate() == QDate(2007,9,7));
+ default:
+ CPPUNIT_ASSERT(s.adjustedNextDueDate() == dueDate);
+ break;
+ }
+
+ s.setWeekendOption(MyMoneySchedule::MoveMonday);
+ switch(i) {
+ case 5: // saturday
+ case 6: // sunday
+ CPPUNIT_ASSERT(s.adjustedNextDueDate() == QDate(2007,9,10));
+ break;
+ default:
+ CPPUNIT_ASSERT(s.adjustedNextDueDate() == dueDate);
+ break;
+ }
+ dueDate = dueDate.addDays(1);
+ }
+}
+
+void MyMoneyScheduleTest::testModifyNextDueDate(void)
+{
+ MyMoneySchedule s;
+ s.setStartDate(QDate(2007, 1, 1));
+ s.setOccurence(MyMoneySchedule::OCCUR_MONTHLY);
+ s.setNextDueDate(s.startDate().addMonths(1));
+ s.setLastPayment(s.startDate());
+
+ QValueList<QDate> dates;
+ dates = s.paymentDates(QDate(2007,2,1), QDate(2007,2,1));
+ CPPUNIT_ASSERT(s.nextDueDate() == QDate(2007,2,1));
+ CPPUNIT_ASSERT(dates.count() == 1);
+ CPPUNIT_ASSERT(dates[0] == QDate(2007,2,1));
+
+ s.setNextDueDate(QDate(2007,1,24));
+
+ dates = s.paymentDates(QDate(2007,2,1), QDate(2007,2,1));
+ CPPUNIT_ASSERT(s.nextDueDate() == QDate(2007,1,24));
+ CPPUNIT_ASSERT(dates.count() == 0);
+
+ dates = s.paymentDates(QDate(2007,1,24), QDate(2007,1,24));
+ CPPUNIT_ASSERT(dates.count() == 1);
+
+ dates = s.paymentDates(QDate(2007,1,24), QDate(2007,2,24));
+ CPPUNIT_ASSERT(dates.count() == 2);
+ CPPUNIT_ASSERT(dates[0] == QDate(2007,1,24));
+ CPPUNIT_ASSERT(dates[1] == QDate(2007,2,24));
+
+}
+
+void MyMoneyScheduleTest::testDaysBetweenEvents()
+{
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_ONCE) == 0);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_DAILY) == 1);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_WEEKLY) == 7);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYOTHERWEEK) == 14);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_FORTNIGHTLY) == 14);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYHALFMONTH) == 15);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS) == 21);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYFOURWEEKS) == 28);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS) == 30);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_MONTHLY) == 30);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS) == 56);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYOTHERMONTH) == 60);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS) == 90);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_QUARTERLY) == 90);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYFOURMONTHS) == 120);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_TWICEYEARLY) == 180);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_YEARLY) == 360);
+ CPPUNIT_ASSERT(MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::OCCUR_EVERYOTHERYEAR) == 0);
+}
+
+void MyMoneyScheduleTest::testStringToOccurence()
+{
+ // For each occurenceE:
+ // test MyMoneySchedule::stringToOccurence(QString) == occurence
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Once")) == MyMoneySchedule::OCCUR_ONCE );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Daily")) == MyMoneySchedule::OCCUR_DAILY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Weekly")) == MyMoneySchedule::OCCUR_WEEKLY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every other week")) == MyMoneySchedule::OCCUR_EVERYOTHERWEEK );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Fortnightly")) == MyMoneySchedule::OCCUR_FORTNIGHTLY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every half month")) == MyMoneySchedule::OCCUR_EVERYHALFMONTH );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every four weeks")) == MyMoneySchedule::OCCUR_EVERYFOURWEEKS );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Monthly")) == MyMoneySchedule::OCCUR_MONTHLY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every eight weeks")) == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every two months")) == MyMoneySchedule::OCCUR_EVERYOTHERMONTH );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every three months")) == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Quarterly")) == MyMoneySchedule::OCCUR_QUARTERLY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every four months")) == MyMoneySchedule::OCCUR_EVERYFOURMONTHS );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Twice yearly")) == MyMoneySchedule::OCCUR_TWICEYEARLY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Yearly")) == MyMoneySchedule::OCCUR_YEARLY );
+ CPPUNIT_ASSERT( MyMoneySchedule::stringToOccurence(i18n("Every other year")) == MyMoneySchedule::OCCUR_EVERYOTHERYEAR );
+ // test occurence == stringToOccurence(i18n(occurenceToString(occurence)))
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_ONCE == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_ONCE))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_DAILY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_DAILY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_WEEKLY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_WEEKLY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYOTHERWEEK == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERWEEK))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_FORTNIGHTLY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_FORTNIGHTLY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYHALFMONTH == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYTHREEWEEKS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYTHREEWEEKS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYFOURWEEKS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURWEEKS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_MONTHLY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_MONTHLY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYOTHERMONTH == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERMONTH))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYTHREEMONTHS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_QUARTERLY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_QUARTERLY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYFOURMONTHS == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURMONTHS))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_TWICEYEARLY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_TWICEYEARLY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_YEARLY == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_YEARLY))) );
+ CPPUNIT_ASSERT( MyMoneySchedule::OCCUR_EVERYOTHERYEAR == MyMoneySchedule::stringToOccurence(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERYEAR))) );
+}
+void MyMoneyScheduleTest::testEventsPerYear()
+{
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_ONCE) == 0);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_DAILY) == 365);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_WEEKLY) == 52);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYOTHERWEEK) == 26);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_FORTNIGHTLY) == 26);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYHALFMONTH) == 24);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS) == 17);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYFOURWEEKS) == 13);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS) == 12);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_MONTHLY) == 12);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS) == 6);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYOTHERMONTH) == 6);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS) == 4);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_QUARTERLY) == 4);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYFOURMONTHS) == 3);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_TWICEYEARLY) == 2);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_YEARLY) == 1);
+ CPPUNIT_ASSERT(MyMoneySchedule::eventsPerYear(MyMoneySchedule::OCCUR_EVERYOTHERYEAR) == 0);
+}
+
+void MyMoneyScheduleTest::testOccurenceToString()
+{
+ // For each occurenceE test MyMoneySchedule::occurenceToString(occurenceE)
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_ONCE) == "Once" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_DAILY) == "Daily" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_WEEKLY) == "Weekly" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERWEEK) == "Every other week" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_FORTNIGHTLY) == "Fortnightly" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH) == "Every half month" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS) == "Every three weeks" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURWEEKS) == "Every four weeks" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS) == "Every thirty days" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_MONTHLY) == "Monthly" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS) == "Every eight weeks" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERMONTH) == "Every two months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS) == "Every three months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_QUARTERLY) == "Quarterly" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURMONTHS) == "Every four months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_TWICEYEARLY) == "Twice yearly" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_YEARLY) == "Yearly" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERYEAR) == "Every other year" );
+ // For each occurenceE set occurence and compare occurenceToString() with oTS(occurence())
+ MyMoneySchedule s;
+ s.setStartDate(QDate(2007, 1, 1));
+ s.setNextDueDate(s.startDate());
+ s.setLastPayment(s.startDate());
+ s.setOccurence(MyMoneySchedule::OCCUR_ONCE); CPPUNIT_ASSERT(s.occurenceToString() == "Once" );
+ s.setOccurence(MyMoneySchedule::OCCUR_DAILY); CPPUNIT_ASSERT(s.occurenceToString() == "Daily" );
+ s.setOccurence(MyMoneySchedule::OCCUR_WEEKLY); CPPUNIT_ASSERT(s.occurenceToString() == "Weekly" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERWEEK); CPPUNIT_ASSERT(s.occurenceToString() == "Every other week" );
+ // Fortnightly no longer used: Every other week used instead
+ s.setOccurence(MyMoneySchedule::OCCUR_FORTNIGHTLY); CPPUNIT_ASSERT(s.occurenceToString() == "Every other week" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYHALFMONTH); CPPUNIT_ASSERT(s.occurenceToString() == "Every half month" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS); CPPUNIT_ASSERT(s.occurenceToString() == "Every three weeks" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYFOURWEEKS); CPPUNIT_ASSERT(s.occurenceToString() == "Every four weeks" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS); CPPUNIT_ASSERT(s.occurenceToString() == "Every thirty days" );
+ s.setOccurence(MyMoneySchedule::OCCUR_MONTHLY); CPPUNIT_ASSERT(s.occurenceToString() == "Monthly" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS); CPPUNIT_ASSERT(s.occurenceToString() == "Every eight weeks" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERMONTH); CPPUNIT_ASSERT(s.occurenceToString() == "Every two months" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS); CPPUNIT_ASSERT(s.occurenceToString() == "Every three months" );
+ // Quarterly no longer used. Every three months used instead
+ s.setOccurence(MyMoneySchedule::OCCUR_QUARTERLY); CPPUNIT_ASSERT(s.occurenceToString() == "Every three months" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYFOURMONTHS); CPPUNIT_ASSERT(s.occurenceToString() == "Every four months" );
+ s.setOccurence(MyMoneySchedule::OCCUR_TWICEYEARLY); CPPUNIT_ASSERT(s.occurenceToString() == "Twice yearly" );
+ s.setOccurence(MyMoneySchedule::OCCUR_YEARLY); CPPUNIT_ASSERT(s.occurenceToString() == "Yearly" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERYEAR); CPPUNIT_ASSERT(s.occurenceToString() == "Every other year" );
+ // Test occurenceToString(mult,occ)
+ // Test all pairs equivalent to simple occurences: should return the same as occurenceToString(simpleOcc)
+ // TODO replace string with (mult,occ) call.
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_ONCE) == MyMoneySchedule::occurenceToString(1,MyMoneySchedule::OCCUR_ONCE) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_DAILY) == MyMoneySchedule::occurenceToString(1,MyMoneySchedule::OCCUR_DAILY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_WEEKLY) == MyMoneySchedule::occurenceToString(1,MyMoneySchedule::OCCUR_WEEKLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERWEEK) == MyMoneySchedule::occurenceToString(2,MyMoneySchedule::OCCUR_WEEKLY) );
+ // OCCUR_FORTNIGHTLY will no longer be used: only Every Other Week
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH) == MyMoneySchedule::occurenceToString(1,MyMoneySchedule::OCCUR_EVERYHALFMONTH) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS) == MyMoneySchedule::occurenceToString(3,MyMoneySchedule::OCCUR_WEEKLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURWEEKS) == MyMoneySchedule::occurenceToString(4,MyMoneySchedule::OCCUR_WEEKLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_MONTHLY) == MyMoneySchedule::occurenceToString(1,MyMoneySchedule::OCCUR_MONTHLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS) == MyMoneySchedule::occurenceToString(8,MyMoneySchedule::OCCUR_WEEKLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERMONTH) == MyMoneySchedule::occurenceToString(2,MyMoneySchedule::OCCUR_MONTHLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS) == MyMoneySchedule::occurenceToString(3,MyMoneySchedule::OCCUR_MONTHLY) );
+ // OCCUR_QUARTERLY will no longer be used: only Every Three Months
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURMONTHS) == MyMoneySchedule::occurenceToString(4,MyMoneySchedule::OCCUR_MONTHLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_TWICEYEARLY) == MyMoneySchedule::occurenceToString(6,MyMoneySchedule::OCCUR_MONTHLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_YEARLY) == MyMoneySchedule::occurenceToString(1,MyMoneySchedule::OCCUR_YEARLY) );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERYEAR) == MyMoneySchedule::occurenceToString(2,MyMoneySchedule::OCCUR_YEARLY) );
+ // Test additional calls with other mult,occ
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(2,MyMoneySchedule::OCCUR_ONCE) == "2 times" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(2,MyMoneySchedule::OCCUR_DAILY) == "Every 2 days" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(5,MyMoneySchedule::OCCUR_WEEKLY) == "Every 5 weeks" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(2,MyMoneySchedule::OCCUR_EVERYHALFMONTH) == "Every 2 half months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(5,MyMoneySchedule::OCCUR_MONTHLY) == "Every 5 months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(3,MyMoneySchedule::OCCUR_YEARLY) == "Every 3 years" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(37,MyMoneySchedule::OCCUR_ONCE) == "37 times" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(43,MyMoneySchedule::OCCUR_DAILY) == "Every 43 days" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(61,MyMoneySchedule::OCCUR_WEEKLY) == "Every 61 weeks" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(73,MyMoneySchedule::OCCUR_EVERYHALFMONTH) == "Every 73 half months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(83,MyMoneySchedule::OCCUR_MONTHLY) == "Every 83 months" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurenceToString(89,MyMoneySchedule::OCCUR_YEARLY) == "Every 89 years" );
+ // Test instance-level occurenceToString method is using occurencePeriod and multiplier
+ // For each base occurence set occurencePeriod and multiplier
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_ONCE); s.setOccurenceMultiplier(1);
+ s.setOccurence(MyMoneySchedule::OCCUR_ONCE);
+ s.setOccurenceMultiplier(1); CPPUNIT_ASSERT(s.occurenceToString() == "Once" );
+ s.setOccurenceMultiplier(2); CPPUNIT_ASSERT(s.occurenceToString() == "2 times" );
+ s.setOccurenceMultiplier(3); CPPUNIT_ASSERT(s.occurenceToString() == "3 times" );
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_DAILY);
+ s.setOccurenceMultiplier(1); CPPUNIT_ASSERT(s.occurenceToString() == "Daily" );
+ s.setOccurenceMultiplier(30); CPPUNIT_ASSERT(s.occurenceToString() == "Every thirty days" );
+ s.setOccurenceMultiplier(3); CPPUNIT_ASSERT(s.occurenceToString() == "Every 3 days" );
+ s.setOccurence(MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceToString() == "Weekly" );
+ s.setOccurenceMultiplier(2); CPPUNIT_ASSERT(s.occurenceToString() == "Every other week" );
+ s.setOccurenceMultiplier(3); CPPUNIT_ASSERT(s.occurenceToString() == "Every three weeks" );
+ s.setOccurenceMultiplier(4); CPPUNIT_ASSERT(s.occurenceToString() == "Every four weeks" );
+ s.setOccurenceMultiplier(5); CPPUNIT_ASSERT(s.occurenceToString() == "Every 5 weeks" );
+ s.setOccurenceMultiplier(7); CPPUNIT_ASSERT(s.occurenceToString() == "Every 7 weeks" );
+ s.setOccurenceMultiplier(8); CPPUNIT_ASSERT(s.occurenceToString() == "Every eight weeks" );
+ s.setOccurenceMultiplier(9); CPPUNIT_ASSERT(s.occurenceToString() == "Every 9 weeks" );
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ s.setOccurenceMultiplier(1); CPPUNIT_ASSERT(s.occurenceToString() == "Every half month" );
+ s.setOccurenceMultiplier(2); CPPUNIT_ASSERT(s.occurenceToString() == "Every 2 half months" );
+ s.setOccurence(MyMoneySchedule::OCCUR_MONTHLY);
+ s.setOccurenceMultiplier(1); CPPUNIT_ASSERT(s.occurenceToString() == "Monthly" );
+ s.setOccurenceMultiplier(2); CPPUNIT_ASSERT(s.occurenceToString() == "Every two months" );
+ s.setOccurenceMultiplier(3); CPPUNIT_ASSERT(s.occurenceToString() == "Every three months" );
+ s.setOccurenceMultiplier(4); CPPUNIT_ASSERT(s.occurenceToString() == "Every four months" );
+ s.setOccurenceMultiplier(5); CPPUNIT_ASSERT(s.occurenceToString() == "Every 5 months" );
+ s.setOccurenceMultiplier(6); CPPUNIT_ASSERT(s.occurenceToString() == "Twice yearly" );
+ s.setOccurenceMultiplier(7); CPPUNIT_ASSERT(s.occurenceToString() == "Every 7 months" );
+ s.setOccurence(MyMoneySchedule::OCCUR_YEARLY);
+ s.setOccurenceMultiplier(1); CPPUNIT_ASSERT(s.occurenceToString() == "Yearly" );
+ s.setOccurenceMultiplier(2); CPPUNIT_ASSERT(s.occurenceToString() == "Every other year" );
+ s.setOccurenceMultiplier(3); CPPUNIT_ASSERT(s.occurenceToString() == "Every 3 years" );
+}
+
+void MyMoneyScheduleTest::testOccurencePeriodToString()
+{
+ // For each occurenceE test MyMoneySchedule::occurencePeriodToString(occurenceE)
+ // Base occurences are translated
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_ONCE) == "Once" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_DAILY) == "Day" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_WEEKLY) == "Week" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH) == "Half-month" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_MONTHLY) == "Month" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_YEARLY) == "Year" );
+ // All others are not translated so return Any
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYOTHERWEEK) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_FORTNIGHTLY) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYFOURWEEKS) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYOTHERMONTH) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_QUARTERLY) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYFOURMONTHS) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_TWICEYEARLY) == "Any" );
+ CPPUNIT_ASSERT(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYOTHERYEAR) == "Any" );
+}
+
+void MyMoneyScheduleTest::testOccurencePeriod()
+{
+ // Each occurence:
+ // Set occurence using setOccurencePeriod
+ // occurencePeriod should match what we set
+ // occurence depends on multiplier
+ // TODO:
+ // Once occurence() and setOccurence() are converting between compound and simple occurences
+ // we need to change the occurence() check and add an occurenceMultiplier() check
+ MyMoneySchedule s;
+ s.setStartDate(QDate(2007, 1, 1));
+ s.setNextDueDate(s.startDate());
+ s.setLastPayment(s.startDate());
+ // Set all base occurences
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_ONCE);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_ONCE );
+ s.setOccurenceMultiplier(1);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_ONCE );
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_ONCE );
+ s.setOccurenceMultiplier(2);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_ONCE );
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_ONCE );
+
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_DAILY);
+ s.setOccurenceMultiplier(1);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_DAILY);
+ s.setOccurenceMultiplier(30);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 30);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS);
+ s.setOccurenceMultiplier(2);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_DAILY);
+
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ s.setOccurenceMultiplier(1);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_WEEKLY);
+ s.setOccurenceMultiplier(2);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERWEEK);
+ s.setOccurenceMultiplier(3);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 3);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS);
+ s.setOccurenceMultiplier(4);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 4);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYFOURWEEKS);
+ s.setOccurenceMultiplier(5);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 5);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_WEEKLY);
+ s.setOccurenceMultiplier(8);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 8);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS);
+
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ s.setOccurenceMultiplier(1);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ s.setOccurenceMultiplier(2);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ s.setOccurenceMultiplier(1);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_MONTHLY);
+ s.setOccurenceMultiplier(2);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERMONTH);
+ s.setOccurenceMultiplier(3);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 3);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS);
+ s.setOccurenceMultiplier(4);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 4);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYFOURMONTHS);
+ s.setOccurenceMultiplier(5);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 5);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_MONTHLY);
+ s.setOccurenceMultiplier(6);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 6);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_TWICEYEARLY);
+
+ s.setOccurencePeriod(MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_YEARLY);
+ s.setOccurenceMultiplier(1);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_YEARLY);
+ s.setOccurenceMultiplier(2);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+ s.setOccurenceMultiplier(3);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 3);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_YEARLY);
+
+ // Set occurence: check occurence, Period and Multiplier
+ s.setOccurence(MyMoneySchedule::OCCUR_ONCE);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_ONCE);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_ONCE);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+
+ s.setOccurence(MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 30);
+
+ s.setOccurence(MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERWEEK);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERWEEK);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ // Fortnightly no longer used: Every other week used instead
+ s.setOccurence(MyMoneySchedule::OCCUR_FORTNIGHTLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERWEEK);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 3);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYFOURWEEKS);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYFOURWEEKS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 4);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_WEEKLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 8);
+
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+
+ s.setOccurence(MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERMONTH);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERMONTH);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 3);
+ // Quarterly no longer used. Every three months used instead
+ s.setOccurence(MyMoneySchedule::OCCUR_QUARTERLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 3);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYFOURMONTHS);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYFOURMONTHS);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 4);
+ s.setOccurence(MyMoneySchedule::OCCUR_TWICEYEARLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_TWICEYEARLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 6);
+
+ s.setOccurence(MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 1);
+ s.setOccurence(MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+ CPPUNIT_ASSERT(s.occurence() == MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+ CPPUNIT_ASSERT(s.occurencePeriod() == MyMoneySchedule::OCCUR_YEARLY);
+ CPPUNIT_ASSERT(s.occurenceMultiplier() == 2);
+}
+
+void MyMoneyScheduleTest::testSimpleToFromCompoundOccurence()
+{
+ // Conversion between Simple and Compound occurences
+ // Each simple occurence to compound occurence
+ MyMoneySchedule::occurenceE occ;
+ int mult;
+ occ = MyMoneySchedule::OCCUR_ONCE; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_ONCE && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_DAILY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_DAILY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_WEEKLY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_EVERYOTHERWEEK; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 2 );
+ occ = MyMoneySchedule::OCCUR_FORTNIGHTLY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 2 );
+ occ = MyMoneySchedule::OCCUR_EVERYHALFMONTH; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYHALFMONTH && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_EVERYTHREEWEEKS; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 3 );
+ occ = MyMoneySchedule::OCCUR_EVERYFOURWEEKS; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 4 );
+ occ = MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_DAILY && mult == 30 );
+ occ = MyMoneySchedule::OCCUR_MONTHLY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 8 );
+ occ = MyMoneySchedule::OCCUR_EVERYOTHERMONTH; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 2 );
+ occ = MyMoneySchedule::OCCUR_EVERYTHREEMONTHS; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 3 );
+ occ = MyMoneySchedule::OCCUR_QUARTERLY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 3 );
+ occ = MyMoneySchedule::OCCUR_EVERYFOURMONTHS; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 4 );
+ occ = MyMoneySchedule::OCCUR_TWICEYEARLY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 6 );
+ occ = MyMoneySchedule::OCCUR_YEARLY; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_YEARLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_EVERYOTHERYEAR; mult = 1;
+ MyMoneySchedule::simpleToCompoundOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_YEARLY && mult == 2 );
+ // Compound to Simple Occurences
+ occ = MyMoneySchedule::OCCUR_ONCE; mult = 1;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_ONCE && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_DAILY; mult = 1;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_DAILY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_WEEKLY; mult = 1;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_WEEKLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_WEEKLY; mult = 2;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYOTHERWEEK && mult == 1 );
+ // MyMoneySchedule::OCCUR_FORTNIGHTLY not converted back
+ occ = MyMoneySchedule::OCCUR_EVERYHALFMONTH; mult = 1;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYHALFMONTH && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_WEEKLY; mult = 3;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_WEEKLY ; mult = 4;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYFOURWEEKS && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_DAILY; mult = 30;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_MONTHLY; mult = 1;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_MONTHLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_WEEKLY; mult = 8;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_MONTHLY; mult = 2;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYOTHERMONTH && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_MONTHLY; mult = 3;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS && mult == 1 );
+ // MyMoneySchedule::OCCUR_QUARTERLY not converted back
+ occ = MyMoneySchedule::OCCUR_MONTHLY; mult = 4;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYFOURMONTHS && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_MONTHLY; mult = 6;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_TWICEYEARLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_YEARLY; mult = 1;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_YEARLY && mult == 1 );
+ occ = MyMoneySchedule::OCCUR_YEARLY; mult = 2;
+ MyMoneySchedule::compoundToSimpleOccurence(mult, occ);
+ CPPUNIT_ASSERT( occ == MyMoneySchedule::OCCUR_EVERYOTHERYEAR && mult == 1 );
+}
+
+void MyMoneyScheduleTest::testPaidEarlyOneTime()
+{
+// this tries to figure out what's wrong with
+// https://bugs.kde.org/show_bug.cgi?id=231029
+
+ MyMoneySchedule sch;
+ QDate paymentInFuture = QDate::currentDate().addDays(7);
+
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SCHEDULE-CONTAINER>\n"
+ " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"0\" weekendOption=\"1\" lastPayment=\"%2\" paymentType=\"2\" endDate=\"%3\" type=\"4\" id=\"SCH0042\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"32\" >\n"
+ " <PAYMENTS/>\n"
+ " <TRANSACTION postdate=\"\" memo=\"\" id=\"\" commodity=\"GBP\" entrydate=\"\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Transfer\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" id=\"S0001\" account=\"A000076\" />\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"Transfer\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"-96379/100\" id=\"S0002\" account=\"A000276\" />\n"
+ " </SPLITS>\n"
+ " </TRANSACTION>\n"
+ " </SCHEDULED_TX>\n"
+ "</SCHEDULE-CONTAINER>\n"
+ ).arg(paymentInFuture.toString(Qt::ISODate))
+ .arg(paymentInFuture.toString(Qt::ISODate))
+ .arg(paymentInFuture.toString(Qt::ISODate));
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ sch = MyMoneySchedule(node);
+ CPPUNIT_ASSERT(sch.isFinished() == true);
+ CPPUNIT_ASSERT(sch.occurencePeriod() == MyMoneySchedule::OCCUR_MONTHLY);
+ CPPUNIT_ASSERT(sch.paymentDates(QDate::currentDate(), QDate::currentDate().addDays(21)).count() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+}
diff --git a/kmymoney2/mymoney/mymoneyscheduletest.h b/kmymoney2/mymoney/mymoneyscheduletest.h
new file mode 100644
index 0000000..ea2c929
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyscheduletest.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ mymoneyscheduletest.h
+ -------------------
+ copyright : (C) 2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYSCHEDULETEST_H__
+#define __MYMONEYSCHEDULETEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#define protected public
+#include "mymoneyscheduled.h"
+#include "mymoneyfile.h"
+#include "storage/mymoneyseqaccessmgr.h"
+#undef private
+
+class MyMoneyScheduleTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyScheduleTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testAssignmentConstructor);
+ // The following tests must be done in this order.
+ CPPUNIT_TEST(testSingleton);
+ CPPUNIT_TEST(testAddSchedule);
+ CPPUNIT_TEST(testAnyScheduled);
+ CPPUNIT_TEST(testOverdue);
+ CPPUNIT_TEST(testGetSchedule);
+ CPPUNIT_TEST(testGetScheduled);
+ CPPUNIT_TEST(testGetOverdue);
+ CPPUNIT_TEST(testNextPayment);
+ CPPUNIT_TEST(testPaymentDates);
+ CPPUNIT_TEST(testReplaceSchedule);
+ CPPUNIT_TEST(testRemoveSchedule);
+ CPPUNIT_TEST(testWriteXML);
+ CPPUNIT_TEST(testReadXML);
+ CPPUNIT_TEST(testHasReferenceTo);
+ CPPUNIT_TEST(testAdjustedNextDueDate);
+ CPPUNIT_TEST(testModifyNextDueDate);
+ CPPUNIT_TEST(testDaysBetweenEvents);
+ CPPUNIT_TEST(testEventsPerYear);
+ CPPUNIT_TEST(testAddHalfMonths);
+ CPPUNIT_TEST(testOccurenceToString);
+ CPPUNIT_TEST(testOccurencePeriodToString);
+ CPPUNIT_TEST(testStringToOccurence);
+ CPPUNIT_TEST(testOccurencePeriod);
+ CPPUNIT_TEST(testSimpleToFromCompoundOccurence);
+ CPPUNIT_TEST(testPaidEarlyOneTime);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+// MyMoneyFile *m_file;
+// MyMoneySeqAccessMgr* storage;
+ //TestObserverSet *observer;
+ //TestObserverSet *hierarchyObserver;
+
+public:
+ MyMoneyScheduleTest();
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testConstructor();
+ void testSetFunctions();
+ void testCopyConstructor();
+ void testAssignmentConstructor();
+ void testSingleton();
+ void testAddSchedule();
+ void testAnyScheduled();
+ void testOverdue();
+ void testGetSchedule();
+ void testGetScheduled();
+ void testGetOverdue();
+ void testNextPayment();
+ void testAddHalfMonths();
+ void testPaymentDates();
+ void testReplaceSchedule();
+ void testRemoveSchedule();
+ void testWriteXML();
+ void testReadXML();
+ void testHasReferenceTo();
+ void testAdjustedNextDueDate();
+ void testModifyNextDueDate();
+ void testDaysBetweenEvents();
+ void testEventsPerYear();
+ void testOccurenceToString();
+ void testOccurencePeriodToString();
+ void testStringToOccurence();
+ void testOccurencePeriod();
+ void testSimpleToFromCompoundOccurence();
+ void testPaidEarlyOneTime();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneysecurity.cpp b/kmymoney2/mymoney/mymoneysecurity.cpp
new file mode 100644
index 0000000..73edbdb
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysecurity.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+ mymoneysecurity.cpp - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneysecurity.h"
+#include "mymoneyexception.h"
+
+MyMoneySecurity::MyMoneySecurity() :
+ m_securityType(SECURITY_NONE),
+ m_smallestAccountFraction(100),
+ m_smallestCashFraction(100),
+ m_partsPerUnit(100)
+{
+}
+
+MyMoneySecurity::MyMoneySecurity(const QString& id, const QString& name, const QString& symbol, const int partsPerUnit, const int smallestCashFraction, const int smallestAccountFraction) :
+ MyMoneyObject(id),
+ m_name(name),
+ m_securityType(SECURITY_CURRENCY)
+{
+ if(symbol.isEmpty())
+ m_tradingSymbol = id;
+ else
+ m_tradingSymbol = symbol;
+
+ m_partsPerUnit = partsPerUnit;
+ m_smallestCashFraction = smallestCashFraction;
+ if(smallestAccountFraction)
+ m_smallestAccountFraction = smallestAccountFraction;
+ else
+ m_smallestAccountFraction = smallestCashFraction;
+}
+
+MyMoneySecurity::MyMoneySecurity(const QString& id, const MyMoneySecurity& equity) :
+ MyMoneyObject(id)
+{
+ *this = equity;
+ m_id = id;
+}
+
+MyMoneySecurity::MyMoneySecurity(const QDomElement& node) :
+ MyMoneyObject(node),
+ MyMoneyKeyValueContainer(node.elementsByTagName("KEYVALUEPAIRS").item(0).toElement())
+{
+ if(("SECURITY" != node.tagName())
+ && ("EQUITY" != node.tagName())
+ && ("CURRENCY" != node.tagName()))
+ throw new MYMONEYEXCEPTION("Node was not SECURITY or CURRENCY");
+
+ setName(QStringEmpty(node.attribute("name")));
+ setTradingSymbol(QStringEmpty(node.attribute("symbol")));
+ setSecurityType(static_cast<eSECURITYTYPE>(node.attribute("type").toInt()));
+ setSmallestAccountFraction(node.attribute("saf").toInt());
+
+ if(isCurrency()) {
+ setPartsPerUnit(node.attribute("ppu").toInt());
+ setSmallestCashFraction(node.attribute("scf").toInt());
+ } else {
+ setTradingCurrency(QStringEmpty(node.attribute("trading-currency")));
+ setTradingMarket(QStringEmpty(node.attribute("trading-market")));
+ }
+}
+
+MyMoneySecurity::~MyMoneySecurity()
+{
+}
+
+bool MyMoneySecurity::operator == (const MyMoneySecurity& r) const
+{
+ return (m_id == r.m_id)
+ && (m_name == r.m_name)
+ && (m_tradingSymbol == r.m_tradingSymbol)
+ && (m_tradingMarket == r.m_tradingMarket)
+ && (m_tradingSymbol == r.m_tradingSymbol)
+ && (m_tradingCurrency == r.m_tradingCurrency)
+ && (m_securityType == r.m_securityType)
+ && (m_smallestAccountFraction == r.m_smallestAccountFraction)
+ && (m_smallestCashFraction == r.m_smallestCashFraction)
+ && (m_partsPerUnit == r.m_partsPerUnit)
+ && this->MyMoneyKeyValueContainer::operator == (r);
+
+}
+
+bool MyMoneySecurity::operator < (const MyMoneySecurity& right) const
+{
+ if(m_securityType == right.m_securityType)
+ return m_name < right.m_name;
+ return m_securityType < right.m_securityType;
+}
+
+
+bool MyMoneySecurity::hasReferenceTo(const QString& id) const
+{
+ return (id == m_tradingCurrency);
+}
+
+void MyMoneySecurity::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el;
+ if(isCurrency())
+ el = document.createElement("CURRENCY");
+ else
+ el = document.createElement("SECURITY");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("name", m_name);
+ el.setAttribute("symbol", m_tradingSymbol);
+ el.setAttribute("type", static_cast<int>(m_securityType));
+ el.setAttribute("saf", m_smallestAccountFraction);
+ if(isCurrency()) {
+ el.setAttribute("ppu", m_partsPerUnit);
+ el.setAttribute("scf", m_smallestCashFraction);
+ } else {
+ el.setAttribute("trading-currency", m_tradingCurrency);
+ el.setAttribute("trading-market", m_tradingMarket);
+ }
+
+ //Add in Key-Value Pairs for securities.
+ MyMoneyKeyValueContainer::writeXML(document, el);
+
+ parent.appendChild(el);
+}
+
+QString MyMoneySecurity::securityTypeToString(const eSECURITYTYPE securityType)
+{
+ QString returnString;
+
+ switch (securityType) {
+ case MyMoneySecurity::SECURITY_STOCK:
+ returnString = I18N_NOOP("Stock");
+ break;
+ case MyMoneySecurity::SECURITY_MUTUALFUND:
+ returnString = I18N_NOOP("Mutual Fund");
+ break;
+ case MyMoneySecurity::SECURITY_BOND:
+ returnString = I18N_NOOP("Bond");
+ break;
+ case MyMoneySecurity::SECURITY_CURRENCY:
+ returnString = I18N_NOOP("Currency");
+ break;
+ case MyMoneySecurity::SECURITY_NONE:
+ returnString = I18N_NOOP("None");
+ break;
+ default:
+ returnString = I18N_NOOP("Unknown");
+ }
+
+ return returnString;
+}
+
diff --git a/kmymoney2/mymoney/mymoneysecurity.h b/kmymoney2/mymoney/mymoneysecurity.h
new file mode 100644
index 0000000..666398e
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysecurity.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ mymoneysecurity.h - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSECURITY_H
+#define MYMONEYSECURITY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+#include <qmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+
+/**
+ * Class that holds all the required information about a security that the user
+ * has entered information about. A security can be a stock, a mutual fund, a bond
+ * or a currency.
+ *
+ * @author Kevin Tambascio
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT MyMoneySecurity : public MyMoneyObject, public MyMoneyKeyValueContainer
+{
+public:
+ MyMoneySecurity();
+ MyMoneySecurity(const QString& id, const MyMoneySecurity& equity);
+ MyMoneySecurity(const QString& id, const QString& name, const QString& symbol = QString(), const int partsPerUnit = 100, const int smallestCashFraction = 100, const int smallestAccountFraction = 0);
+ MyMoneySecurity(const QDomElement& node);
+ virtual ~MyMoneySecurity();
+
+ bool operator < (const MyMoneySecurity&) const;
+
+ /**
+ * This operator tests for equality of two MyMoneySecurity objects
+ */
+ bool operator == (const MyMoneySecurity&) const;
+
+ /**
+ * This operator tests for inequality of this MyMoneySecurity object
+ * and the one passed by @p r
+ *
+ * @param r the right side of the comparison
+ */
+ bool operator != (const MyMoneySecurity& r) const { return !(*this == r); }
+
+public:
+ typedef enum {
+ SECURITY_STOCK,
+ SECURITY_MUTUALFUND,
+ SECURITY_BOND,
+ SECURITY_CURRENCY,
+ SECURITY_NONE
+ } eSECURITYTYPE;
+
+ const QString& name() const { return m_name; }
+ void setName(const String& str) { m_name = str; }
+
+ const QString& tradingSymbol() const { return m_tradingSymbol; }
+ void setTradingSymbol(const String& str) { m_tradingSymbol = str; }
+
+ eSECURITYTYPE securityType() const { return m_securityType; }
+ void setSecurityType(const eSECURITYTYPE& s) { m_securityType = s; }
+ bool isCurrency(void) const { return m_securityType == SECURITY_CURRENCY; };
+
+ const QString& tradingMarket() const { return m_tradingMarket; }
+ void setTradingMarket(const QString& str) { m_tradingMarket = str; }
+
+ const QString& tradingCurrency(void) const { return m_tradingCurrency; };
+ void setTradingCurrency(const QString& str) { m_tradingCurrency = str; };
+
+ int smallestAccountFraction(void) const { return m_smallestAccountFraction; };
+ void setSmallestAccountFraction(const int sf) { m_smallestAccountFraction = sf; };
+
+ int partsPerUnit(void) const { return m_partsPerUnit; };
+ int smallestCashFraction(void) const { return m_smallestCashFraction; };
+
+ void setPartsPerUnit(const int ppu) { m_partsPerUnit = ppu; };
+ void setSmallestCashFraction(const int sf) { m_smallestCashFraction = sf; };
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ bool hasReferenceTo(const QString& id) const;
+
+ /**
+ * This method is used to convert the internal representation of
+ * an security type into a human readable format
+ *
+ * @param securityType enumerated representation of the security type.
+ * For possible values, see MyMoneySecurity::eSECURITYTYPE
+ *
+ * @return QString representing the human readable form
+ */
+ static QString securityTypeToString(const MyMoneySecurity::eSECURITYTYPE securityType);
+
+
+protected:
+ QString m_name;
+ QString m_tradingSymbol;
+ QString m_tradingMarket;
+ QString m_tradingCurrency;
+ eSECURITYTYPE m_securityType;
+ int m_smallestAccountFraction;
+ int m_smallestCashFraction;
+ int m_partsPerUnit;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneysecuritytest.cpp b/kmymoney2/mymoney/mymoneysecuritytest.cpp
new file mode 100644
index 0000000..77b6764
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysecuritytest.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+ mymoneysecuritytest.cpp
+ -------------------
+ copyright : (C) 2002 by Kevin Tambascio
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneysecuritytest.h"
+
+MyMoneySecurityTest::MyMoneySecurityTest()
+{
+}
+
+
+void MyMoneySecurityTest::setUp () {
+ m = new MyMoneySecurity();
+}
+
+void MyMoneySecurityTest::tearDown () {
+ delete m;
+}
+
+void MyMoneySecurityTest::testEmptyConstructor() {
+ CPPUNIT_ASSERT(m->id().isEmpty());
+ CPPUNIT_ASSERT(m->name().isEmpty());
+ CPPUNIT_ASSERT(m->tradingSymbol().isEmpty());
+ CPPUNIT_ASSERT(m->securityType() == MyMoneySecurity::SECURITY_NONE);
+ CPPUNIT_ASSERT(m->tradingMarket().isEmpty());
+ CPPUNIT_ASSERT(m->tradingCurrency().isEmpty());
+ CPPUNIT_ASSERT(m->smallestCashFraction() == 100);
+ CPPUNIT_ASSERT(m->smallestAccountFraction() == 100);
+ CPPUNIT_ASSERT(m->partsPerUnit() == 100);
+}
+
+void MyMoneySecurityTest::testCopyConstructor() {
+ MyMoneySecurity* n1 = new MyMoneySecurity("GUID1", *m);
+ MyMoneySecurity n2(*n1);
+
+ // CPPUNIT_ASSERT(*n1 == n2);
+
+ delete n1;
+}
+
+void MyMoneySecurityTest::testNonemptyConstructor() {
+ QDate date(2004,4,1);
+ MyMoneyMoney val("1234/100");
+
+ m->setName("name");
+ m->setTradingSymbol("symbol");
+ m->setSecurityType(MyMoneySecurity::SECURITY_CURRENCY);
+ // m->addPriceHistory(date, val);
+
+ MyMoneySecurity n("id", *m);
+
+ CPPUNIT_ASSERT(n.id() == QString("id"));
+ CPPUNIT_ASSERT(n.tradingSymbol() == QString("symbol"));
+ CPPUNIT_ASSERT(n.securityType() == MyMoneySecurity::SECURITY_CURRENCY);
+ // CPPUNIT_ASSERT(n.priceHistory().count() == 1);
+}
+
+
+void MyMoneySecurityTest::testSetFunctions() {
+ m->setName("Name");
+ m->setTradingSymbol("Symbol");
+ m->setTradingMarket("Market");
+ m->setTradingCurrency("Currency");
+ m->setSecurityType(MyMoneySecurity::SECURITY_STOCK);
+ m->setSmallestAccountFraction(50);
+ m->setSmallestCashFraction(2);
+ m->setPartsPerUnit(30);
+
+ CPPUNIT_ASSERT(m->name() == "Name");
+ CPPUNIT_ASSERT(m->tradingSymbol() == "Symbol");
+ CPPUNIT_ASSERT(m->tradingMarket() == "Market");
+ CPPUNIT_ASSERT(m->tradingCurrency() == "Currency");
+ CPPUNIT_ASSERT(m->securityType() == MyMoneySecurity::SECURITY_STOCK);
+ CPPUNIT_ASSERT(m->smallestAccountFraction() == 50);
+ CPPUNIT_ASSERT(m->smallestCashFraction() == 2);
+ CPPUNIT_ASSERT(m->partsPerUnit() == 30);
+}
+
+/*
+void MyMoneySecurityTest::testMyMoneyFileConstructor() {
+ MyMoneySecurity *t = new MyMoneySecurity("GUID", *n);
+
+ CPPUNIT_ASSERT(t->id() == "GUID");
+
+ delete t;
+}
+*/
+
+void MyMoneySecurityTest::testEquality () {
+ testSetFunctions();
+ m->setValue("Key", "Value");
+
+ MyMoneySecurity n;
+ n = *m;
+
+ CPPUNIT_ASSERT(n == *m);
+ n.setName("NewName");
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setTradingSymbol("NewSymbol");
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setTradingMarket("NewMarket");
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setTradingCurrency("NewCurrency");
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setSecurityType(MyMoneySecurity::SECURITY_CURRENCY);
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setSmallestAccountFraction(40);
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setSmallestCashFraction(20);
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setPartsPerUnit(3);
+ CPPUNIT_ASSERT(!(n == *m));
+ n = *m;
+ n.setValue("Key", "NewValue");
+ CPPUNIT_ASSERT(!(n == *m));
+}
+
+void MyMoneySecurityTest::testInequality () {
+ testSetFunctions();
+ m->setValue("Key", "Value");
+
+ MyMoneySecurity n;
+ n = *m;
+
+ CPPUNIT_ASSERT(!(n != *m));
+ n.setName("NewName");
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setTradingSymbol("NewSymbol");
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setTradingMarket("NewMarket");
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setTradingCurrency("NewCurrency");
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setSecurityType(MyMoneySecurity::SECURITY_CURRENCY);
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setSmallestAccountFraction(40);
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setSmallestCashFraction(20);
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setPartsPerUnit(3);
+ CPPUNIT_ASSERT(n != *m);
+ n = *m;
+ n.setValue("Key", "NewValue");
+ CPPUNIT_ASSERT(n != *m);
+}
+
+/*
+void MyMoneySecurityTest::testAccountIDList () {
+ MyMoneySecurity equity;
+ QStringList list;
+ QString id;
+
+ // list must be empty
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 0);
+
+ // add one account
+ institution.addAccountId("A000002");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+
+ // adding same account shouldn't make a difference
+ institution.addAccountId("A000002");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+
+ // now add another account
+ institution.addAccountId("A000001");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+ CPPUNIT_ASSERT(list.contains("A000001") == 1);
+
+ id = institution.removeAccountId("A000001");
+ CPPUNIT_ASSERT(id == "A000001");
+ list = institution.accountList();
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list.contains("A000002") == 1);
+
+}
+*/
+
diff --git a/kmymoney2/mymoney/mymoneysecuritytest.h b/kmymoney2/mymoney/mymoneysecuritytest.h
new file mode 100644
index 0000000..39d0cd4
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysecuritytest.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ mymoneysecuritytest.h
+ -------------------
+ copyright : (C) 2004 by Kevin Tambascio
+ email : ktambascio@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYSECURITYTEST_H__
+#define __MYMONEYSECURITYTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#include "mymoneysecurity.h"
+#undef private
+
+class MyMoneySecurityTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneySecurityTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testNonemptyConstructor);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST(testInequality);
+/*
+ CPPUNIT_TEST(testMyMoneyFileConstructor);
+ CPPUNIT_TEST(testAccountIDList);
+*/
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneySecurity *m;
+
+public:
+ MyMoneySecurityTest();
+
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testNonemptyConstructor();
+ void testCopyConstructor();
+ void testSetFunctions();
+ void testEquality ();
+ void testInequality ();
+ // void testMyMoneyFileConstructor();
+ // void testAccountIDList ();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneysplit.cpp b/kmymoney2/mymoney/mymoneysplit.cpp
new file mode 100644
index 0000000..a19ff43
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysplit.cpp
@@ -0,0 +1,272 @@
+/***************************************************************************
+ mymoneysplit.cpp - description
+ -------------------
+ begin : Sun Apr 28 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneysplit.h"
+#include "mymoneytransaction.h"
+
+const char MyMoneySplit::ActionCheck[] = "Check";
+const char MyMoneySplit::ActionDeposit[] = "Deposit";
+const char MyMoneySplit::ActionTransfer[] = "Transfer";
+const char MyMoneySplit::ActionWithdrawal[] = "Withdrawal";
+const char MyMoneySplit::ActionATM[] = "ATM";
+
+const char MyMoneySplit::ActionAmortization[] = "Amortization";
+const char MyMoneySplit::ActionInterest[] = "Interest";
+
+const char MyMoneySplit::ActionBuyShares[] = "Buy";
+const char MyMoneySplit::ActionDividend[] = "Dividend";
+const char MyMoneySplit::ActionReinvestDividend[] = "Reinvest";
+const char MyMoneySplit::ActionYield[] = "Yield";
+const char MyMoneySplit::ActionAddShares[] = "Add";
+const char MyMoneySplit::ActionSplitShares[] = "Split";
+
+MyMoneySplit::MyMoneySplit()
+{
+ m_reconcileFlag = NotReconciled;
+}
+
+MyMoneySplit::MyMoneySplit(const QDomElement& node) :
+ MyMoneyObject(node, false),
+ MyMoneyKeyValueContainer(node.elementsByTagName("KEYVALUEPAIRS").item(0).toElement())
+{
+ if("SPLIT" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not SPLIT");
+
+ clearId();
+
+ m_payee = QStringEmpty(node.attribute("payee"));
+ m_reconcileDate = stringToDate(QStringEmpty(node.attribute("reconciledate")));
+ m_action = QStringEmpty(node.attribute("action"));
+ m_reconcileFlag = static_cast<MyMoneySplit::reconcileFlagE>(node.attribute("reconcileflag").toInt());
+ m_memo = QStringEmpty(node.attribute("memo"));
+ m_value = MyMoneyMoney(QStringEmpty(node.attribute("value")));
+ m_shares = MyMoneyMoney(QStringEmpty(node.attribute("shares")));
+ m_price = MyMoneyMoney(QStringEmpty(node.attribute("price")));
+ m_account = QStringEmpty(node.attribute("account"));
+ m_number = QStringEmpty(node.attribute("number"));
+ m_bankID = QStringEmpty(node.attribute("bankid"));
+}
+
+MyMoneySplit::MyMoneySplit(const QString& id, const MyMoneySplit& right) :
+ MyMoneyObject(id)
+{
+ *this = right;
+ setId(id);
+}
+
+MyMoneySplit::~MyMoneySplit()
+{
+}
+
+bool MyMoneySplit::operator == (const MyMoneySplit& right) const
+{
+ return MyMoneyObject::operator==(right) &&
+ MyMoneyKeyValueContainer::operator==(right) &&
+ m_account == right.m_account &&
+ m_payee == right.m_payee &&
+ m_memo == right.m_memo &&
+ m_action == right.m_action &&
+ m_reconcileDate == right.m_reconcileDate &&
+ m_reconcileFlag == right.m_reconcileFlag &&
+ ((m_number.length() == 0 && right.m_number.length() == 0) || m_number == right.m_number) &&
+ m_shares == right.m_shares &&
+ m_value == right.m_value &&
+ m_price == right.m_price &&
+ m_transactionId == right.m_transactionId;
+}
+
+void MyMoneySplit::setAccountId(const QString& account)
+{
+ m_account = account;
+}
+
+void MyMoneySplit::setMemo(const QString& memo)
+{
+ m_memo = memo;
+}
+
+void MyMoneySplit::setReconcileDate(const QDate& date)
+{
+ m_reconcileDate = date;
+}
+
+void MyMoneySplit::setReconcileFlag(const reconcileFlagE flag)
+{
+ m_reconcileFlag = flag;
+}
+
+void MyMoneySplit::setShares(const MyMoneyMoney& shares)
+{
+ m_shares = shares;
+}
+
+void MyMoneySplit::setValue(const MyMoneyMoney& value)
+{
+ m_value = value;
+}
+
+void MyMoneySplit::setValue(const MyMoneyMoney& value, const QString& transactionCurrencyId, const QString& splitCurrencyId)
+{
+ if(transactionCurrencyId == splitCurrencyId)
+ setValue(value);
+ else
+ setShares(value);
+}
+
+void MyMoneySplit::setPayeeId(const QString& payee)
+{
+ m_payee = payee;
+}
+
+void MyMoneySplit::setAction(investTransactionTypeE type)
+{
+ switch(type) {
+ case BuyShares:
+ case SellShares:
+ setAction(ActionBuyShares);
+ break;
+ case Dividend:
+ setAction(ActionDividend);
+ break;
+ case Yield:
+ setAction(ActionYield);
+ break;
+ case ReinvestDividend:
+ setAction(ActionReinvestDividend);
+ break;
+ case AddShares:
+ case RemoveShares:
+ setAction(ActionAddShares);
+ break;
+ case MyMoneySplit::SplitShares:
+ setAction(ActionSplitShares);
+ break;
+ case MyMoneySplit::UnknownTransactionType:
+ break;
+ }
+}
+
+void MyMoneySplit::setAction(const QString& action)
+{
+ m_action = action;
+}
+
+void MyMoneySplit::setNumber(const QString& number)
+{
+ m_number = number;
+}
+
+const MyMoneyMoney MyMoneySplit::value(const QString& transactionCurrencyId, const QString& splitCurrencyId) const
+{
+ return (transactionCurrencyId == splitCurrencyId) ? m_value : m_shares;
+}
+
+void MyMoneySplit::setPrice(const MyMoneyMoney& price)
+{
+ m_price = price;
+}
+
+MyMoneyMoney MyMoneySplit::price(void) const
+{
+ if(!m_price.isZero())
+ return m_price;
+ if(!m_value.isZero() && !m_shares.isZero())
+ return m_value / m_shares;
+ return MyMoneyMoney(1,1);
+}
+
+void MyMoneySplit::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("SPLIT");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("payee", m_payee);
+ el.setAttribute("reconciledate", dateToString(m_reconcileDate));
+ el.setAttribute("action", m_action);
+ el.setAttribute("reconcileflag", m_reconcileFlag);
+ el.setAttribute("value", m_value.toString());
+ el.setAttribute("shares", m_shares.toString());
+ if(!m_price.isZero())
+ el.setAttribute("price", m_price.toString());
+ el.setAttribute("memo", m_memo);
+ // No need to write the split id as it will be re-assigned when the file is read
+ // el.setAttribute("id", split.id());
+ el.setAttribute("account", m_account);
+ el.setAttribute("number", m_number);
+ el.setAttribute("bankid", m_bankID);
+
+ MyMoneyKeyValueContainer::writeXML(document, el);
+
+ parent.appendChild(el);
+}
+
+bool MyMoneySplit::hasReferenceTo(const QString& id) const
+{
+ bool rc = false;
+ if(isMatched()) {
+ rc = matchedTransaction().hasReferenceTo(id);
+ }
+ return rc || (id == m_account) || (id == m_payee);
+}
+
+bool MyMoneySplit::isMatched(void) const
+{
+ return !(value("kmm-matched-tx").isEmpty());
+}
+
+void MyMoneySplit::addMatch(const MyMoneyTransaction& _t)
+{
+ if(_t.isImported() && !isMatched()) {
+ MyMoneyTransaction t(_t);
+ t.clearId();
+ QDomDocument doc("MATCH");
+ QDomElement el = doc.createElement("CONTAINER");
+ doc.appendChild(el);
+ t.writeXML(doc, el);
+ QString xml = doc.toString();
+ xml.replace("<", "&lt;");
+ setValue("kmm-matched-tx", xml);
+ }
+}
+
+void MyMoneySplit::removeMatch(void)
+{
+ deletePair("kmm-matched-tx");
+}
+
+MyMoneyTransaction MyMoneySplit::matchedTransaction(void) const
+{
+ QString xml = value("kmm-matched-tx");
+ if(!xml.isEmpty()) {
+ xml.replace("&lt;", "<");
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(xml);
+ node = doc.documentElement().firstChild().toElement();
+ MyMoneyTransaction t(node, false);
+ return t;
+ }
+ return MyMoneyTransaction();
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneysplit.h b/kmymoney2/mymoney/mymoneysplit.h
new file mode 100644
index 0000000..3408a6a
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysplit.h
@@ -0,0 +1,307 @@
+/***************************************************************************
+ mymoneysplit.h - description
+ -------------------
+ begin : Sun Apr 28 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSPLIT_H
+#define MYMONEYSPLIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyexception.h"
+#include "mymoneyutils.h"
+#include "mymoneymoney.h"
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+class MyMoneyTransaction;
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents a split of a transaction.
+ */
+class KMYMONEY_EXPORT MyMoneySplit : public MyMoneyObject, public MyMoneyKeyValueContainer
+{
+public:
+ /**
+ * This enum defines the possible reconciliation states a split
+ * can be in. Possible values are as follows:
+ *
+ * @li NotReconciled
+ * @li Cleared
+ * @li Reconciled
+ * @li Frozen
+ *
+ * Whenever a new split is created, it has the status NotReconciled. It
+ * can be set to cleared when the transaction has been performed. Once the
+ * account is reconciled, cleared splits will be set to Reconciled. The
+ * state Frozen will be used, when the concept of books is introduced into
+ * the engine and a split must not be changed anymore.
+ */
+ enum reconcileFlagE {
+ Unknown = -1,
+ NotReconciled = 0,
+ Cleared,
+ Reconciled,
+ Frozen,
+ // insert new values above
+ MaxReconcileState
+ };
+
+ typedef enum {
+ UnknownTransactionType = -1,
+ BuyShares = 0,
+ SellShares,
+ Dividend,
+ ReinvestDividend,
+ Yield,
+ AddShares,
+ RemoveShares,
+ SplitShares
+ } investTransactionTypeE;
+
+ MyMoneySplit();
+ MyMoneySplit(const QDomElement& node);
+ MyMoneySplit(const QString& id, const MyMoneySplit& right);
+ ~MyMoneySplit();
+
+ bool operator == (const MyMoneySplit&) const;
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ const MyMoneyMoney& shares(void) const { return m_shares; }
+ const MyMoneyMoney& value(void) const { return m_value; }
+
+ /**
+ * This method returns the price. If the member m_price is not zero
+ * its value is returned. Otherwise, if m_shares is not zero the quotient
+ * of m_value / m_shares is returned. If m_values equals to zero, 1
+ * will be returned.
+ */
+ MyMoneyMoney price(void) const;
+ /** This method just returns what is in m_price, so when we write to the
+ * database, we don't just generate prices
+ */
+ MyMoneyMoney actualPrice(void) const { return m_price; }
+
+ const MyMoneyMoney value(const QString& transactionCurrencyId, const QString& splitCurrencyId) const;
+
+ /**
+ * Required to have (direct) access to the MyMoneyKeyValueContainer::value() method.
+ */
+ const QString& value(const QString& key) const { return MyMoneyKeyValueContainer::value(key); }
+
+ /**
+ * Required to have (direct) access to the MyMoneyKeyValueContainer::setValue() method.
+ */
+ void setValue(const QString& key, const QString& value) { MyMoneyKeyValueContainer::setValue(key, value); }
+
+ const QString& accountId(void) const { return m_account; }
+ const QString& memo(void) const { return m_memo; }
+ reconcileFlagE reconcileFlag(void) const { return m_reconcileFlag; }
+ const QDate& reconcileDate(void) const { return m_reconcileDate; }
+ const QString& payeeId(void) const { return m_payee; }
+ const QString& action(void) const { return m_action; }
+ const QString& number(void) const { return m_number; }
+ bool isAmortizationSplit(void) const { return m_action == ActionAmortization; }
+ bool isInterestSplit(void) const { return m_action == ActionInterest; }
+ bool isAutoCalc(void) const { return (m_shares == MyMoneyMoney::autoCalc) || (m_value == MyMoneyMoney::autoCalc); }
+ const QString& bankID(void) const { return m_bankID; }
+ const QString& transactionId(void) const { return m_transactionId; }
+
+ void setShares(const MyMoneyMoney& shares);
+ void setValue(const MyMoneyMoney& value);
+ void setPrice(const MyMoneyMoney& price);
+
+ /**
+ * This method is used to set either the shares or the value depending on
+ * the currencies assigned to the split/account and the transaction.
+ *
+ * If @p transactionCurrencyId equals @p splitCurrencyId this method
+ * calls setValue(MyMoneyMoney) otherwise setShares(MyMoneyMoney).
+ *
+ * @param value the value to be assiged
+ * @param transactionCurrencyId the id of the currency assigned to the transaction
+ * @param splitCurrencyId the id of the currency assigned to the split (i.e. the
+ * the id of the currency assigned to the account that is
+ * referenced by the split)
+ */
+ void setValue(const MyMoneyMoney& value, const QString& transactionCurrencyId, const QString& splitCurrencyId);
+
+ void setAccountId(const QString& account);
+ void setMemo(const QString& memo);
+ void setReconcileFlag(const reconcileFlagE flag);
+ void setReconcileDate(const QDate& date);
+ void setPayeeId(const QString& payee);
+ void setAction(const QString& action);
+ void setAction(investTransactionTypeE type);
+ void setNumber(const QString& number);
+ void setBankID(const QString& bankID) { m_bankID = bankID; };
+ void setTransactionId(const QString& id) { m_transactionId = id; }
+
+ /**
+ * returns @a true if this its a transaction matched against an imported
+ * transaction. The imported and matched transaction can be extracted
+ * using matchedTransaction() and can be removed using removeMatch().
+ */
+ bool isMatched(void) const;
+
+ /**
+ * add an imported transaction @p t as matching transaction. Any previously
+ * added transaction will be overridden. @p t.isImported() must return true,
+ * otherwise the transaction is not stored.
+ */
+ void addMatch(const MyMoneyTransaction& t);
+
+ /**
+ * remove the data of the imported transaction added with addMatch().
+ */
+ void removeMatch(void);
+
+ /**
+ * Return the matching imported transaction. If no such transaction
+ * is available (isMatched() returns false) an empty transaction is returned.
+ */
+ MyMoneyTransaction matchedTransaction(void) const;
+
+ static const char ActionCheck[];
+ static const char ActionDeposit[];
+ static const char ActionTransfer[];
+ static const char ActionWithdrawal[];
+ static const char ActionATM[];
+
+ static const char ActionAmortization[];
+ static const char ActionInterest[];
+
+ static const char ActionBuyShares[]; // negative amount is sellShares
+ static const char ActionDividend[];
+ static const char ActionReinvestDividend[];
+ static const char ActionYield[];
+ static const char ActionAddShares[]; // negative amount is removeShares
+ static const char ActionSplitShares[];
+
+private:
+ /**
+ * This member contains the ID of the transaction
+ */
+ QString m_id;
+
+ /**
+ * This member contains the ID of the payee
+ */
+ QString m_payee;
+
+ /**
+ * This member contains the ID of the account
+ */
+ QString m_account;
+
+ /**
+ */
+ MyMoneyMoney m_shares;
+
+ /**
+ */
+ MyMoneyMoney m_value;
+
+
+ /**
+ * If the quotient of m_shares divided by m_values is not the correct price
+ * because of truncation, the price can be stored in this member. For display
+ * purpose and transaction edit this value can be used by the application.
+ */
+ MyMoneyMoney m_price;
+
+ QString m_memo;
+
+ /**
+ * This member contains information about the reconciliation
+ * state of the split. Possible values are
+ *
+ * @li NotReconciled
+ * @li Cleared
+ * @li Reconciled
+ * @li Frozen
+ *
+ */
+ reconcileFlagE m_reconcileFlag;
+
+ /**
+ * In case the reconciliation flag is set to Reconciled or Frozen
+ * this member contains the date of the reconciliation.
+ */
+ QDate m_reconcileDate;
+
+ /**
+ * The m_action member is an arbitrary string, but is intended to
+ * be conveniently limited to a menu of selections such as
+ * "Buy", "Sell", "Interest", etc.
+ */
+ QString m_action;
+
+ /**
+ * The m_number member is used to store a reference number to
+ * the split supplied by the user (e.g. check number, etc.).
+ */
+ QString m_number;
+
+ /**
+ * This member keeps the bank's unique ID for the split, so we can
+ * avoid duplicates. This is only used for electronic statement downloads.
+ *
+ * This should only be set on the split which refers to the account
+ * that was downloaded.
+ */
+ QString m_bankID;
+
+ /**
+ * This member keeps a backward id to the transaction that this
+ * split can be found in. It is the purpose of the MyMoneyTransaction
+ * object to maintain this member variable.
+ */
+ QString m_transactionId;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneysplittest.cpp b/kmymoney2/mymoney/mymoneysplittest.cpp
new file mode 100644
index 0000000..a592e1a
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysplittest.cpp
@@ -0,0 +1,306 @@
+/***************************************************************************
+ mymoneysplittest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneysplittest.h"
+#include <kmymoney/mymoneyexception.h>
+
+MyMoneySplitTest::MyMoneySplitTest()
+{
+}
+
+
+void MyMoneySplitTest::setUp () {
+ m = new MyMoneySplit();
+}
+
+void MyMoneySplitTest::tearDown () {
+ delete m;
+}
+
+void MyMoneySplitTest::testEmptyConstructor() {
+ CPPUNIT_ASSERT(m->accountId().isEmpty());
+ CPPUNIT_ASSERT(m->id().isEmpty());
+ CPPUNIT_ASSERT(m->memo().isEmpty());
+ CPPUNIT_ASSERT(m->action().isEmpty());
+ CPPUNIT_ASSERT(m->shares().isZero());
+ CPPUNIT_ASSERT(m->value().isZero());
+ CPPUNIT_ASSERT(m->reconcileFlag() == MyMoneySplit::NotReconciled);
+ CPPUNIT_ASSERT(m->reconcileDate() == QDate());
+ CPPUNIT_ASSERT(m->transactionId().isEmpty());
+}
+
+void MyMoneySplitTest::testSetFunctions() {
+ m->setAccountId("Account");
+ m->setMemo("Memo");
+ m->setReconcileDate(QDate(1,2,3));
+ m->setReconcileFlag(MyMoneySplit::Cleared);
+ m->setShares(1234);
+ m->setValue(3456);
+ m->setId("MyID");
+ m->setPayeeId("Payee");
+ m->setAction("Action");
+ m->setTransactionId("TestTransaction");
+ m->setValue("Key", "Value");
+
+ CPPUNIT_ASSERT(m->accountId() == "Account");
+ CPPUNIT_ASSERT(m->memo() == "Memo");
+ CPPUNIT_ASSERT(m->reconcileDate() == QDate(1,2,3));
+ CPPUNIT_ASSERT(m->reconcileFlag() == MyMoneySplit::Cleared);
+ CPPUNIT_ASSERT(m->shares() == MyMoneyMoney(1234));
+ CPPUNIT_ASSERT(m->value() == MyMoneyMoney(3456));
+ CPPUNIT_ASSERT(m->id() == "MyID");
+ CPPUNIT_ASSERT(m->payeeId() == "Payee");
+ CPPUNIT_ASSERT(m->action() == "Action");
+ CPPUNIT_ASSERT(m->transactionId() == "TestTransaction");
+ CPPUNIT_ASSERT(m->value("Key") == "Value");
+}
+
+
+void MyMoneySplitTest::testCopyConstructor() {
+ testSetFunctions();
+
+ MyMoneySplit n(*m);
+
+ CPPUNIT_ASSERT(n.accountId() == "Account");
+ CPPUNIT_ASSERT(n.memo() == "Memo");
+ CPPUNIT_ASSERT(n.reconcileDate() == QDate(1,2,3));
+ CPPUNIT_ASSERT(n.reconcileFlag() == MyMoneySplit::Cleared);
+ CPPUNIT_ASSERT(n.shares() == MyMoneyMoney(1234));
+ CPPUNIT_ASSERT(n.value() == MyMoneyMoney(3456));
+ CPPUNIT_ASSERT(n.id() == "MyID");
+ CPPUNIT_ASSERT(n.payeeId() == "Payee");
+ CPPUNIT_ASSERT(n.action() == "Action");
+ CPPUNIT_ASSERT(n.transactionId() == "TestTransaction");
+ CPPUNIT_ASSERT(n.value("Key") == "Value");
+}
+
+void MyMoneySplitTest::testAssignmentConstructor() {
+ testSetFunctions();
+
+ MyMoneySplit n;
+
+ n = *m;
+
+ CPPUNIT_ASSERT(n.accountId() == "Account");
+ CPPUNIT_ASSERT(n.memo() == "Memo");
+ CPPUNIT_ASSERT(n.reconcileDate() == QDate(1,2,3));
+ CPPUNIT_ASSERT(n.reconcileFlag() == MyMoneySplit::Cleared);
+ CPPUNIT_ASSERT(n.shares() == MyMoneyMoney(1234));
+ CPPUNIT_ASSERT(n.value() == MyMoneyMoney(3456));
+ CPPUNIT_ASSERT(n.id() == "MyID");
+ CPPUNIT_ASSERT(n.payeeId() == "Payee");
+ CPPUNIT_ASSERT(n.action() == "Action");
+ CPPUNIT_ASSERT(n.transactionId() == "TestTransaction");
+ CPPUNIT_ASSERT(n.value("Key") == "Value");
+}
+
+void MyMoneySplitTest::testEquality() {
+ testSetFunctions();
+
+ MyMoneySplit n(*m);
+
+ CPPUNIT_ASSERT(n == *m);
+}
+
+void MyMoneySplitTest::testInequality() {
+ testSetFunctions();
+
+ MyMoneySplit n(*m);
+
+ n.setShares(3456);
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setId("Not My ID");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setPayeeId("No payee");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setAction("No action");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setNumber("No number");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setAccountId("No account");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setMemo("No memo");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setReconcileDate(QDate(3,4,5));
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setReconcileFlag(MyMoneySplit::Frozen);
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setShares(4567);
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setValue(9876);
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setTransactionId("NoTransaction");
+ CPPUNIT_ASSERT(!(n == *m));
+
+ n = *m;
+ n.setValue("Key", "NoValue");
+ CPPUNIT_ASSERT(!(n == *m));
+}
+
+
+void MyMoneySplitTest::testAmortization() {
+ CPPUNIT_ASSERT(m->isAmortizationSplit() == false);
+ testSetFunctions();
+ CPPUNIT_ASSERT(m->isAmortizationSplit() == false);
+ m->setAction(MyMoneySplit::ActionAmortization);
+ CPPUNIT_ASSERT(m->isAmortizationSplit() == true);
+}
+
+void MyMoneySplitTest::testValue() {
+ m->setValue(1);
+ m->setShares(2);
+ CPPUNIT_ASSERT(m->value("EUR", "EUR") == MyMoneyMoney(1));
+ CPPUNIT_ASSERT(m->value("EUR", "USD") == MyMoneyMoney(2));
+}
+
+void MyMoneySplitTest::testSetValue() {
+ CPPUNIT_ASSERT(m->value().isZero());
+ CPPUNIT_ASSERT(m->shares().isZero());
+ m->setValue(1, "EUR", "EUR");
+ CPPUNIT_ASSERT(m->value() == MyMoneyMoney(1));
+ CPPUNIT_ASSERT(m->shares().isZero());
+ m->setValue(3, "EUR", "USD");
+ CPPUNIT_ASSERT(m->value() == MyMoneyMoney(1));
+ CPPUNIT_ASSERT(m->shares() == MyMoneyMoney(3));
+}
+
+void MyMoneySplitTest::testSetAction() {
+ CPPUNIT_ASSERT(m->action() == QString());
+ m->setAction(MyMoneySplit::BuyShares);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionBuyShares);
+ m->setAction(MyMoneySplit::SellShares);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionBuyShares);
+ m->setAction(MyMoneySplit::Dividend);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionDividend);
+ m->setAction(MyMoneySplit::Yield);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionYield);
+ m->setAction(MyMoneySplit::ReinvestDividend);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionReinvestDividend);
+ m->setAction(MyMoneySplit::AddShares);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionAddShares);
+ m->setAction(MyMoneySplit::RemoveShares);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionAddShares);
+ m->setAction(MyMoneySplit::SplitShares);
+ CPPUNIT_ASSERT(m->action() == MyMoneySplit::ActionSplitShares);
+}
+
+void MyMoneySplitTest::testIsAutoCalc() {
+ CPPUNIT_ASSERT(m->isAutoCalc() == false);
+ m->setValue(MyMoneyMoney::autoCalc);
+ CPPUNIT_ASSERT(m->isAutoCalc() == true);
+ m->setShares(MyMoneyMoney::autoCalc);
+ CPPUNIT_ASSERT(m->isAutoCalc() == true);
+ m->setValue(0);
+ CPPUNIT_ASSERT(m->isAutoCalc() == true);
+ m->setShares(1);
+ CPPUNIT_ASSERT(m->isAutoCalc() == false);
+}
+
+void MyMoneySplitTest::testWriteXML() {
+ MyMoneySplit s;
+
+ s.setPayeeId("P000001");
+ s.setShares(MyMoneyMoney(96379, 100));
+ s.setValue(MyMoneyMoney(96379, 1000));
+ s.setAccountId("A000076");
+ s.setNumber("124");
+ s.setBankID("SPID");
+ s.setAction(MyMoneySplit::ActionDeposit);
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+
+ QDomDocument doc("TEST");
+ QDomElement el = doc.createElement("SPLIT-CONTAINER");
+ doc.appendChild(el);
+ s.writeXML(doc, el);
+
+ QString ref = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SPLIT-CONTAINER>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Deposit\" bankid=\"SPID\" number=\"124\" reconcileflag=\"2\" memo=\"\" value=\"96379/1000\" id=\"\" account=\"A000076\" />\n"
+ "</SPLIT-CONTAINER>\n");
+
+ CPPUNIT_ASSERT(doc.toString() == ref);
+}
+
+void MyMoneySplitTest::testReadXML() {
+ MyMoneySplit s;
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SPLIT-CONTAINER>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Deposit\" bankid=\"SPID\" number=\"124\" reconcileflag=\"2\" memo=\"MyMemo\" value=\"96379/1000\" account=\"A000076\" />\n"
+ "</SPLIT-CONTAINER>\n");
+
+ QString ref_false = QString(
+ "<!DOCTYPE TEST>\n"
+ "<SPLIT-CONTAINER>\n"
+ " <SPLITS payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Deposit\" bankid=\"SPID\" number=\"124\" reconcileflag=\"2\" memo=\"\" value=\"96379/1000\" account=\"A000076\" />\n"
+ "</SPLIT-CONTAINER>\n");
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_false);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ s = MyMoneySplit(node);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ s = MyMoneySplit(node);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ CPPUNIT_ASSERT(s.payeeId() == "P000001");
+ CPPUNIT_ASSERT(s.reconcileDate() == QDate());
+ CPPUNIT_ASSERT(s.shares() == MyMoneyMoney(96379, 100));
+ CPPUNIT_ASSERT(s.value() == MyMoneyMoney(96379, 1000));
+ CPPUNIT_ASSERT(s.number() == "124");
+ CPPUNIT_ASSERT(s.bankID() == "SPID");
+ CPPUNIT_ASSERT(s.reconcileFlag() == MyMoneySplit::Reconciled);
+ CPPUNIT_ASSERT(s.action() == MyMoneySplit::ActionDeposit);
+ CPPUNIT_ASSERT(s.accountId() == "A000076");
+ CPPUNIT_ASSERT(s.memo() == "MyMemo");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+}
diff --git a/kmymoney2/mymoney/mymoneysplittest.h b/kmymoney2/mymoney/mymoneysplittest.h
new file mode 100644
index 0000000..d54e11e
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysplittest.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ mymoneysplittest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYSPLITTEST_H__
+#define __MYMONEYSPLITTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#define private public
+#define protected public
+#include "mymoneysplit.h"
+#undef private
+
+class MyMoneySplitTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneySplitTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testAssignmentConstructor);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST(testInequality);
+ CPPUNIT_TEST(testAmortization);
+ CPPUNIT_TEST(testValue);
+ CPPUNIT_TEST(testSetValue);
+ CPPUNIT_TEST(testSetAction);
+ CPPUNIT_TEST(testIsAutoCalc);
+ CPPUNIT_TEST(testWriteXML);
+ CPPUNIT_TEST(testReadXML);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneySplit *m;
+
+public:
+ MyMoneySplitTest ();
+
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testSetFunctions();
+ void testCopyConstructor();
+ void testAssignmentConstructor();
+ void testEquality();
+ void testInequality();
+ void testAmortization();
+ void testValue();
+ void testSetValue();
+ void testSetAction();
+ void testIsAutoCalc();
+ void testWriteXML();
+ void testReadXML();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneystatement.cpp b/kmymoney2/mymoney/mymoneystatement.cpp
new file mode 100644
index 0000000..0373863
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneystatement.cpp
@@ -0,0 +1,299 @@
+/***************************************************************************
+ mymoneystatement.cpp
+ -------------------
+ begin : Mon Aug 30 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdom.h>
+#include <qstringlist.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../../kdecompat.h"
+#include "mymoneystatement.h"
+
+const QStringList kAccountTypeTxt = QStringList::split(",","none,checkings,savings,investment,creditcard,invalid");
+const QStringList kActionText = QStringList::split(",","none,buy,sell,reinvestdividend,cashdividend,add,remove,stocksplit,fees,interest,invalid");
+
+void MyMoneyStatement::write(QDomElement& _root,QDomDocument* _doc) const
+{
+ QDomElement e = _doc->createElement("STATEMENT");
+ _root.appendChild(e);
+
+ e.setAttribute("version","1.1");
+ e.setAttribute("accountname", m_strAccountName);
+ e.setAttribute("accountnumber", m_strAccountNumber);
+ e.setAttribute("routingnumber", m_strRoutingNumber);
+ e.setAttribute("currency", m_strCurrency);
+ e.setAttribute("begindate", m_dateBegin.toString(Qt::ISODate));
+ e.setAttribute("enddate", m_dateEnd.toString(Qt::ISODate));
+ e.setAttribute("closingbalance", m_closingBalance.toString());
+ e.setAttribute("type", kAccountTypeTxt[m_eType]);
+ e.setAttribute("accountid", m_accountId);
+ e.setAttribute("skipCategoryMatching", m_skipCategoryMatching);
+
+ // iterate over transactions, and add each one
+ QValueList<Transaction>::const_iterator it_t = m_listTransactions.begin();
+ while ( it_t != m_listTransactions.end() )
+ {
+ QDomElement p = _doc->createElement("TRANSACTION");
+ p.setAttribute("dateposted", (*it_t).m_datePosted.toString(Qt::ISODate));
+ p.setAttribute("payee", (*it_t).m_strPayee);
+ p.setAttribute("memo", (*it_t).m_strMemo);
+ p.setAttribute("number", (*it_t).m_strNumber);
+ p.setAttribute("amount", (*it_t).m_amount.toString());
+ p.setAttribute("bankid", (*it_t).m_strBankID);
+ p.setAttribute("reconcile", (*it_t).m_reconcile);
+ p.setAttribute("action", kActionText[(*it_t).m_eAction]);
+
+ if (m_eType == etInvestment)
+ {
+ p.setAttribute("shares", (*it_t).m_shares.toString());
+ p.setAttribute("security", (*it_t).m_strSecurity);
+ p.setAttribute("brokerageaccount", (*it_t).m_strBrokerageAccount);
+ }
+
+ // add all the splits we know of (might be empty)
+ QValueList<Split>::const_iterator it_s;
+ for(it_s = (*it_t).m_listSplits.begin(); it_s != (*it_t).m_listSplits.end(); ++it_s) {
+ QDomElement split = _doc->createElement("SPLIT");
+ split.setAttribute("accountid", (*it_s).m_accountId);
+ split.setAttribute("amount", (*it_s).m_amount.toString());
+ split.setAttribute("reconcile", (*it_s).m_reconcile);
+ split.setAttribute("category", (*it_s).m_strCategoryName);
+ split.setAttribute("memo", (*it_s).m_strMemo);
+ split.setAttribute("reconcile", (*it_s).m_reconcile);
+ p.appendChild(split);
+ }
+
+ e.appendChild(p);
+
+ ++it_t;
+ }
+
+ // iterate over prices, and add each one
+ QValueList<Price>::const_iterator it_p = m_listPrices.begin();
+ while ( it_p != m_listPrices.end() )
+ {
+ QDomElement p = _doc->createElement("PRICE");
+ p.setAttribute("dateposted", (*it_p).m_date.toString(Qt::ISODate));
+ p.setAttribute("security", (*it_p).m_strSecurity);
+ p.setAttribute("amount", (*it_p).m_amount.toString());
+
+ e.appendChild(p);
+
+ ++it_p;
+ }
+
+ // iterate over securities, and add each one
+ QValueList<Security>::const_iterator it_s = m_listSecurities.begin();
+ while ( it_s != m_listSecurities.end() )
+ {
+ QDomElement p = _doc->createElement("SECURITY");
+ p.setAttribute("name", (*it_s).m_strName);
+ p.setAttribute("symbol", (*it_s).m_strSymbol);
+ p.setAttribute("id", (*it_s).m_strId);
+
+ e.appendChild(p);
+
+ ++it_s;
+ }
+
+}
+
+bool MyMoneyStatement::read(const QDomElement& _e)
+{
+ bool result = false;
+
+ if ( _e.tagName() == "STATEMENT" )
+ {
+ result = true;
+
+ m_strAccountName = _e.attribute("accountname");
+ m_strAccountNumber = _e.attribute("accountnumber");
+ m_strRoutingNumber = _e.attribute("routingnumber");
+ m_strCurrency = _e.attribute("currency");
+ m_dateBegin = QDate::fromString(_e.attribute("begindate"),Qt::ISODate);
+ m_dateEnd = QDate::fromString(_e.attribute("enddate"),Qt::ISODate);
+ m_closingBalance = MyMoneyMoney(_e.attribute("closingbalance"));
+ m_accountId = _e.attribute("accountid");
+ m_skipCategoryMatching = _e.attribute("skipCategoryMatching");
+
+ int i = kAccountTypeTxt.findIndex(_e.attribute("type",kAccountTypeTxt[1]));
+ if ( i != -1 )
+ m_eType = static_cast<EType>(i);
+
+ QDomNode child = _e.firstChild();
+ while(!child.isNull() && child.isElement())
+ {
+ QDomElement c = child.toElement();
+
+ if ( c.tagName() == "TRANSACTION" )
+ {
+ MyMoneyStatement::Transaction t;
+
+ t.m_datePosted = QDate::fromString(c.attribute("dateposted"),Qt::ISODate);
+ t.m_amount = MyMoneyMoney(c.attribute("amount"));
+ t.m_strMemo = c.attribute("memo");
+ t.m_strNumber = c.attribute("number");
+ t.m_strPayee = c.attribute("payee");
+ t.m_strBankID = c.attribute("bankid");
+ t.m_reconcile = static_cast<MyMoneySplit::reconcileFlagE>(c.attribute("reconcile").toInt());
+ int i = kActionText.findIndex(c.attribute("action",kActionText[1]));
+ if ( i != -1 )
+ t.m_eAction = static_cast<Transaction::EAction>(i);
+
+ if (m_eType == etInvestment)
+ {
+ t.m_shares = MyMoneyMoney(c.attribute("shares"));
+ t.m_strSecurity = c.attribute("security");
+ t.m_strBrokerageAccount = c.attribute("brokerageaccount");
+ }
+
+ // process splits (if any)
+ QDomNode child = c.firstChild();
+ while(!child.isNull() && child.isElement()) {
+ QDomElement c = child.toElement();
+ if(c.tagName() == "SPLIT") {
+ MyMoneyStatement::Split s;
+ s.m_accountId = c.attribute("accountid");
+ s.m_amount = MyMoneyMoney(c.attribute("amount"));
+ s.m_reconcile = static_cast<MyMoneySplit::reconcileFlagE>(c.attribute("reconcile").toInt());
+ s.m_strCategoryName = c.attribute("category");
+ s.m_strMemo = c.attribute("memo");
+ t.m_listSplits += s;
+ }
+ child = child.nextSibling();
+ }
+ m_listTransactions += t;
+ }
+ else if ( c.tagName() == "PRICE" )
+ {
+ MyMoneyStatement::Price p;
+
+ p.m_date = QDate::fromString(c.attribute("dateposted"), Qt::ISODate);
+ p.m_strSecurity = c.attribute("security");
+ p.m_amount = MyMoneyMoney(c.attribute("amount"));
+
+ m_listPrices += p;
+ }
+ else if ( c.tagName() == "SECURITY" )
+ {
+ MyMoneyStatement::Security s;
+
+ s.m_strName = c.attribute("name");
+ s.m_strSymbol = c.attribute("symbol");
+ s.m_strId = c.attribute("id");
+
+ m_listSecurities += s;
+ }
+ child = child.nextSibling();
+ }
+ }
+
+ return result;
+}
+
+bool MyMoneyStatement::isStatementFile(const QString& _filename)
+{
+ // filename is considered a statement file if it contains
+ // the tag "<KMYMONEY2-STATEMENT>" in the first 20 lines.
+ bool result = false;
+
+ QFile f( _filename );
+ if ( f.open( IO_ReadOnly ) )
+ {
+ QTextStream ts( &f );
+
+ int lineCount = 20;
+ while ( !ts.atEnd() && !result && lineCount != 0) {
+ if ( ts.readLine().contains("<KMYMONEY-STATEMENT>",false) )
+ result = true;
+ --lineCount;
+ }
+ f.close();
+ }
+
+ return result;
+}
+
+void MyMoneyStatement::writeXMLFile( const MyMoneyStatement& _s, const QString& _filename )
+{
+ static unsigned filenum = 1;
+ QString filename = _filename;
+ if ( filename.isEmpty() ) {
+ filename = QString("statement-%1%2.xml").arg((filenum<10)?"0":"").arg(filenum);
+ filenum++;
+ }
+
+ QDomDocument* doc = new QDomDocument("KMYMONEY-STATEMENT");
+ Q_CHECK_PTR(doc);
+
+ //writeStatementtoXMLDoc(_s,doc);
+ QDomProcessingInstruction instruct = doc->createProcessingInstruction(QString("xml"), QString("version=\"1.0\" encoding=\"utf-8\""));
+ doc->appendChild(instruct);
+ QDomElement eroot = doc->createElement("KMYMONEY-STATEMENT");
+ doc->appendChild(eroot);
+ _s.write(eroot,doc);
+
+ QFile g( filename );
+ if(g.open( IO_WriteOnly )) {
+ QTextStream stream(&g);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << doc->toString();
+ g.close();
+ }
+
+ delete doc;
+}
+
+bool MyMoneyStatement::readXMLFile( MyMoneyStatement& _s, const QString& _filename )
+{
+ bool result = false;
+ QFile f( _filename );
+ f.open( IO_ReadOnly );
+ QDomDocument* doc = new QDomDocument;
+ if(doc->setContent(&f, false))
+ {
+ QDomElement rootElement = doc->documentElement();
+ if(!rootElement.isNull())
+ {
+ QDomNode child = rootElement.firstChild();
+ while(!child.isNull() && child.isElement())
+ {
+ result = true;
+ QDomElement childElement = child.toElement();
+ _s.read(childElement);
+
+ child = child.nextSibling();
+ }
+ }
+ }
+ delete doc;
+
+ return result;
+}
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneystatement.h b/kmymoney2/mymoney/mymoneystatement.h
new file mode 100644
index 0000000..0bea510
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneystatement.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ mymoneystatement.h
+ -------------------
+ begin : Mon Aug 30 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSTATEMENT_H
+#define MYMONEYSTATEMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneysplit.h>
+
+class QDomElement;
+class QDomDocument;
+
+/**
+Represents the electronic analog of the paper bank statement just like we used to get in the regular mail. This class is designed to be easy to extend and easy to create with minimal dependencies. So the header file should include as few project files as possible (preferrably NONE).
+
+@author ace jones
+*/
+class MyMoneyStatement
+{
+public:
+ MyMoneyStatement() : m_closingBalance(MyMoneyMoney::autoCalc), m_eType(etNone), m_skipCategoryMatching(false) {}
+
+ enum EType { etNone = 0, etCheckings, etSavings, etInvestment, etCreditCard, etEnd };
+
+ class Split {
+ public:
+ Split() : m_reconcile(MyMoneySplit::NotReconciled) {}
+ QString m_strCategoryName;
+ QString m_strMemo;
+ QString m_accountId;
+ MyMoneySplit::reconcileFlagE m_reconcile;
+ MyMoneyMoney m_amount;
+
+ };
+
+ class Transaction {
+ public:
+ Transaction() : m_reconcile(MyMoneySplit::NotReconciled), m_eAction(eaNone) {}
+ QDate m_datePosted;
+ QString m_strPayee;
+ QString m_strMemo;
+ QString m_strNumber;
+ QString m_strBankID;
+ MyMoneyMoney m_amount;
+ MyMoneySplit::reconcileFlagE m_reconcile;
+
+ // the following members are only used for investment accounts (m_eType==etInvestment)
+ // eaNone means the action, shares, and security can be ignored.
+ enum EAction { eaNone = 0, eaBuy, eaSell, eaReinvestDividend, eaCashDividend, eaShrsin, eaShrsout, eaStksplit, eaFees, eaInterest, eaEnd };
+ EAction m_eAction;
+ MyMoneyMoney m_shares;
+ MyMoneyMoney m_fees;
+ MyMoneyMoney m_price;
+ QString m_strInterestCategory;
+ QString m_strBrokerageAccount;
+ QString m_strSymbol;
+ QString m_strSecurity;
+ QValueList<Split> m_listSplits;
+ };
+
+ struct Price
+ {
+ QDate m_date;
+ QString m_strSecurity;
+ MyMoneyMoney m_amount;
+ };
+
+ struct Security
+ {
+ QString m_strName;
+ QString m_strSymbol;
+ QString m_strId;
+ };
+
+ QString m_strAccountName;
+ QString m_strAccountNumber;
+ QString m_strRoutingNumber;
+
+ /**
+ * The statement provider's information for the statement reader how to find the
+ * account. The provider usually leaves some value with a key unique to the provider in the KVP of the
+ * MyMoneyAccount object when setting up the connection or at a later point in time.
+ * Using the KMyMoneyPlugin::KMMStatementInterface::account() method it can retrieve the
+ * MyMoneyAccount object for this key. The account id of that account should be returned
+ * here. If no id is available, leave it empty.
+ */
+ QString m_accountId;
+
+ QString m_strCurrency;
+ QDate m_dateBegin;
+ QDate m_dateEnd;
+ MyMoneyMoney m_closingBalance;
+ EType m_eType;
+
+ QValueList<Transaction> m_listTransactions;
+ QValueList<Price> m_listPrices;
+ QValueList<Security> m_listSecurities;
+
+ bool m_skipCategoryMatching;
+
+ void write(QDomElement&,QDomDocument*) const;
+ bool read(const QDomElement&);
+
+ KMYMONEY_EXPORT static bool isStatementFile(const QString&);
+ KMYMONEY_EXPORT static bool readXMLFile( MyMoneyStatement&, const QString& );
+ KMYMONEY_EXPORT static void writeXMLFile( const MyMoneyStatement&, const QString& );
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneysubject.cpp b/kmymoney2/mymoney/mymoneysubject.cpp
new file mode 100644
index 0000000..c54d738
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysubject.cpp
@@ -0,0 +1,58 @@
+/***************************************************************************
+ mymoneysubject.cpp - description
+ -------------------
+ begin : Sat May 18 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneysubject.h"
+#include "mymoneyobserver.h"
+#include <qptrvector.h>
+
+MyMoneySubject::MyMoneySubject()
+{
+}
+
+MyMoneySubject::~MyMoneySubject()
+{
+}
+
+void MyMoneySubject::attach (MyMoneyObserver* o)
+{
+ m_observers.append(o);
+}
+
+void MyMoneySubject::detach (MyMoneyObserver* o)
+{
+ m_observers.remove(o);
+}
+
+void MyMoneySubject::notify(const QString& id)
+{
+ QPtrList<MyMoneyObserver> ptrList = m_observers;
+ MyMoneyObserver* i;
+
+ for (i = ptrList.first(); i != 0; i = ptrList.next()) {
+ // only call the observer if it did not detach in the meantime
+ if(m_observers.findRef(i) != -1) {
+ // qDebug("call observer @ 0x%08lX with '%s'", (unsigned long)i, id.data());
+ i->update(id);
+ }
+ }
+}
+
diff --git a/kmymoney2/mymoney/mymoneysubject.h b/kmymoney2/mymoney/mymoneysubject.h
new file mode 100644
index 0000000..74b8290
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneysubject.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ mymoneysubject.h - description
+ -------------------
+ begin : Sat May 18 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSUBJECT_H
+#define MYMONEYSUBJECT_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qptrlist.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+class MyMoneyObserver;
+class QString;
+
+/**
+ * This is the base class to be used to construct a
+ * subject for usage in a subject/observer relationship
+ *
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT MyMoneySubject {
+public:
+ virtual ~MyMoneySubject();
+ virtual void attach(MyMoneyObserver*);
+ virtual void detach(MyMoneyObserver*);
+ virtual void notify(const QString& id);
+
+protected:
+ MyMoneySubject();
+
+private:
+ QPtrList<MyMoneyObserver> m_observers;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneytransaction.cpp b/kmymoney2/mymoney/mymoneytransaction.cpp
new file mode 100644
index 0000000..10b4c08
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneytransaction.cpp
@@ -0,0 +1,484 @@
+/***************************************************************************
+
+ mymoneytransaction.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes,
+ 2002 by Thomas Baumgart
+ email : mte@users.sourceforge.net,
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneytransaction.h"
+
+MyMoneyTransaction::MyMoneyTransaction() :
+ MyMoneyObject()
+{
+ m_nextSplitID = 1;
+ m_entryDate = QDate();
+ m_postDate = QDate();
+}
+
+MyMoneyTransaction::MyMoneyTransaction(const QString id, const MyMoneyTransaction& transaction) :
+ MyMoneyObject(id)
+{
+ *this = transaction;
+ m_id = id;
+ if(m_entryDate == QDate())
+ m_entryDate = QDate::currentDate();
+
+ QValueList<MyMoneySplit>::Iterator it;
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ (*it).setTransactionId(id);
+ }
+}
+
+MyMoneyTransaction::MyMoneyTransaction(const QDomElement& node, const bool forceId) :
+ MyMoneyObject(node, forceId)
+{
+ if("TRANSACTION" != node.tagName())
+ throw new MYMONEYEXCEPTION("Node was not TRANSACTION");
+
+ m_nextSplitID = 1;
+
+ m_postDate = stringToDate(node.attribute("postdate"));
+ m_entryDate = stringToDate(node.attribute("entrydate"));
+ m_bankID = QStringEmpty(node.attribute("bankid"));
+ m_memo = QStringEmpty(node.attribute("memo"));
+ m_commodity = QStringEmpty(node.attribute("commodity"));
+
+ QDomNode child = node.firstChild();
+ while ( !child.isNull() && child.isElement() )
+ {
+ QDomElement c = child.toElement();
+ if(c.tagName() == "SPLITS") {
+ // Process any split information found inside the transaction entry.
+ QDomNodeList nodeList = c.elementsByTagName("SPLIT");
+ for(unsigned int i = 0; i < nodeList.count(); ++i) {
+ MyMoneySplit s(nodeList.item(i).toElement());
+ if(!m_bankID.isEmpty())
+ s.setBankID(m_bankID);
+ if(!s.accountId().isEmpty())
+ addSplit(s);
+ else
+ qDebug("Dropped split because it did not have an account id");
+ }
+
+ } else if(c.tagName() == "KEYVALUEPAIRS") {
+ MyMoneyKeyValueContainer kvp(c);
+ setPairs(kvp.pairs());
+ }
+ child = child.nextSibling();
+ }
+ m_bankID = QString();
+}
+
+MyMoneyTransaction::~MyMoneyTransaction()
+{
+}
+
+bool MyMoneyTransaction::operator == (const MyMoneyTransaction& right) const
+{
+ return (MyMoneyObject::operator==(right) &&
+ MyMoneyKeyValueContainer::operator==(right) &&
+ (m_commodity == right.m_commodity) &&
+ ((m_memo.length() == 0 && right.m_memo.length() == 0) || (m_memo == right.m_memo)) &&
+ (m_splits == right.m_splits) &&
+ (m_entryDate == right.m_entryDate) &&
+ (m_postDate == right.m_postDate) );
+}
+
+bool MyMoneyTransaction::accountReferenced(const QString& id) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).accountId() == id)
+ return true;
+ }
+ return false;
+}
+
+void MyMoneyTransaction::addSplit(MyMoneySplit& split)
+{
+ if(!split.id().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot add split with assigned id (" + split.id() + ")");
+
+/*
+ QValueList<MyMoneySplit>::Iterator it;
+
+ // if the account referenced in this split is already
+ // referenced in another split, we add the amount of
+ // this split to the other one. All other data contained
+ // in the new split will be discarded.
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).accountId() == split.accountId()) {
+ (*it).setValue((*it).value()+split.value());
+ split = (*it);
+ return;
+ }
+ }
+*/
+
+ if(split.accountId().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot add split that does not contain an account reference");
+
+ MyMoneySplit newSplit(nextSplitID(), split);
+ split = newSplit;
+ split.setTransactionId(id());
+ m_splits.append(split);
+}
+
+void MyMoneyTransaction::modifySplit(MyMoneySplit& split)
+{
+// This version of the routine allows only a single
+// split to reference one account. If a second split
+// is modified to reference an account already referenced
+// by another split, the values will be added and the
+// duplicate removed.
+/*
+ QValueList<MyMoneySplit>::Iterator it;
+ QValueList<MyMoneySplit>::Iterator self = m_splits.end();
+ QValueList<MyMoneySplit>::Iterator dup = self;
+ bool duplicateAccount = false;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if(split.id() == (*it).id()) {
+ self = it;
+ } else if(split.accountId() == (*it).accountId()) {
+ (*it).setValue((*it).value() + split.value());
+ dup = it;
+ duplicateAccount = true;
+ }
+ }
+
+ if(self == m_splits.end())
+ throw new MYMONEYEXCEPTION("Invalid split id '" + split.id() + "'");
+
+ if(duplicateAccount) {
+ m_splits.remove(self);
+ split = *dup;
+ } else
+ *self = split;
+*/
+
+// This is the other version which allows having more splits referencing
+// the same account.
+ if(split.accountId().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot modify split that does not contain an account reference");
+
+ QValueList<MyMoneySplit>::Iterator it;
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if(split.id() == (*it).id()) {
+ *it = split;
+ return;
+ }
+ }
+ throw new MYMONEYEXCEPTION(QString("Invalid split id '%1'").arg(split.id()));
+}
+
+void MyMoneyTransaction::removeSplit(const MyMoneySplit& split)
+{
+ QValueList<MyMoneySplit>::Iterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if(split.id() == (*it).id()) {
+ m_splits.remove(it);
+ break;
+ }
+ }
+ if(it == m_splits.end())
+ throw new MYMONEYEXCEPTION(QString("Invalid split id '%1'").arg(split.id()));
+}
+
+void MyMoneyTransaction::removeSplits(void)
+{
+ m_splits.clear();
+ m_nextSplitID = 1;
+}
+
+const MyMoneySplit& MyMoneyTransaction::splitByPayee(const QString& payeeId) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).payeeId() == payeeId)
+ return *it;
+ }
+ throw new MYMONEYEXCEPTION(QString("Split not found for payee '%1'").arg(QString(payeeId)));
+}
+
+const MyMoneySplit& MyMoneyTransaction::splitByAccount(const QString& accountId, const bool match) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if(match == true && (*it).accountId() == accountId)
+ return *it;
+ if(match == false && (*it).accountId() != accountId)
+ return *it;
+ }
+ throw new MYMONEYEXCEPTION(QString("Split not found for account %1%2").arg(match?"":"!").arg(QString(accountId)));
+}
+
+const MyMoneySplit& MyMoneyTransaction::splitByAccount(const QStringList& accountIds, const bool match) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if(match == true && accountIds.contains((*it).accountId()) )
+ return *it;
+ if(match == false && !accountIds.contains((*it).accountId()))
+ return *it;
+ }
+ throw new MYMONEYEXCEPTION(QString("Split not found for account %1%1...%2").arg(match?"":"!").arg(accountIds.front(),accountIds.back()));
+}
+
+const MyMoneySplit& MyMoneyTransaction::splitById(const QString& splitId) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).id() == splitId)
+ return *it;
+ }
+ throw new MYMONEYEXCEPTION(QString("Split not found for id '%1'").arg(QString(splitId)));
+}
+
+const QString MyMoneyTransaction::nextSplitID()
+{
+ QString id;
+ id = "S" + id.setNum(m_nextSplitID++).rightJustify(SPLIT_ID_SIZE, '0');
+ return id;
+}
+
+const QString MyMoneyTransaction::firstSplitID()
+{
+ QString id;
+ id = "S" + id.setNum(1).rightJustify(SPLIT_ID_SIZE, '0');
+ return id;
+}
+
+const MyMoneyMoney MyMoneyTransaction::splitSum(void) const
+{
+ MyMoneyMoney result(0);
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ result += (*it).value();
+ }
+ return result;
+}
+
+void MyMoneyTransaction::setPostDate(const QDate& date) { m_postDate = date; }
+void MyMoneyTransaction::setEntryDate(const QDate& date) { m_entryDate = date; }
+void MyMoneyTransaction::setMemo(const QString& memo) { m_memo = memo; }
+
+bool MyMoneyTransaction::isLoanPayment(void) const
+{
+ try {
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).isAmortizationSplit())
+ return true;
+ }
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ return false;
+}
+
+const MyMoneySplit& MyMoneyTransaction::amortizationSplit(void) const
+{
+ static MyMoneySplit nullSplit;
+
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).isAmortizationSplit() && (*it).isAutoCalc())
+ return *it;
+ }
+ return nullSplit;
+}
+
+const MyMoneySplit& MyMoneyTransaction::interestSplit(void) const
+{
+ static MyMoneySplit nullSplit;
+
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).isInterestSplit() && (*it).isAutoCalc())
+ return *it;
+ }
+ return nullSplit;
+}
+
+unsigned long MyMoneyTransaction::hash(const QString& txt, unsigned long h)
+{
+ unsigned long g;
+
+ for(unsigned i=0; i < txt.length(); ++i) {
+ unsigned short uc = txt[i].unicode();
+ for(unsigned j = 0; j < 2; ++j) {
+ unsigned char c = uc & 0xff;
+ // if either the cell or the row of the Unicode char is 0, stop processing
+ if(!c)
+ break;
+ h = (h << 4) + c;
+ if( (g = (h & 0xf0000000)) ) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ uc >>= 8;
+ }
+ }
+ return h;
+}
+
+bool MyMoneyTransaction::isStockSplit(void) const
+{
+ return (m_splits.count() == 1 && m_splits[0].action() == MyMoneySplit::ActionSplitShares);
+}
+
+bool MyMoneyTransaction::isImported(void) const
+{
+ return value("Imported").lower() == QString("true");
+}
+
+void MyMoneyTransaction::setImported(bool state)
+{
+ if(state)
+ setValue("Imported", "true");
+ else
+ deletePair("Imported");
+}
+
+bool MyMoneyTransaction::isDuplicate(const MyMoneyTransaction& r) const
+{
+ bool rc = true;
+ if(splitCount() != r.splitCount()) {
+ rc = false;
+ } else {
+ if(abs(m_postDate.daysTo(r.postDate())) > 3) {
+ rc = false;
+ } else {
+ unsigned long accHash[2];
+ unsigned long valHash[2];
+ unsigned long numHash[2];
+ for(int i = 0; i < 2; ++i)
+ accHash[i] = valHash[i] = numHash[i] = 0;
+
+ QValueList<MyMoneySplit>::ConstIterator it;
+ for(it = splits().begin(); it != splits().end(); ++it) {
+ accHash[0] += hash((*it).accountId());
+ valHash[0] += hash((*it).value().formatMoney("", 4));
+ numHash[0] += hash((*it).number());
+ }
+ for(it = r.splits().begin(); it != r.splits().end(); ++it) {
+ accHash[1] += hash((*it).accountId());
+ valHash[1] += hash((*it).value().formatMoney("", 4));
+ numHash[1] += hash((*it).number());
+ }
+
+ if(accHash[0] != accHash[1]
+ || valHash[0] != valHash[1]
+ || numHash[0] != numHash[1]
+ ) {
+ rc = false;
+ }
+ }
+ }
+
+ return rc;
+}
+
+void MyMoneyTransaction::writeXML(QDomDocument& document, QDomElement& parent) const
+{
+ QDomElement el = document.createElement("TRANSACTION");
+
+ writeBaseXML(document, el);
+
+ el.setAttribute("postdate", dateToString(m_postDate));
+ el.setAttribute("memo", m_memo);
+ el.setAttribute("entrydate", dateToString(m_entryDate));
+ el.setAttribute("commodity", m_commodity);
+
+ QDomElement splits = document.createElement("SPLITS");
+ QValueList<MyMoneySplit>::ConstIterator it;
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ (*it).writeXML(document, splits);
+ }
+ el.appendChild(splits);
+
+ MyMoneyKeyValueContainer::writeXML(document, el);
+
+ parent.appendChild(el);
+}
+
+bool MyMoneyTransaction::hasReferenceTo(const QString& id) const
+{
+ QValueList<MyMoneySplit>::const_iterator it;
+ bool rc = (id == m_commodity);
+ for(it = m_splits.begin(); rc == false && it != m_splits.end(); ++it) {
+ rc = (*it).hasReferenceTo(id);
+ }
+ return rc;
+}
+
+bool MyMoneyTransaction::hasAutoCalcSplit(void) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ for(it = m_splits.begin(); it != m_splits.end(); ++it) {
+ if((*it).isAutoCalc())
+ return true;
+ }
+ return false;
+}
+
+QString MyMoneyTransaction::accountSignature(bool includeSplitCount) const
+{
+ QMap<QString, int> accountList;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = m_splits.begin(); it_s != m_splits.end(); ++it_s) {
+ accountList[(*it_s).accountId()] += 1;
+ }
+
+ QMap<QString, int>::const_iterator it_a;
+ QString rc;
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ if(it_a != accountList.begin())
+ rc += "-";
+ rc += it_a.key();
+ if(includeSplitCount)
+ rc += QString("*%1").arg(*it_a);
+ }
+ return rc;
+}
+
+QString MyMoneyTransaction::uniqueSortKey(void) const
+{
+ QString year, month, day, key;
+ const QDate& postdate = postDate();
+ year = year.setNum(postdate.year()).rightJustify(YEAR_SIZE, '0');
+ month = month.setNum(postdate.month()).rightJustify(MONTH_SIZE, '0');
+ day = day.setNum(postdate.day()).rightJustify(DAY_SIZE, '0');
+ key = year + "-" + month + "-" + day + "-" + m_id;
+ return key;
+}
diff --git a/kmymoney2/mymoney/mymoneytransaction.h b/kmymoney2/mymoney/mymoneytransaction.h
new file mode 100644
index 0000000..ce52779
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneytransaction.h
@@ -0,0 +1,353 @@
+/***************************************************************************
+ mymoneytransaction.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ (C) 2002 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYTRANSACTION_H
+#define MYMONEYTRANSACTION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyutils.h"
+#include "mymoneymoney.h"
+#include "mymoneykeyvaluecontainer.h"
+#include "mymoneysplit.h"
+#include <kmymoney/export.h>
+
+/**
+ * This class represents a transaction within the MyMoneyEngine. A transaction
+ * contains none, one or more splits of type MyMoneySplit. They are stored in
+ * a QValueList<MyMoneySplit> within this object. A transaction containing only
+ * a single split with an amount not equal to 0 is an unbalanced transaction. It
+ * is tolerated by the engine, but in general not a good idea as it is financially
+ * wrong.
+ */
+class KMYMONEY_EXPORT MyMoneyTransaction : public MyMoneyObject, public MyMoneyKeyValueContainer
+{
+public:
+ MyMoneyTransaction();
+ MyMoneyTransaction(const QString id,
+ const MyMoneyTransaction& transaction);
+ /**
+ * @param node reference to QDomNode
+ * @param forceId see MyMoneyObject(const QDomElement&, const bool)
+ */
+ MyMoneyTransaction(const QDomElement& node, const bool forceId = true);
+ ~MyMoneyTransaction();
+
+public:
+ friend QDataStream &operator<<(QDataStream &, MyMoneyTransaction &);
+ friend QDataStream &operator>>(QDataStream &, MyMoneyTransaction &);
+
+ // Simple get operations
+ const QDate& entryDate(void) const { return m_entryDate; };
+ const QDate& postDate(void) const { return m_postDate; };
+ const QString& memo(void) const { return m_memo; };
+ const QValueList<MyMoneySplit>& splits(void) const { return m_splits; };
+ QValueList<MyMoneySplit>& splits(void) { return m_splits; };
+ unsigned int splitCount(void) const { return m_splits.count(); };
+ const QString& commodity(void) const { return m_commodity; };
+ const QString& bankID(void) const /*__attribute__ ((deprecated))*/ { return m_bankID; };
+
+ // Simple set operations
+ void setPostDate(const QDate& date);
+ void setEntryDate(const QDate& date);
+ void setMemo(const QString& memo);
+ void setCommodity(const QString& commodityId) { m_commodity = commodityId; };
+ void setBankID(const QString& bankID) /*__attribute__ ((deprecated))*/ { m_bankID = bankID; };
+
+ bool operator == (const MyMoneyTransaction&) const;
+ inline bool operator != (const MyMoneyTransaction& r) const { return !(*this == r); };
+ bool operator< (const MyMoneyTransaction& r) const { return postDate() < r.postDate(); };
+ bool operator<= (const MyMoneyTransaction& r) const { return postDate() <= r.postDate(); };
+ bool operator> (const MyMoneyTransaction& r) const { return postDate() > r.postDate(); };
+
+ /**
+ * This method is used to extract a split for a given accountId
+ * from a transaction. A parameter controls, whether the accountId
+ * should match or not. In case of 'not match', the first not-matching
+ * split is returned.
+ *
+ * @param accountId the account to look for
+ * @param match if true, the account Id must match
+ * if false, the account Id must not match
+ *
+ * @return reference to split within the transaction is returned
+ */
+ const MyMoneySplit& splitByAccount(const QString& accountId, const bool match = true) const;
+
+ /**
+ * This method is essentially the same as the previous method, except that
+ * takes a list of accounts instead of just one.
+ *
+ * @param accountIds the list of accounts to look for
+ * @param match if true, the account Id must match
+ * if false, the account Id must not match
+ *
+ * @return reference to split within the transaction is returned
+ */
+ const MyMoneySplit& splitByAccount(const QStringList& accountIds, const bool match = true) const;
+
+ /**
+ * This method is used to extract a split from a transaction.
+ *
+ * @param splitId the split to look for
+ *
+ * @return reference to split within the transaction is returned
+ */
+ const MyMoneySplit& splitById(const QString& splitId) const;
+
+ /**
+ * This method is used to extract a split for a given payeeId
+ * from a transaction.
+ *
+ * @param payeeId the payee to look for
+ *
+ * @return reference to split within the transaction is returned
+ */
+ const MyMoneySplit& splitByPayee(const QString& payeeId) const;
+
+ /**
+ * This method is used to check if the given account is used
+ * in any of the splits of this transation
+ *
+ * @param id account id that should be checked for usage
+ */
+ bool accountReferenced(const QString& id) const;
+
+ /**
+ * This method is used to add a split to the transaction. The split
+ * will be assigned an id. The id member must be empty and the
+ * accountId member must be filled.
+ *
+ * @param split reference to the split that should be added
+ *
+ */
+ void addSplit(MyMoneySplit& split);
+
+ /**
+ * This method is used to modify a split in a transaction
+ */
+ void modifySplit(MyMoneySplit& split);
+
+ /**
+ * This method is used to remove a split from a transaction
+ */
+ void removeSplit(const MyMoneySplit& split);
+
+ /**
+ * This method is used to remove all splits from a transaction
+ */
+ void removeSplits(void);
+
+ /**
+ * This method is used to return the sum of all splits of this transaction
+ *
+ * @return MyMoneyMoney value of sum of all splits
+ */
+ const MyMoneyMoney splitSum(void) const;
+
+ /**
+ * This method returns information if the transaction
+ * contains information of a loan payment or not.
+ * Loan payment transactions have at least one
+ * split that is identified with a MyMoneySplit::action() of type
+ * MyMoneySplit::ActionAmortization.
+ *
+ * @retval false transaction is no loan payment transaction
+ * @retval true transaction is a loan payment transaction
+ *
+ * @note Upon internal failures, the return value @p false will be used.
+ */
+ bool isLoanPayment(void) const;
+
+ /**
+ * This method returns a const reference to the amortization split.
+ * In case none is found, a reference to an empty split will be returned.
+ */
+ const MyMoneySplit& amortizationSplit(void) const;
+
+ /**
+ * This method returns a const reference to the interest split.
+ * In case none is found, a reference to an empty split will be returned.
+ */
+ const MyMoneySplit& interestSplit(void) const;
+
+ /**
+ * This method is used to check if two transactions are identical.
+ * Identical transactions have:
+ *
+ * - the same number of splits
+ * - reference the same accounts
+ * - have the same values in the splits
+ * - have a postDate wihtin 3 days
+ *
+ * @param transaction reference to the transaction to be checked
+ * against this transaction
+ * @retval true transactions are identical
+ * @retval false transactions are not identical
+ */
+ bool isDuplicate(const MyMoneyTransaction& transaction) const;
+
+ /**
+ * returns @a true if this is a stock split transaction
+ */
+ bool isStockSplit(void) const;
+
+ /**
+ * returns @a true if this is an imported transaction
+ */
+ bool isImported(void) const;
+
+ /**
+ * Sets the imported state of this transaction to be the value of @a state .
+ * @p state defaults to @p true.
+ */
+ void setImported(bool state = true);
+
+ /**
+ * This static method returns the id which will be assigned to the
+ * first split added to a transaction. This ID can be used to figure
+ * out the split that references the account through which a transaction
+ * was entered.
+ *
+ * @return QString with ID of the first split of transactions
+ */
+ static const QString firstSplitID(void);
+
+ void writeXML(QDomDocument& document, QDomElement& parent) const;
+
+ /**
+ * This method checks if a reference to the given object exists. It returns,
+ * a @p true if the object is referencing the one requested by the
+ * parameter @p id. If it does not, this method returns @p false.
+ *
+ * @param id id of the object to be checked for references
+ * @retval true This object references object with id @p id.
+ * @retval false This object does not reference the object with id @p id.
+ */
+ virtual bool hasReferenceTo(const QString& id) const;
+
+ /**
+ * Checks whether any split contains an autocalc split.
+ *
+ * @retval true at least one split has an autocalc value
+ * @retval false all splits have fixed values
+ */
+ bool hasAutoCalcSplit(void) const;
+
+ /**
+ * Returns a signature consisting of the account ids and the
+ * number of times they occur in the transaction if @a includeSplitCount
+ * is @a true. The signature is independant from the order of splits.
+ *
+ * Example: Having splits referencing the account B, A and B, the returned
+ * value will be "A-B" if @p includeSplitCount is @p false or A*1-B*2 if it
+ * is @p true.
+ *
+ * The same result will be returned if the list of splits is A, B, B.
+ *
+ * @param includeSplitCount if @p true, the string @p *n with @p n being
+ * the number of splits referencing this account. The default for
+ * this parameter is @p false.
+ */
+ QString accountSignature(bool includeSplitCount = false) const;
+
+ QString uniqueSortKey(void) const;
+
+ /**
+ * This module implements an algorithm used by P.J. Weinberger
+ * for fast hashing. Source: COMPILERS by Alfred V. Aho,
+ * pages 435-437.
+ *
+ * It converts the string passed in @p txt into a non-unique
+ * unsigned long integer value.
+ *
+ * @param txt the text to be hashed
+ * @param h initial hash value (default 0)
+ * @return non-unique hash value of the text @p txt
+ */
+ static unsigned long hash(const QString& txt, unsigned long h = 0);
+
+private:
+ /**
+ * This method returns the next id to be used for a split
+ */
+ const QString nextSplitID(void);
+
+private:
+ static const int SPLIT_ID_SIZE = 4;
+
+ /**
+ * This member contains the date when the transaction was entered
+ * into the engine
+ */
+ QDate m_entryDate;
+
+ /**
+ * This member contains the date the transaction was posted
+ */
+ QDate m_postDate;
+
+ /**
+ * This member keeps the memo text associated with this transaction
+ */
+ QString m_memo;
+
+ /**
+ * This member contains the splits for this transaction
+ */
+ QValueList<MyMoneySplit> m_splits;
+
+ /**
+ * This member keeps the unique numbers of splits within this
+ * transaction. Upon creation of a MyMoneyTransaction object this
+ * value will be set to 1.
+ */
+ unsigned int m_nextSplitID;
+
+ /**
+ * This member keeps the base commodity (e.g. currency) for this transaction
+ */
+ QString m_commodity;
+
+ /**
+ * This member keeps the bank's unique ID for the transaction, so we can
+ * avoid duplicates. This is only used for electronic statement downloads.
+ *
+ * Note this is now deprecated! Bank ID's should be set on splits, not transactions.
+ */
+ QString m_bankID;
+
+ /** constants for unique sort key */
+ static const int YEAR_SIZE = 4;
+ static const int MONTH_SIZE = 2;
+ static const int DAY_SIZE = 2;
+};
+#endif
diff --git a/kmymoney2/mymoney/mymoneytransactionfilter.cpp b/kmymoney2/mymoney/mymoneytransactionfilter.cpp
new file mode 100644
index 0000000..317400d
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneytransactionfilter.cpp
@@ -0,0 +1,860 @@
+/***************************************************************************
+ mymoneytransactionfilter.cpp - description
+ -------------------
+ begin : Fri Aug 22 2003
+ copyright : (C) 2003 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include "mymoneytransactionfilter.h"
+
+MyMoneyTransactionFilter::MyMoneyTransactionFilter()
+{
+ m_filterSet.allFilter = 0;
+ m_reportAllSplits = true;
+ m_considerCategory = true;
+ m_invertText = false;
+}
+
+MyMoneyTransactionFilter::MyMoneyTransactionFilter(const QString& id)
+{
+ m_filterSet.allFilter = 0;
+ m_reportAllSplits = false;
+ m_considerCategory = false;
+ m_invertText = false;
+
+ addAccount(id);
+ // addCategory(id);
+}
+
+MyMoneyTransactionFilter::~MyMoneyTransactionFilter()
+{
+}
+
+void MyMoneyTransactionFilter::clear(void)
+{
+ m_filterSet.allFilter = 0;
+ m_invertText = false;
+ m_accounts.clear();
+ m_categories.clear();
+ m_payees.clear();
+ m_types.clear();
+ m_states.clear();
+ m_validity.clear();
+ m_matchingSplits.clear();
+ m_fromDate = QDate();
+ m_toDate = QDate();
+}
+
+void MyMoneyTransactionFilter::clearAccountFilter(void)
+{
+ m_filterSet.singleFilter.accountFilter = 0;
+ m_accounts.clear();
+}
+
+void MyMoneyTransactionFilter::setTextFilter(const QRegExp& text, bool invert)
+{
+ m_filterSet.singleFilter.textFilter = 1;
+ m_invertText = invert;
+ m_text = text;
+}
+
+void MyMoneyTransactionFilter::addAccount(const QStringList& ids)
+{
+ QStringList::ConstIterator it;
+
+ m_filterSet.singleFilter.accountFilter = 1;
+ for(it = ids.begin(); it != ids.end(); ++it)
+ addAccount(*it);
+}
+
+void MyMoneyTransactionFilter::addAccount(const QString& id)
+{
+ if(!m_accounts.isEmpty() && !id.isEmpty()) {
+ if(m_accounts.find(id) != 0)
+ return;
+ }
+ if(m_accounts.count() >= m_accounts.size()*2) {
+ m_accounts.resize(457);
+ }
+ m_filterSet.singleFilter.accountFilter = 1;
+ if(!id.isEmpty())
+ m_accounts.insert(id, "");
+}
+
+void MyMoneyTransactionFilter::addCategory(const QStringList& ids)
+{
+ QStringList::ConstIterator it;
+
+ m_filterSet.singleFilter.categoryFilter = 1;
+ for(it = ids.begin(); it != ids.end(); ++it)
+ addCategory(*it);
+}
+
+void MyMoneyTransactionFilter::addCategory(const QString& id)
+{
+ if(!m_categories.isEmpty() && !id.isEmpty()) {
+ if(m_categories.find(id) != 0)
+ return;
+ }
+ if(m_categories.count() >= m_categories.size()*2) {
+ m_categories.resize(457);
+ }
+ m_filterSet.singleFilter.categoryFilter = 1;
+ if(!id.isEmpty())
+ m_categories.insert(id, "");
+}
+
+void MyMoneyTransactionFilter::setDateFilter(const QDate& from, const QDate& to)
+{
+ m_filterSet.singleFilter.dateFilter = from.isValid() | to.isValid();
+ m_fromDate = from;
+ m_toDate = to;
+}
+
+void MyMoneyTransactionFilter::setAmountFilter(const MyMoneyMoney& from, const MyMoneyMoney& to)
+{
+ m_filterSet.singleFilter.amountFilter = 1;
+ m_fromAmount = from.abs();
+ m_toAmount = to.abs();
+
+ // make sure that the user does not try to fool us ;-)
+ if(from > to) {
+ MyMoneyMoney tmp = m_fromAmount;
+ m_fromAmount = m_toAmount;
+ m_toAmount = tmp;
+ }
+}
+
+void MyMoneyTransactionFilter::addPayee(const QString& id)
+{
+ if(!m_payees.isEmpty() && !id.isEmpty()) {
+ if(m_payees.find(id) != 0)
+ return;
+ }
+ if(m_payees.count() >= m_payees.size()*2) {
+ m_payees.resize(457);
+ }
+ m_filterSet.singleFilter.payeeFilter = 1;
+ if(!id.isEmpty())
+ m_payees.insert(id, "");
+}
+
+void MyMoneyTransactionFilter::addType(const int type)
+{
+ if(!m_types.isEmpty()) {
+ if(m_types.find(type) != 0)
+ return;
+ }
+ // we don't have more than 4 or 5 types, so we don't worry about
+ // the size of the QIntDict object.
+ m_filterSet.singleFilter.typeFilter = 1;
+ m_types.insert(type, "");
+}
+
+void MyMoneyTransactionFilter::addState(const int state)
+{
+ if(!m_states.isEmpty()) {
+ if(m_states.find(state) != 0)
+ return;
+ }
+ // we don't have more than 4 or 5 states, so we don't worry about
+ // the size of the QIntDict object.
+ m_filterSet.singleFilter.stateFilter = 1;
+ m_states.insert(state, "");
+}
+
+void MyMoneyTransactionFilter::addValidity(const int type)
+{
+ if(!m_validity.isEmpty()) {
+ if(m_validity.find(type) != 0)
+ return;
+ }
+ // we don't have more than 4 or 5 states, so we don't worry about
+ // the size of the QIntDict object.
+ m_filterSet.singleFilter.validityFilter = 1;
+ m_validity.insert(type, "");
+}
+
+void MyMoneyTransactionFilter::setNumberFilter(const QString& from, const QString& to)
+{
+ m_filterSet.singleFilter.nrFilter = 1;
+ m_fromNr = from;
+ m_toNr = to;
+}
+
+void MyMoneyTransactionFilter::setReportAllSplits(const bool report)
+{
+ m_reportAllSplits = report;
+}
+
+void MyMoneyTransactionFilter::setConsiderCategory(const bool check)
+{
+ m_considerCategory = check;
+}
+
+const QValueList<MyMoneySplit>& MyMoneyTransactionFilter::matchingSplits(void) const
+{
+ return m_matchingSplits;
+}
+
+bool MyMoneyTransactionFilter::matchText(const MyMoneySplit * const sp) const
+{
+ // check if the text is contained in one of the fields
+ // memo, value, number, payee, account, date
+ if(m_filterSet.singleFilter.textFilter) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ const MyMoneyAccount& acc = file->account(sp->accountId());
+ const MyMoneySecurity& sec = file->security(acc.currencyId());
+ if(sp->memo().contains(m_text)
+ || sp->shares().formatMoney(acc.fraction(sec)).contains(m_text)
+ || sp->value().formatMoney(acc.fraction(sec)).contains(m_text)
+ || sp->number().contains(m_text))
+ return !m_invertText;
+
+ if(acc.name().contains(m_text))
+ return !m_invertText;
+
+ if(!sp->payeeId().isEmpty()) {
+ const MyMoneyPayee& payee = file->payee(sp->payeeId());
+ if(payee.name().contains(m_text))
+ return !m_invertText;
+ }
+ return m_invertText;
+ }
+ return true;
+}
+
+bool MyMoneyTransactionFilter::matchAmount(const MyMoneySplit * const sp) const
+{
+ if(m_filterSet.singleFilter.amountFilter) {
+ if(((sp->value().abs() < m_fromAmount) || sp->value().abs() > m_toAmount)
+ && ((sp->shares().abs() < m_fromAmount) || sp->shares().abs() > m_toAmount))
+ return false;
+ }
+
+ return true;
+}
+
+bool MyMoneyTransactionFilter::match(const MyMoneySplit * const sp) const
+{
+ return matchText(sp) && matchAmount(sp);
+}
+
+bool MyMoneyTransactionFilter::match(const MyMoneyTransaction& transaction)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ m_matchingSplits.clear();
+
+ // qDebug("T: %s", transaction.id().data());
+ // if no filter is set, we can savely return a match
+ // if we should report all splits, then we collect them
+ if(!m_filterSet.allFilter) {
+ if(m_reportAllSplits) {
+ m_matchingSplits = transaction.splits();
+ }
+ return true;
+ }
+
+ // perform checks on the MyMoneyTransaction object first
+
+ // check the date range
+ if(m_filterSet.singleFilter.dateFilter) {
+ if(m_fromDate != QDate()) {
+ if(transaction.postDate() < m_fromDate)
+ return false;
+ }
+
+ if(m_toDate != QDate()) {
+ if(transaction.postDate() > m_toDate)
+ return false;
+ }
+ }
+
+ // construct a local list of pointers to all splits and
+ // remove the ones that do not match account and/or categories.
+
+ QPtrList<MyMoneySplit> matchingSplits;
+ for(it = transaction.splits().begin(); it != transaction.splits().end(); ++it) {
+ matchingSplits.append(&(*it));
+ }
+
+ bool categoryMatched = !m_filterSet.singleFilter.categoryFilter;
+ bool accountMatched = !m_filterSet.singleFilter.accountFilter;
+ bool isTransfer = true;
+
+ // check the transaction's validity
+ if(m_filterSet.singleFilter.validityFilter) {
+ if(m_validity.count() > 0) {
+ if(!m_validity.find(validTransaction(transaction)))
+ return false;
+ }
+ }
+
+ MyMoneySplit* sp;
+
+ if(m_filterSet.singleFilter.accountFilter == 1
+ || m_filterSet.singleFilter.categoryFilter == 1) {
+ for(sp = matchingSplits.first(); sp != 0; ) {
+ MyMoneySplit* removeSplit = sp;
+ const MyMoneyAccount& acc = file->account(sp->accountId());
+ if(m_considerCategory) {
+ switch(acc.accountGroup()) {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ isTransfer = false;
+ // check if the split references one of the categories in the list
+ if(m_filterSet.singleFilter.categoryFilter) {
+ if(m_categories.count() > 0) {
+ if(m_categories.find(sp->accountId())) {
+ categoryMatched = true;
+ removeSplit = 0;
+ }
+ } else {
+ // we're looking for transactions with 'no' categories
+ return false;
+ }
+ }
+ break;
+
+ default:
+ // check if the split references one of the accounts in the list
+ if(m_filterSet.singleFilter.accountFilter) {
+ if(m_accounts.count() > 0) {
+ if(m_accounts.find(sp->accountId())) {
+ accountMatched = true;
+ removeSplit = 0;
+ }
+ }
+ } else
+ removeSplit = 0;
+
+ break;
+ }
+
+ } else {
+ if(m_filterSet.singleFilter.accountFilter) {
+ if(m_accounts.count() > 0) {
+ if(m_accounts.find(sp->accountId())) {
+ accountMatched = true;
+ removeSplit = 0;
+ }
+ }
+ } else
+ removeSplit = 0;
+ }
+
+ sp = matchingSplits.next();
+ if(removeSplit) {
+ // qDebug(" S: %s", (*it).id().data());
+ matchingSplits.remove(removeSplit);
+ }
+ }
+ }
+
+ // check if we're looking for transactions without assigned category
+ if(!categoryMatched && transaction.splitCount() == 1 && m_categories.count() == 0) {
+ categoryMatched = true;
+ }
+
+ // if there's no category filter and the category did not
+ // match, then we still want to see this transaction if it's
+ // a transfer
+ if(!categoryMatched && !m_filterSet.singleFilter.categoryFilter)
+ categoryMatched = isTransfer;
+
+ if(matchingSplits.count() == 0
+ || !(accountMatched && categoryMatched))
+ return false;
+
+ FilterSet filterSet = m_filterSet;
+ filterSet.singleFilter.dateFilter =
+ filterSet.singleFilter.accountFilter =
+ filterSet.singleFilter.categoryFilter = 0;
+
+ // check if we still have something to do
+ if(filterSet.allFilter != 0) {
+ for(sp = matchingSplits.first(); sp != 0;) {
+ MyMoneySplit* removeSplit = 0;
+ removeSplit = (matchAmount(sp) && matchText(sp)) ? 0 : sp;
+
+ const MyMoneyAccount& acc = file->account(sp->accountId());
+
+ // Determine if this account is a category or an account
+ bool isCategory = false;
+ switch(acc.accountGroup()) {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ isCategory = true;
+ default:
+ break;
+ }
+
+ if(!isCategory && !removeSplit) {
+ // check the payee list
+ if(!removeSplit && m_filterSet.singleFilter.payeeFilter) {
+ if(m_payees.count() > 0) {
+ if(sp->payeeId().isEmpty() || !m_payees.find(sp->payeeId()))
+ removeSplit = sp;
+ } else if(!sp->payeeId().isEmpty())
+ removeSplit = sp;
+ }
+
+ // check the type list
+ if(!removeSplit && m_filterSet.singleFilter.typeFilter) {
+ if(m_types.count() > 0) {
+ if(!m_types.find(splitType(transaction, *sp)))
+ removeSplit = sp;
+ }
+ }
+
+ // check the state list
+ if(!removeSplit && m_filterSet.singleFilter.stateFilter) {
+ if(m_states.count() > 0) {
+ if(!m_states.find(splitState(*sp)))
+ removeSplit = sp;
+ }
+ }
+
+ if(!removeSplit && m_filterSet.singleFilter.nrFilter) {
+ if(!m_fromNr.isEmpty()) {
+ if(sp->number() < m_fromNr)
+ removeSplit = sp;
+ }
+ if(!m_toNr.isEmpty()) {
+ if(sp->number() > m_toNr)
+ removeSplit = sp;
+ }
+ }
+ } else if(m_filterSet.singleFilter.payeeFilter
+ || m_filterSet.singleFilter.typeFilter
+ || m_filterSet.singleFilter.stateFilter
+ || m_filterSet.singleFilter.nrFilter)
+ removeSplit = sp;
+
+ sp = matchingSplits.next();
+ if(removeSplit) {
+ // qDebug(" S: %s", (*it).id().data());
+ matchingSplits.remove(removeSplit);
+ }
+ }
+ }
+
+ if(m_reportAllSplits == false && matchingSplits.count() != 0) {
+ m_matchingSplits.append(transaction.splits()[0]);
+ } else {
+ for(sp = matchingSplits.first(); sp != 0; sp = matchingSplits.next()) {
+ m_matchingSplits.append(*sp);
+ }
+ }
+ // all filters passed, I guess we have a match
+ // qDebug(" C: %d", m_matchingSplits.count());
+ return matchingSplits.count() != 0;
+}
+
+int MyMoneyTransactionFilter::splitState(const MyMoneySplit& split) const
+{
+ int rc = notReconciled;
+
+ switch(split.reconcileFlag()) {
+ default:
+ case MyMoneySplit::NotReconciled:
+ break;;
+
+ case MyMoneySplit::Cleared:
+ rc = cleared;
+ break;
+
+ case MyMoneySplit::Reconciled:
+ rc = reconciled;
+ break;
+
+ case MyMoneySplit::Frozen:
+ rc = frozen;
+ break;
+ }
+ return rc;
+}
+
+int MyMoneyTransactionFilter::splitType(const MyMoneyTransaction& t, const MyMoneySplit& split) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount a, b;
+ a = file->account(split.accountId());
+ if((a.accountGroup() == MyMoneyAccount::Income
+ || a.accountGroup() == MyMoneyAccount::Expense))
+ return allTypes;
+
+ if(t.splitCount() == 2) {
+ QString ida, idb;
+ ida = t.splits()[0].accountId();
+ idb = t.splits()[1].accountId();
+
+ a = file->account(ida);
+ b = file->account(idb);
+ if((a.accountGroup() != MyMoneyAccount::Expense
+ && a.accountGroup() != MyMoneyAccount::Income)
+ && (b.accountGroup() != MyMoneyAccount::Expense
+ && b.accountGroup() != MyMoneyAccount::Income))
+ return transfers;
+ }
+
+ if(split.value().isPositive())
+ return deposits;
+
+ return payments;
+}
+
+MyMoneyTransactionFilter::validityOptionE MyMoneyTransactionFilter::validTransaction(const MyMoneyTransaction& t) const
+{
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ MyMoneyMoney val;
+
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ val += (*it_s).value();
+ }
+ return (val == MyMoneyMoney(0,1)) ? valid : invalid;
+}
+
+bool MyMoneyTransactionFilter::includesCategory( const QString& cat ) const
+{
+ return (! m_filterSet.singleFilter.categoryFilter) || m_categories.find( cat );
+}
+
+bool MyMoneyTransactionFilter::includesAccount( const QString& acc ) const
+{
+ return (! m_filterSet.singleFilter.accountFilter) || m_accounts.find( acc );
+}
+
+bool MyMoneyTransactionFilter::includesPayee( const QString& pye ) const
+{
+ return (! m_filterSet.singleFilter.payeeFilter) || m_payees.find( pye );
+}
+
+bool MyMoneyTransactionFilter::dateFilter( QDate& from, QDate& to ) const
+{
+ from = m_fromDate;
+ to = m_toDate;
+ return m_filterSet.singleFilter.dateFilter==1;
+}
+
+bool MyMoneyTransactionFilter::amountFilter( MyMoneyMoney& from, MyMoneyMoney& to ) const
+{
+ from = m_fromAmount;
+ to = m_toAmount;
+ return m_filterSet.singleFilter.amountFilter==1;
+}
+
+bool MyMoneyTransactionFilter::numberFilter( QString& from, QString& to ) const
+{
+ from = m_fromNr;
+ to = m_toNr;
+ return m_filterSet.singleFilter.nrFilter==1;
+}
+
+bool MyMoneyTransactionFilter::payees(QStringList& list) const
+{
+ bool result = m_filterSet.singleFilter.payeeFilter;
+
+ if ( result )
+ {
+ QAsciiDictIterator<char> it_payee( m_payees );
+ while ( it_payee.current() )
+ {
+ list += it_payee.currentKey();
+ ++it_payee;
+ }
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::accounts(QStringList& list) const
+{
+ bool result = m_filterSet.singleFilter.accountFilter;
+
+ if ( result )
+ {
+ QAsciiDictIterator<char> it_account( m_accounts );
+ while ( it_account.current() )
+ {
+ QString account = it_account.currentKey();
+ list += account;
+ ++it_account;
+ }
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::categories(QStringList& list) const
+{
+ bool result = m_filterSet.singleFilter.categoryFilter;
+
+ if ( result )
+ {
+ QAsciiDictIterator<char> it_category( m_categories );
+ while ( it_category.current() )
+ {
+ list += it_category.currentKey();
+ ++it_category;
+ }
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::types(QValueList<int>& list) const
+{
+ bool result = m_filterSet.singleFilter.typeFilter;
+
+ if ( result )
+ {
+ QIntDictIterator<char> it_type( m_types );
+ while ( it_type.current() )
+ {
+ list += it_type.currentKey();
+ ++it_type;
+ }
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::states(QValueList<int>& list) const
+{
+ bool result = m_filterSet.singleFilter.stateFilter;
+
+ if ( result )
+ {
+ QIntDictIterator<char> it_state( m_states );
+ while ( it_state.current() )
+ {
+ list += it_state.currentKey();
+ ++it_state;
+ }
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::firstType(int&i) const
+{
+ bool result = m_filterSet.singleFilter.typeFilter;
+
+ if ( result )
+ {
+ QIntDictIterator<char> it_type( m_types );
+ if ( it_type.current() )
+ i = it_type.currentKey();
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::firstState(int&i) const
+{
+ bool result = m_filterSet.singleFilter.stateFilter;
+
+ if ( result )
+ {
+ QIntDictIterator<char> it_state( m_states );
+ if ( it_state.current() )
+ i = it_state.currentKey();
+ }
+ return result;
+}
+
+bool MyMoneyTransactionFilter::textFilter(QRegExp& exp) const
+{
+ exp = m_text;
+ return m_filterSet.singleFilter.textFilter == 1;
+}
+
+void MyMoneyTransactionFilter::setDateFilter(dateOptionE range)
+{
+ QDate from, to;
+ if ( translateDateRange(range,from,to) )
+ setDateFilter(from,to);
+}
+
+static int fiscalYearStartMonth = 1;
+static int fiscalYearStartDay = 1;
+
+void MyMoneyTransactionFilter::setFiscalYearStart(int firstMonth, int firstDay)
+{
+ fiscalYearStartMonth = firstMonth;
+ fiscalYearStartDay = firstDay;
+}
+
+bool MyMoneyTransactionFilter::translateDateRange(dateOptionE id, QDate& start, QDate& end)
+{
+ bool rc = true;
+ int yr, mon, day;
+ yr = QDate::currentDate().year();
+ mon = QDate::currentDate().month();
+ day = QDate::currentDate().day();
+ QDate tmp;
+
+ switch(id) {
+ case MyMoneyTransactionFilter::allDates:
+ start = QDate();
+ end = QDate();
+ break;
+ case MyMoneyTransactionFilter::asOfToday:
+ start = QDate();
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::currentMonth:
+ start = QDate(yr,mon,1);
+ end = QDate(yr,mon,1).addMonths(1).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::currentYear:
+ start = QDate(yr,1,1);
+ end = QDate(yr,12,31);
+ break;
+ case MyMoneyTransactionFilter::monthToDate:
+ start = QDate(yr,mon,1);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::yearToDate:
+ start = QDate(yr,1,1);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::yearToMonth:
+ start = QDate(yr,1,1);
+ end = QDate(yr,mon,1).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::lastMonth:
+ start = QDate(yr,mon,1).addMonths(-1);
+ end = QDate(yr,mon,1).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::lastYear:
+ start = QDate(yr,1,1).addYears(-1);
+ end = QDate(yr,12,31).addYears(-1);
+ break;
+ case MyMoneyTransactionFilter::last7Days:
+ start = QDate::currentDate().addDays(-7);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::last30Days:
+ start = QDate::currentDate().addDays(-30);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::last3Months:
+ start = QDate::currentDate().addMonths(-3);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::last6Months:
+ start = QDate::currentDate().addMonths(-6);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::last11Months:
+ start = QDate(yr,mon,1).addMonths(-12);
+ end = QDate(yr,mon,1).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::last12Months:
+ start = QDate::currentDate().addMonths(-12);
+ end = QDate::currentDate();
+ break;
+ case MyMoneyTransactionFilter::next7Days:
+ start = QDate::currentDate();
+ end = QDate::currentDate().addDays(7);
+ break;
+ case MyMoneyTransactionFilter::next30Days:
+ start = QDate::currentDate();
+ end = QDate::currentDate().addDays(30);
+ break;
+ case MyMoneyTransactionFilter::next3Months:
+ start = QDate::currentDate();
+ end = QDate::currentDate().addMonths(3);
+ break;
+ case MyMoneyTransactionFilter::next6Months:
+ start = QDate::currentDate();
+ end = QDate::currentDate().addMonths(6);
+ break;
+ case MyMoneyTransactionFilter::next12Months:
+ start = QDate::currentDate();
+ end = QDate::currentDate().addMonths(12);
+ break;
+ case MyMoneyTransactionFilter::userDefined:
+ start = QDate();
+ end = QDate();
+ break;
+ case MyMoneyTransactionFilter::last3ToNext3Months:
+ start = QDate::currentDate().addMonths(-3);
+ end = QDate::currentDate().addMonths(3);
+ break;
+ case MyMoneyTransactionFilter::currentQuarter:
+ start = QDate(yr, mon - ((mon-1) % 3), 1);
+ end = start.addMonths(3).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::lastQuarter:
+ start = QDate(yr, mon - ((mon-1) % 3), 1).addMonths(-3);
+ end = start.addMonths(3).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::nextQuarter:
+ start = QDate(yr, mon - ((mon-1) % 3), 1).addMonths(3);
+ end = start.addMonths(3).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::currentFiscalYear:
+ start = QDate(QDate::currentDate().year(), fiscalYearStartMonth, fiscalYearStartDay);
+ if(QDate::currentDate() < start)
+ start = start.addYears(-1);
+ end = start.addYears(1).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::lastFiscalYear:
+ start = QDate(QDate::currentDate().year(), fiscalYearStartMonth, fiscalYearStartDay);
+ if(QDate::currentDate() < start)
+ start = start.addYears(-1);
+ start = start.addYears(-1);
+ end = start.addYears(1).addDays(-1);
+ break;
+ case MyMoneyTransactionFilter::today:
+ start = QDate::currentDate();
+ end = QDate::currentDate();
+ break;
+ default:
+ qFatal("Unknown date identifier %d in MyMoneyTransactionFilter::translateDateRange()", id);
+ rc = false;
+ break;
+ }
+ return rc;
+}
+
+void MyMoneyTransactionFilter::removeReference(const QString& id)
+{
+ if(m_accounts.find(id)) {
+ qDebug("%s", (QString("Remove account '%1' from report").arg(id)).data());
+ m_accounts.remove(id);
+ } else if(m_categories.find(id)) {
+ qDebug("%s", (QString("Remove category '%1' from report").arg(id)).data());
+ m_categories.remove(id);
+ } else if(m_payees.find(id)) {
+ qDebug("%s", (QString("Remove payee '%1' from report").arg(id)).data());
+ m_payees.remove(id);
+ }
+}
+
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/mymoneytransactionfilter.h b/kmymoney2/mymoney/mymoneytransactionfilter.h
new file mode 100644
index 0000000..edad9cc
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneytransactionfilter.h
@@ -0,0 +1,578 @@
+/***************************************************************************
+ mymoneytransactionfilter.h - description
+ -------------------
+ begin : Fri Aug 22 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYTRANSACTIONFILTER_H
+#define MYMONEYTRANSACTIONFILTER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qmap.h>
+#include <qasciidict.h>
+#include <qintdict.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/export.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KMYMONEY_EXPORT MyMoneyTransactionFilter
+{
+public:
+ // Make sure to keep the following enum valus in sync with the values
+ // used by the GUI (for KMyMoney in kfindtransactiondlgdecl.ui)
+ enum typeOptionE {
+ allTypes = 0,
+ payments,
+ deposits,
+ transfers,
+ // insert new constants above of this line
+ typeOptionCount
+ };
+
+ // Make sure to keep the following enum valus in sync with the values
+ // used by the GUI (for KMyMoney in kfindtransactiondlgdecl.ui)
+ enum stateOptionE {
+ allStates = 0,
+ notReconciled,
+ cleared,
+ reconciled,
+ frozen,
+ // insert new constants above of this line
+ stateOptionCount
+ };
+
+ // Make sure to keep the following enum valus in sync with the values
+ // used by the GUI (for KMyMoney in kfindtransactiondlgdecl.ui)
+ enum validityOptionE {
+ anyValidity = 0,
+ valid,
+ invalid,
+ // insert new constants above of this line
+ validityOptionCount
+ };
+
+ // Make sure to keep the following enum valus in sync with the values
+ // used by the GUI (for KMyMoney in kfindtransactiondlgdecl.ui)
+ enum dateOptionE {
+ allDates = 0,
+ asOfToday,
+ currentMonth,
+ currentYear,
+ monthToDate,
+ yearToDate,
+ yearToMonth,
+ lastMonth,
+ lastYear,
+ last7Days,
+ last30Days,
+ last3Months,
+ last6Months,
+ last12Months,
+ next7Days,
+ next30Days,
+ next3Months,
+ next6Months,
+ next12Months,
+ userDefined,
+ last3ToNext3Months,
+ last11Months,
+ currentQuarter,
+ lastQuarter,
+ nextQuarter,
+ currentFiscalYear,
+ lastFiscalYear,
+ today,
+ // insert new constants above of this line
+ dateOptionCount
+ };
+
+ typedef union {
+ unsigned allFilter;
+ struct {
+ unsigned textFilter : 1;
+ unsigned accountFilter : 1;
+ unsigned payeeFilter : 1;
+ unsigned categoryFilter : 1;
+ unsigned nrFilter : 1;
+ unsigned dateFilter : 1;
+ unsigned amountFilter : 1;
+ unsigned typeFilter : 1;
+ unsigned stateFilter : 1;
+ unsigned validityFilter : 1;
+ } singleFilter;
+ } FilterSet;
+
+ /**
+ * This is the standard constructor for a transaction filter.
+ * It creates the object and calls setReportAllSplits() to
+ * report all matching splits as separate entries. Use
+ * setReportAllSplits() to override this behaviour.
+ */
+ MyMoneyTransactionFilter();
+
+ /**
+ * This is a convenience constructor to allow construction of
+ * a simple account filter. It is basically the same as the
+ * following:
+ *
+ * @code
+ * :
+ * MyMoneyTransactionFilter filter;
+ * filter.setReportAllSplits(false);
+ * filter.addAccount(id);
+ * :
+ * @endcode
+ *
+ * @param id reference to account id
+ */
+ MyMoneyTransactionFilter(const QString& id);
+
+ ~MyMoneyTransactionFilter();
+
+ /**
+ * This method is used to clear the filter. All settings will be
+ * removed.
+ */
+ void clear(void);
+
+ /**
+ * This method is used to clear the accounts filter only.
+ */
+ void clearAccountFilter(void);
+
+ /**
+ * This method is used to set the regular expression filter to the value specified
+ * as parameter @p exp. The following text based fields are searched:
+ *
+ * - Memo
+ * - Payee
+ * - Category
+ * - Shares / Value
+ * - Number
+ *
+ * @param exp The regular expression that must be found in a transaction
+ * before it is included in the result set.
+ * @param invert If true, value must not be contained in any of the above mentioned fields
+ *
+ */
+ void setTextFilter(const QRegExp& exp, bool invert = false);
+
+ /**
+ * This method will add the account with id @p id to the list of matching accounts.
+ * If the list is empty, any transaction will match.
+ *
+ * @param id internal ID of the account
+ */
+ void addAccount(const QString& id);
+
+ /**
+ * This is a convenience method and behaves exactly like the above
+ * method but for a list of id's.
+ */
+ void addAccount(const QStringList& ids);
+
+ /**
+ * This method will add the category with id @p id to the list of matching categories.
+ * If the list is empty, only transaction with a single asset/liability account will match.
+ *
+ * @param id internal ID of the account
+ */
+ void addCategory(const QString& id);
+
+ /**
+ * This is a convenience method and behaves exactly like the above
+ * method but for a list of id's.
+ */
+ void addCategory(const QStringList& ids);
+
+ /**
+ * This method sets the date filter to match only transactions with posting dates in
+ * the date range specified by @p from and @p to. If @p from equal QDate()
+ * all transactions with dates prior to @p to match. If @p to equals QDate()
+ * all transactions with posting dates past @p from match. If @p from and @p to
+ * are equal QDate() the filter is not activated and all transactions match.
+ *
+ * @param from from date
+ * @param to to date
+ */
+ void setDateFilter(const QDate& from, const QDate& to);
+
+ void setDateFilter(dateOptionE range);
+
+ /**
+ * This method sets the amount filter to match only transactions with
+ * an amount in the range specified by @p from and @p to.
+ * If a specific amount should be searched, @p from and @p to should be
+ * the same value.
+ *
+ * @param from smallest value to match
+ * @param to largest value to match
+ */
+ void setAmountFilter(const MyMoneyMoney& from, const MyMoneyMoney& to);
+
+ /**
+ * This method will add the payee with id @p id to the list of matching payees.
+ * If the list is empty, any transaction will match.
+ *
+ * @param id internal id of the payee
+ */
+ void addPayee(const QString& id);
+
+ /**
+ */
+ void addType(const int type);
+
+ /**
+ */
+ void addValidity(const int type);
+
+ /**
+ */
+ void addState(const int state);
+
+ /**
+ * This method sets the number filter to match only transactions with
+ * a number in the range specified by @p from and @p to.
+ * If a specific number should be searched, @p from and @p to should be
+ * the same value.
+ *
+ * @param from smallest value to match
+ * @param to largest value to match
+ *
+ * @note @p from and @p to can contain alphanumeric text
+ */
+ void setNumberFilter(const QString& from, const QString& to);
+
+ /**
+ * This method is used to check a specific transaction against the filter.
+ * The transaction will match the whole filter, if all specified filters
+ * match. If the filter is cleared using the clear() method, any transaciton
+ * matches.
+ *
+ * @param transaction A transaction
+ *
+ * @retval true The transaction matches the filter set
+ * @retval false The transaction does not match at least one of
+ * the filters in the filter set
+ */
+ bool match(const MyMoneyTransaction& transaction);
+
+ /**
+ * This method is used to check a specific split against the
+ * text filter. The split will match if all specified and
+ * checked filters match. If the filter is cleared using the clear()
+ * method, any split matches.
+ *
+ * @param sp pointer to the split to be checked
+ *
+ * @retval true The split matches the filter set
+ * @retval false The split does not match at least one of
+ * the filters in the filter set
+ */
+ bool matchText(const MyMoneySplit * const sp) const;
+
+ /**
+ * This method is used to check a specific split against the
+ * amount filter. The split will match if all specified and
+ * checked filters match. If the filter is cleared using the clear()
+ * method, any split matches.
+ *
+ * @param sp pointer to the split to be checked
+ *
+ * @retval true The split matches the filter set
+ * @retval false The split does not match at least one of
+ * the filters in the filter set
+ */
+ bool matchAmount(const MyMoneySplit * const sp) const;
+
+ /**
+ * Convenience method which actually returns matchText(sp) && matchAmount(sp).
+ */
+ bool match(const MyMoneySplit * const sp) const;
+
+ /**
+ * This method is used to switch the amount of splits reported
+ * by matchingSplits(). If the argument @p report is @p true (the default
+ * if no argument specified) then matchingSplits() will return all
+ * matching splits of the transaction. If @p report is set to @p false,
+ * then only the very first matching split will be returned by
+ * matchingSplits().
+ *
+ * @param report controls the behaviour of matchingsSplits() as explained above.
+ */
+ void setReportAllSplits(const bool report = true);
+
+ void setConsiderCategory(const bool check = true);
+
+ /**
+ * This method returns a list of the matching splits for the filter.
+ * If m_reportAllSplits is set to false, then only the very first
+ * split will be returned. Use setReportAllSplits() to change the
+ * behaviour.
+ *
+ * @return reference list of MyMoneySplit objects containing the
+ * matching splits. If multiple splits match, only the first
+ * one will be returned.
+ *
+ * @note an empty list will be returned, if the filter only required
+ * to check the data contained in the MyMoneyTransaction
+ * object (e.g. posting-date, state, etc.).
+ *
+ * @note The constructors set m_reportAllSplits differently. Please
+ * see the documentation of the constructors MyMoneyTransactionFilter()
+ * and MyMoneyTransactionFilter(const QString&) for details.
+ */
+ const QValueList<MyMoneySplit>& matchingSplits(void) const;
+
+ /**
+ * This method returns the from date set in the filter. If
+ * no value has been set up for this filter, then QDate() is
+ * returned.
+ *
+ * @return returns m_fromDate
+ */
+ const QDate fromDate(void) const { return m_fromDate; };
+
+ /**
+ * This method returns the to date set in the filter. If
+ * no value has been set up for this filter, then QDate() is
+ * returned.
+ *
+ * @return returns m_toDate
+ */
+ const QDate toDate(void) const { return m_toDate; };
+
+ /**
+ * This method is used to return information about the
+ * presence of a specific category in the category filter.
+ * The category in question is included in the filter set,
+ * if it has been set or no category filter is set.
+ *
+ * @param cat id of category in question
+ * @return true if category is in filter set, false otherwise
+ */
+ bool includesCategory( const QString& cat ) const;
+
+ /**
+ * This method is used to return information about the
+ * presence of a specific account in the account filter.
+ * The account in question is included in the filter set,
+ * if it has been set or no account filter is set.
+ *
+ * @param acc id of account in question
+ * @return true if account is in filter set, false otherwise
+ */
+ bool includesAccount( const QString& acc ) const;
+
+ /**
+ * This method is used to return information about the
+ * presence of a specific payee in the account filter.
+ * The payee in question is included in the filter set,
+ * if it has been set or no account filter is set.
+ *
+ * @param pye id of payee in question
+ * @return true if payee is in filter set, false otherwise
+ */
+ bool includesPayee( const QString& pye ) const;
+
+ /**
+ * This method is used to return information about the
+ * presence of a date filter.
+ *
+ * @param from result value for the beginning of the date range
+ * @param to result value for the end of the date range
+ * @return true if an amount filter is set
+ */
+ bool dateFilter( QDate& from, QDate& to ) const;
+
+ /**
+ * This method is used to return information about the
+ * presence of an amount filter.
+ *
+ * @param from result value for the low end of the amount range
+ * @param to result value for the high end of the amount range
+ * @return true if an amount filter is set
+ */
+ bool amountFilter( MyMoneyMoney& from, MyMoneyMoney& to ) const;
+
+ /**
+ * This method is used to return information about the
+ * presence of an number filter.
+ *
+ * @param from result value for the low end of the number range
+ * @param to result value for the high end of the number range
+ * @return true if a number filter is set
+ */
+ bool numberFilter( QString& from, QString& to ) const;
+
+ /**
+ * This method returns whether a payee filter has been set,
+ * and if so, it returns all the payees set in the filter.
+ *
+ * @param list list to append payees into
+ * @return return true if a payee filter has been set
+ */
+ bool payees(QStringList& list) const;
+
+ /**
+ * This method returns whether an account filter has been set,
+ * and if so, it returns all the accounts set in the filter.
+ *
+ * @param list list to append accounts into
+ * @return return true if an account filter has been set
+ */
+ bool accounts(QStringList& list) const;
+
+ /**
+ * This method returns whether a category filter has been set,
+ * and if so, it returns all the categories set in the filter.
+ *
+ * @param list list to append categories into
+ * @return return true if a category filter has been set
+ */
+ bool categories(QStringList& list) const;
+
+ /**
+ * This method returns whether a type filter has been set,
+ * and if so, it returns the first type in the filter.
+ *
+ * @param i int to replace with first type filter, untouched otherwise
+ * @return return true if a type filter has been set
+ */
+ bool firstType(int& i) const;
+
+ bool types(QValueList<int>& list) const;
+
+ /**
+ * This method returns whether a state filter has been set,
+ * and if so, it returns the first state in the filter.
+ *
+ * @param i reference to int to replace with first state filter, untouched otherwise
+ * @return return true if a state filter has been set
+ */
+ bool firstState(int& i) const;
+
+ bool states(QValueList<int>& list) const;
+ /**
+ * This method returns whether a text filter has been set,
+ * and if so, it returns the text filter.
+ *
+ * @param text regexp to replace with text filter, or blank if none set
+ * @return return true if a text filter has been set
+ */
+ bool textFilter(QRegExp& text) const;
+
+ /**
+ * This method returns whether the text filter should return
+ * that DO NOT contain the text
+ */
+ bool isInvertingText(void) const {return m_invertText;};
+
+ /**
+ * This method translates a plain-language date range into QDate
+ * start & end
+ *
+ * @param range Plain-language range of dates, e.g. 'CurrentYear'
+ * @param start QDate will be set to corresponding to the first date in @p range
+ * @param end QDate will be set to corresponding to the last date in @p range
+ * @return return true if a range was successfully set, or false if @p range was invalid
+ */
+ static bool translateDateRange(dateOptionE range, QDate& start, QDate& end);
+
+ static void setFiscalYearStart(int firstMonth, int firstDay);
+
+ FilterSet filterSet(void) const { return m_filterSet; };
+
+ /**
+ * This member removes all references to object identified by @p id. Used
+ * to remove objects which are about to be removed from the engine.
+ */
+ void removeReference(const QString& id);
+
+private:
+ /**
+ * This is a conversion tool from MyMoneySplit::reconcileFlagE
+ * to MyMoneyTransactionFilter::stateE types
+ *
+ * @param split reference to split in question
+ *
+ * @return converted reconcile flag of the split passed as parameter
+ */
+ int splitState(const MyMoneySplit& split) const;
+
+ /**
+ * This is a conversion tool from MyMoneySplit::action
+ * to MyMoneyTransactionFilter::typeE types
+ *
+ * @param t reference to transaction
+ * @param split reference to split in question
+ *
+ * @return converted action of the split passed as parameter
+ */
+ int splitType(const MyMoneyTransaction& t, const MyMoneySplit& split) const;
+
+ /**
+ * This method checks if a transaction is valid or not. A transaction
+ * is considered valid, if the sum of all splits is zero, invalid otherwise.
+ *
+ * @param transaction reference to transaction to be checked
+ * @retval valid transaction is valid
+ * @retval invalid transaction is invalid
+ */
+ validityOptionE validTransaction(const MyMoneyTransaction& transaction) const;
+
+protected:
+ FilterSet m_filterSet;
+ bool m_reportAllSplits;
+ bool m_considerCategory;
+
+ QRegExp m_text;
+ bool m_invertText;
+ QAsciiDict<char> m_accounts;
+ QAsciiDict<char> m_payees;
+ QAsciiDict<char> m_categories;
+ QIntDict<char> m_states;
+ QIntDict<char> m_types;
+ QIntDict<char> m_validity;
+ QString m_fromNr, m_toNr;
+ QDate m_fromDate, m_toDate;
+ MyMoneyMoney m_fromAmount, m_toAmount;
+ QValueList<MyMoneySplit> m_matchingSplits;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/mymoneytransactiontest.cpp b/kmymoney2/mymoney/mymoneytransactiontest.cpp
new file mode 100644
index 0000000..11af6b3
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneytransactiontest.cpp
@@ -0,0 +1,628 @@
+/***************************************************************************
+ mymoneytransactiontest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneytransactiontest.h"
+
+MyMoneyTransactionTest::MyMoneyTransactionTest ()
+{
+}
+
+
+void MyMoneyTransactionTest::setUp () {
+ m = new MyMoneyTransaction();
+}
+
+void MyMoneyTransactionTest::tearDown () {
+ delete m;
+}
+
+void MyMoneyTransactionTest::testEmptyConstructor() {
+ CPPUNIT_ASSERT(m->id().isEmpty());
+ CPPUNIT_ASSERT(m->entryDate() == QDate());
+ CPPUNIT_ASSERT(m->memo().isEmpty());
+ CPPUNIT_ASSERT(m->splits().count() == 0);
+}
+
+void MyMoneyTransactionTest::testSetFunctions() {
+ m->setMemo("Memo");
+ m->setPostDate(QDate(1,2,3));
+
+ CPPUNIT_ASSERT(m->postDate() == QDate(1,2,3));
+ CPPUNIT_ASSERT(m->memo() == "Memo");
+}
+
+void MyMoneyTransactionTest::testConstructor() {
+ testSetFunctions();
+ MyMoneyTransaction a("ID", *m);
+
+ CPPUNIT_ASSERT(a.id() == "ID");
+ CPPUNIT_ASSERT(a.entryDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(a.memo() == "Memo");
+ CPPUNIT_ASSERT(a.postDate() == QDate(1,2,3));
+}
+
+void MyMoneyTransactionTest::testCopyConstructor() {
+ testConstructor();
+ MyMoneyTransaction a("ID", *m);
+ a.setValue("Key", "Value");
+
+ MyMoneyTransaction n(a);
+
+ CPPUNIT_ASSERT(n.id() == "ID");
+ CPPUNIT_ASSERT(n.entryDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(n.memo() == "Memo");
+ CPPUNIT_ASSERT(n.postDate() == QDate(1,2,3));
+ CPPUNIT_ASSERT(n.value("Key") == "Value");
+}
+
+void MyMoneyTransactionTest::testAssignmentConstructor() {
+ testConstructor();
+ MyMoneyTransaction a("ID", *m);
+ a.setValue("Key", "Value");
+
+ MyMoneyTransaction n;
+
+ n = a;
+
+ CPPUNIT_ASSERT(n.id() == "ID");
+ CPPUNIT_ASSERT(n.entryDate() == QDate::currentDate());
+ CPPUNIT_ASSERT(n.memo() == "Memo");
+ CPPUNIT_ASSERT(n.postDate() == QDate(1,2,3));
+ CPPUNIT_ASSERT(n.value("Key") == "Value");
+}
+
+void MyMoneyTransactionTest::testEquality() {
+ testConstructor();
+
+ MyMoneyTransaction n(*m);
+
+ CPPUNIT_ASSERT(n == *m);
+ CPPUNIT_ASSERT(!(n != *m));
+}
+
+void MyMoneyTransactionTest::testInequality() {
+ testConstructor();
+
+ MyMoneyTransaction n(*m);
+
+ n.setPostDate(QDate(1,1,1));
+ CPPUNIT_ASSERT(!(n == *m));
+ CPPUNIT_ASSERT(n != *m);
+
+ n = *m;
+ n.setValue("key", "value");
+ CPPUNIT_ASSERT(!(n == *m));
+ CPPUNIT_ASSERT(n != *m);
+}
+
+void MyMoneyTransactionTest::testAddSplits() {
+ m->setId("TestID");
+ MyMoneySplit split1, split2;
+ split1.setAccountId("A000001");
+ split2.setAccountId("A000002");
+ split1.setValue(100);
+ split2.setValue(200);
+
+ try {
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == false);
+ CPPUNIT_ASSERT(m->accountReferenced("A000002") == false);
+ m->addSplit(split1);
+ m->addSplit(split2);
+ CPPUNIT_ASSERT(m->splitCount() == 2);
+ CPPUNIT_ASSERT(m->splits()[0].accountId() == "A000001");
+ CPPUNIT_ASSERT(m->splits()[1].accountId() == "A000002");
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == true);
+ CPPUNIT_ASSERT(m->accountReferenced("A000002") == true);
+ CPPUNIT_ASSERT(m->splits()[0].id() == "S0001");
+ CPPUNIT_ASSERT(m->splits()[1].id() == "S0002");
+ CPPUNIT_ASSERT(split1.id() == "S0001");
+ CPPUNIT_ASSERT(split2.id() == "S0002");
+ CPPUNIT_ASSERT(m->splits()[0].transactionId() == "TestID");
+ CPPUNIT_ASSERT(m->splits()[1].transactionId() == "TestID");
+ CPPUNIT_ASSERT(split1.transactionId() == "TestID");
+ CPPUNIT_ASSERT(split2.transactionId() == "TestID");
+
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ // try to add split with assigned ID
+ try {
+ m->addSplit(split1);
+ CPPUNIT_FAIL("Exception expected!");
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyTransactionTest::testModifySplits() {
+ testAddSplits();
+ MyMoneySplit split;
+
+ split = m->splits()[0];
+ split.setAccountId("A000003");
+ split.setId("S00000000");
+
+ // this one should fail, because the ID is invalid
+ try {
+ m->modifySplit(split);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ // set id to correct value, and check that it worked
+ split.setId("S0001");
+ try {
+ m->modifySplit(split);
+ CPPUNIT_ASSERT(m->splitCount() == 2);
+ CPPUNIT_ASSERT(m->splits()[0].accountId() == "A000003");
+ CPPUNIT_ASSERT(m->splits()[1].accountId() == "A000002");
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == false);
+ CPPUNIT_ASSERT(m->accountReferenced("A000002") == true);
+ CPPUNIT_ASSERT(m->splits()[0].id() == "S0001");
+ CPPUNIT_ASSERT(m->splits()[1].id() == "S0002");
+
+ CPPUNIT_ASSERT(split.id() == "S0001");
+ CPPUNIT_ASSERT(split.accountId() == "A000003");
+
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+}
+
+void MyMoneyTransactionTest::testDeleteSplits() {
+ testAddSplits();
+ MyMoneySplit split;
+
+ // add a third split
+ split.setAccountId("A000003");
+ split.setValue(MyMoneyMoney(300));
+ try {
+ m->addSplit(split);
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+
+ split.setId("S00000000");
+ // this one should fail, because the ID is invalid
+ try {
+ m->modifySplit(split);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ // set id to correct value, and check that it worked
+ split.setId("S0002");
+ try {
+ m->removeSplit(split);
+ CPPUNIT_ASSERT(m->splitCount() == 2);
+ CPPUNIT_ASSERT(m->splits()[0].accountId() == "A000001");
+ CPPUNIT_ASSERT(m->accountReferenced("A000002") == false);
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == true);
+ CPPUNIT_ASSERT(m->accountReferenced("A000003") == true);
+ CPPUNIT_ASSERT(m->splits()[0].id() == "S0001");
+
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+
+ // set id to the other correct value, and check that it worked
+ split.setId("S0003");
+ try {
+ m->removeSplit(split);
+ CPPUNIT_ASSERT(m->splitCount() == 1);
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == true);
+ CPPUNIT_ASSERT(m->accountReferenced("A000003") == false);
+ CPPUNIT_ASSERT(m->splits()[0].id() == "S0001");
+
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+}
+
+void MyMoneyTransactionTest::testDeleteAllSplits() {
+ testAddSplits();
+
+ try {
+ m->removeSplits();
+ CPPUNIT_ASSERT(m->splitCount() == 0);
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+}
+
+void MyMoneyTransactionTest::testExtractSplit() {
+ testAddSplits();
+ MyMoneySplit split;
+
+ // this one should fail, as the account is not referenced by
+ // any split in the transaction
+ try {
+ split = m->splitByAccount(QString("A000003"));
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ // this one should be found
+ try {
+ split = m->splitByAccount(QString("A000002"));
+ CPPUNIT_ASSERT(split.id() == "S0002");
+
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+
+ // this one should be found also
+ try {
+ split = m->splitByAccount(QString("A000002"), false);
+ CPPUNIT_ASSERT(split.id() == "S0001");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL("Unexpected exception!");
+ delete e;
+ }
+}
+
+void MyMoneyTransactionTest::testSplitSum() {
+ CPPUNIT_ASSERT(m->splitSum().isZero());
+
+ testAddSplits();
+
+ MyMoneySplit s1, s2;
+
+ s1 = m->splits()[0];
+ s1.setValue(0);
+ s2 = m->splits()[1];
+ s2.setValue(0);
+
+ m->modifySplit(s1);
+ m->modifySplit(s2);
+ CPPUNIT_ASSERT(m->splitSum().isZero());
+
+ s1.setValue(1234);
+ m->modifySplit(s1);
+ CPPUNIT_ASSERT(m->splitSum() == MyMoneyMoney(1234));
+
+ s2.setValue(-1234);
+ m->modifySplit(s2);
+ CPPUNIT_ASSERT(m->splitSum().isZero());
+
+ s1.setValue(5678);
+ m->modifySplit(s1);
+ CPPUNIT_ASSERT(m->splitSum() == MyMoneyMoney(4444));
+}
+
+void MyMoneyTransactionTest::testIsLoanPayment() {
+ testAddSplits();
+ CPPUNIT_ASSERT(m->isLoanPayment() == false);
+
+ MyMoneySplit s1, s2;
+ s1 = m->splits()[0];
+ s2 = m->splits()[1];
+
+ s1.setAction(MyMoneySplit::ActionAmortization);
+ m->modifySplit(s1);
+ CPPUNIT_ASSERT(m->isLoanPayment() == true);
+ s1.setAction(MyMoneySplit::ActionWithdrawal);
+ m->modifySplit(s1);
+ CPPUNIT_ASSERT(m->isLoanPayment() == false);
+
+ s2.setAction(MyMoneySplit::ActionAmortization);
+ m->modifySplit(s2);
+ CPPUNIT_ASSERT(m->isLoanPayment() == true);
+ s2.setAction(MyMoneySplit::ActionWithdrawal);
+ m->modifySplit(s2);
+ CPPUNIT_ASSERT(m->isLoanPayment() == false);
+}
+
+void MyMoneyTransactionTest::testAddDuplicateAccount() {
+ testAddSplits();
+
+ MyMoneySplit split1, split2;
+ split1.setAccountId("A000001");
+ split2.setAccountId("A000002");
+ split1.setValue(100);
+ split2.setValue(200);
+
+ try {
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == true);
+ CPPUNIT_ASSERT(m->accountReferenced("A000002") == true);
+ m->addSplit(split1);
+ m->addSplit(split2);
+ CPPUNIT_ASSERT(m->splitCount() == 2);
+ CPPUNIT_ASSERT(m->splits()[0].accountId() == "A000001");
+ CPPUNIT_ASSERT(m->splits()[1].accountId() == "A000002");
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == true);
+ CPPUNIT_ASSERT(m->accountReferenced("A000002") == true);
+ CPPUNIT_ASSERT(m->splits()[0].id() == "S0001");
+ CPPUNIT_ASSERT(m->splits()[1].id() == "S0002");
+ CPPUNIT_ASSERT(split1.id() == "S0001");
+ CPPUNIT_ASSERT(split2.id() == "S0002");
+
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ CPPUNIT_ASSERT(m->splits()[0].value() == MyMoneyMoney(200));
+ CPPUNIT_ASSERT(m->splits()[1].value() == MyMoneyMoney(400));
+}
+
+void MyMoneyTransactionTest::testModifyDuplicateAccount() {
+ testAddSplits();
+ MyMoneySplit split;
+
+ split = m->splitByAccount(QString("A000002"));
+ split.setAccountId("A000001");
+ try {
+ m->modifySplit(split);
+ CPPUNIT_ASSERT(m->splitCount() == 1);
+ CPPUNIT_ASSERT(m->accountReferenced("A000001") == true);
+ CPPUNIT_ASSERT(m->splits()[0].value() == MyMoneyMoney(300));
+
+ } catch(MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+void MyMoneyTransactionTest::testWriteXML() {
+ MyMoneyTransaction t;
+ t.setPostDate(QDate(2001,12,28));
+ t.setEntryDate(QDate(2003,9,29));
+ t.setId("T000000000000000001");
+ t.setMemo("Wohnung:Miete");
+ t.setCommodity("EUR");
+ t.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(MyMoneyMoney(96379, 100));
+ s.setValue(MyMoneyMoney(96379, 100));
+ s.setAction(MyMoneySplit::ActionWithdrawal);
+ s.setAccountId("A000076");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ s.setBankID("SPID");
+ t.addSplit(s);
+
+ QDomDocument doc("TEST");
+ QDomElement el = doc.createElement("TRANSACTION-CONTAINER");
+ doc.appendChild(el);
+ t.writeXML(doc, el);
+
+ QString ref = QString(
+ "<!DOCTYPE TEST>\n"
+ "<TRANSACTION-CONTAINER>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"T000000000000000001\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Withdrawal\" bankid=\"SPID\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" id=\"S0001\" account=\"A000076\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ "</TRANSACTION-CONTAINER>\n"
+
+ );
+
+ CPPUNIT_ASSERT(doc.toString() == ref);
+}
+
+void MyMoneyTransactionTest::testReadXML() {
+ MyMoneyTransaction t;
+
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<TRANSACTION-CONTAINER>\n"
+ " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"T000000000000000001\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Withdrawal\" bankid=\"SPID\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANSACTION>\n"
+ "</TRANSACTION-CONTAINER>\n"
+ );
+
+ QString ref_false = QString(
+ "<!DOCTYPE TEST>\n"
+ "<TRANSACTION-CONTAINER>\n"
+ " <TRANS-ACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"T000000000000000001\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Withdrawal\" bankid=\"SPID\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
+ " </SPLITS>\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"key\" value=\"value\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </TRANS-ACTION>\n"
+ "</TRANSACTION-CONTAINER>\n"
+ );
+
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_false);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ t = MyMoneyTransaction(node);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ t.setValue("key", "VALUE");
+ try {
+ t = MyMoneyTransaction(node);
+ CPPUNIT_ASSERT(t.m_postDate == QDate(2001,12,28));
+ CPPUNIT_ASSERT(t.m_entryDate == QDate(2003,9,29));
+ CPPUNIT_ASSERT(t.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(t.m_memo == "Wohnung:Miete");
+ CPPUNIT_ASSERT(t.m_commodity == "EUR");
+ CPPUNIT_ASSERT(t.pairs().count() == 1);
+ CPPUNIT_ASSERT(t.value("key") == "value");
+ CPPUNIT_ASSERT(t.splits().count() == 1);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyTransactionTest::testReadXMLEx()
+{
+ MyMoneyTransaction t;
+
+ QString ref_ok = QString(
+ "<!DOCTYPE TEST>\n"
+ "<TRANSACTION-CONTAINER>\n"
+ "<TRANSACTION postdate=\"2010-03-05\" memo=\"\" id=\"T000000000000004189\" commodity=\"EUR\" entrydate=\"2010-03-08\" >\n"
+ " <SPLITS>\n"
+ " <SPLIT payee=\"P000010\" reconciledate=\"\" shares=\"-125000/100\" action=\"Transfer\" bankid=\"A000076-2010-03-05-b6850c0-1\" number=\"\" reconcileflag=\"1\" memo=\"UMBUCHUNG\" value=\"-125000/100\" id=\"S0001\" account=\"A000076\" >\n"
+ " <KEYVALUEPAIRS>\n"
+ " <PAIR key=\"kmm-match-split\" value=\"S0002\" />\n"
+ " <PAIR key=\"kmm-matched-tx\" value=\"&amp;lt;!DOCTYPE MATCH>\n"
+ " &amp;lt;CONTAINER>\n"
+ " &amp;lt;TRANSACTION postdate=&quot;2010-03-05&quot; memo=&quot;UMBUCHUNG&quot; id=&quot;&quot; commodity=&quot;EUR&quot; entrydate=&quot;2010-03-08&quot; >\n"
+ " &amp;lt;SPLITS>\n"
+ " &amp;lt;SPLIT payee=&quot;P000010&quot; reconciledate=&quot;&quot; shares=&quot;125000/100&quot; action=&quot;Transfer&quot; bankid=&quot;&quot; number=&quot;&quot; reconcileflag=&quot;0&quot; memo=&quot;UMBUCHUNG&quot; value=&quot;125000/100&quot; id=&quot;S0001&quot; account=&quot;A000087&quot; />\n"
+ " &amp;lt;SPLIT payee=&quot;P000010&quot; reconciledate=&quot;&quot; shares=&quot;-125000/100&quot; action=&quot;&quot; bankid=&quot;A000076-2010-03-05-b6850c0-1&quot; number=&quot;&quot; reconcileflag=&quot;0&quot; memo=&quot;UMBUCHUNG&quot; value=&quot;-125000/100&quot; id=&quot;S0002&quot; account=&quot;A000076&quot; />\n"
+ " &amp;lt;/SPLITS>\n"
+ " &amp;lt;KEYVALUEPAIRS>\n"
+ " &amp;lt;PAIR key=&quot;Imported&quot; value=&quot;true&quot; />\n"
+ " &amp;lt;/KEYVALUEPAIRS>\n"
+ " &amp;lt;/TRANSACTION>\n"
+ " &amp;lt;/CONTAINER>\n"
+ "\" />\n"
+ " <PAIR key=\"kmm-orig-memo\" value=\"\" />\n"
+ " </KEYVALUEPAIRS>\n"
+ " </SPLIT>\n"
+ " <SPLIT payee=\"P000010\" reconciledate=\"\" shares=\"125000/100\" action=\"Transfer\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"125000/100\" id=\"S0002\" account=\"A000087\" />\n"
+ " </SPLITS>\n"
+ "</TRANSACTION>\n"
+ "</TRANSACTION-CONTAINER>\n"
+ );
+ QDomDocument doc;
+ QDomElement node;
+ doc.setContent(ref_ok);
+ node = doc.documentElement().firstChild().toElement();
+
+ try {
+ t = MyMoneyTransaction(node);
+ CPPUNIT_ASSERT(t.pairs().count() == 0);
+ CPPUNIT_ASSERT(t.splits().count() == 2);
+ CPPUNIT_ASSERT(t.splits()[0].pairs().count() == 3);
+ CPPUNIT_ASSERT(t.splits()[1].pairs().count() == 0);
+ CPPUNIT_ASSERT(t.splits()[0].isMatched());
+
+ MyMoneyTransaction ti = t.splits()[0].matchedTransaction();
+ CPPUNIT_ASSERT(ti.pairs().count() == 1);
+ CPPUNIT_ASSERT(ti.isImported());
+ CPPUNIT_ASSERT(ti.splits().count() == 2);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+}
+
+void MyMoneyTransactionTest::testHasReferenceTo()
+{
+ MyMoneyTransaction t;
+ t.setPostDate(QDate(2001,12,28));
+ t.setEntryDate(QDate(2003,9,29));
+ t.setId("T000000000000000001");
+ t.setMemo("Wohnung:Miete");
+ t.setCommodity("EUR");
+ t.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(MyMoneyMoney(96379, 100));
+ s.setValue(MyMoneyMoney(96379, 100));
+ s.setAction(MyMoneySplit::ActionWithdrawal);
+ s.setAccountId("A000076");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ t.addSplit(s);
+
+ CPPUNIT_ASSERT(t.hasReferenceTo("EUR") == true);
+ CPPUNIT_ASSERT(t.hasReferenceTo("P000001") == true);
+ CPPUNIT_ASSERT(t.hasReferenceTo("A000076") == true);
+}
+
+void MyMoneyTransactionTest::testAutoCalc()
+{
+ CPPUNIT_ASSERT(m->hasAutoCalcSplit() == false);
+ testAddSplits();
+ CPPUNIT_ASSERT(m->hasAutoCalcSplit() == false);
+ MyMoneySplit split;
+
+ split = m->splits()[0];
+ split.setShares(MyMoneyMoney::autoCalc);
+ split.setValue(MyMoneyMoney::autoCalc);
+ m->modifySplit(split);
+
+ CPPUNIT_ASSERT(m->hasAutoCalcSplit() == true);
+}
+
+void MyMoneyTransactionTest::testIsStockSplit()
+{
+ CPPUNIT_ASSERT(m->isStockSplit() == false);
+ testAddSplits();
+ CPPUNIT_ASSERT(m->isStockSplit() == false);
+ m->removeSplits();
+ MyMoneySplit s;
+ s.setShares(MyMoneyMoney(1,2));
+ s.setAction(MyMoneySplit::ActionSplitShares);
+ s.setAccountId("A0001");
+ m->addSplit(s);
+ CPPUNIT_ASSERT(m->isStockSplit() == true);
+}
+
+void MyMoneyTransactionTest::testAddMissingAccountId()
+{
+ MyMoneySplit s;
+ s.setShares(MyMoneyMoney(1,2));
+ try {
+ m->addSplit(s);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyTransactionTest::testModifyMissingAccountId()
+{
+ testAddSplits();
+ MyMoneySplit s = m->splits()[0];
+ s.setAccountId(QString());
+
+ try {
+ m->modifySplit(s);
+ CPPUNIT_FAIL("Missing expected exception");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
diff --git a/kmymoney2/mymoney/mymoneytransactiontest.h b/kmymoney2/mymoney/mymoneytransactiontest.h
new file mode 100644
index 0000000..c2bb0da
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneytransactiontest.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ mymoneytransactiontest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYTRANSACTIONTEST_H__
+#define __MYMONEYTRANSACTIONTEST_H__
+
+/*
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestSuite.h>
+*/
+#include <cppunit/extensions/HelperMacros.h>
+#include "autotest.h"
+
+#define private public
+#define protected public
+#include "mymoneytransaction.h"
+#undef private
+
+class MyMoneyTransactionTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyTransactionTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testConstructor);
+ CPPUNIT_TEST(testCopyConstructor);
+ CPPUNIT_TEST(testAssignmentConstructor);
+ CPPUNIT_TEST(testAddSplits);
+ CPPUNIT_TEST(testModifySplits);
+ CPPUNIT_TEST(testDeleteSplits);
+ CPPUNIT_TEST(testDeleteAllSplits);
+ CPPUNIT_TEST(testEquality);
+ CPPUNIT_TEST(testInequality);
+ CPPUNIT_TEST(testExtractSplit);
+ CPPUNIT_TEST(testSplitSum);
+ CPPUNIT_TEST(testIsLoanPayment);
+ CPPUNIT_TEST(testWriteXML);
+ CPPUNIT_TEST(testReadXML);
+ CPPUNIT_TEST(testReadXMLEx);
+ CPPUNIT_TEST(testAutoCalc);
+ CPPUNIT_TEST(testHasReferenceTo);
+ CPPUNIT_TEST(testIsStockSplit);
+ CPPUNIT_TEST(testAddMissingAccountId);
+ CPPUNIT_TEST(testModifyMissingAccountId);
+#if 0
+ CPPUNIT_TEST(testAddDuplicateAccount);
+ CPPUNIT_TEST(testModifyDuplicateAccount);
+#endif
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyTransaction *m;
+
+public:
+ MyMoneyTransactionTest ();
+
+ void setUp ();
+ void tearDown ();
+ void testEmptyConstructor();
+ void testSetFunctions();
+ void testConstructor();
+ void testCopyConstructor();
+ void testAssignmentConstructor();
+ void testEquality();
+ void testInequality();
+ void testAddSplits();
+ void testModifySplits();
+ void testDeleteSplits();
+ void testExtractSplit();
+ void testDeleteAllSplits();
+ void testSplitSum();
+ void testIsLoanPayment();
+ void testAddDuplicateAccount();
+ void testModifyDuplicateAccount();
+ void testWriteXML();
+ void testReadXML();
+ void testReadXMLEx();
+ void testAutoCalc();
+ void testHasReferenceTo();
+ void testIsStockSplit();
+ void testAddMissingAccountId();
+ void testModifyMissingAccountId();
+};
+#endif
diff --git a/kmymoney2/mymoney/mymoneyutils.cpp b/kmymoney2/mymoney/mymoneyutils.cpp
new file mode 100644
index 0000000..3739f9a
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyutils.cpp
@@ -0,0 +1,339 @@
+/***************************************************************************
+ mymoneyutils.cpp - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <iostream>
+
+#include "mymoneyutils.h"
+#include "mymoneyaccount.h"
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstdlib>
+
+#include <qregexp.h>
+
+#ifdef _CHECK_MEMORY
+
+#undef new
+#undef _CheckMemory_Leak
+#undef _CheckMemory_FreeAll
+
+_CheckMemory chkmem;
+bool enable=false;
+
+_CheckMemoryEntry::_CheckMemoryEntry(void *p, int line, size_t size, const char *file)
+ : m_p(p), m_line(line), m_size(size), m_file(file)
+{
+}
+
+_CheckMemoryEntry::_CheckMemoryEntry()
+ : m_p(0), m_line(0), m_size(0)
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+_CheckMemory::_CheckMemory()
+{
+ outfunc = (_CheckMemoryOutFunc *)NULL;
+}
+
+_CheckMemory::_CheckMemory(_CheckMemoryOutFunc *out)
+{
+ outfunc = out;
+}
+
+_CheckMemory::~_CheckMemory()
+{
+}
+
+_CheckMemoryOutFunc *_CheckMemory::SetOutFunc(_CheckMemoryOutFunc *out)
+{
+ _CheckMemoryOutFunc *old;
+ old = outfunc;
+ outfunc = out;
+ return old;
+}
+
+void _CheckMemory::Output(const char *fmt,...)
+{
+ va_list args;
+ char buf[128];
+ va_start(args,fmt);
+ if(outfunc) {
+ vsprintf(buf,fmt,args);
+ outfunc(buf);
+ }
+ else {
+ vfprintf(stderr,fmt,args);
+ putc('\n', stderr);
+ }
+ va_end(args);
+}
+
+int _CheckMemory::TableCount(void)
+{
+ return table.size();
+}
+
+bool _CheckMemory::CheckMemoryLeak(bool freeall)
+{
+ bool d = false;
+ size_t total = 0;
+ int freec = 0;
+ CheckMemoryTable::ConstIterator it;
+
+ for(it = table.begin(); it != table.end(); ++it) {
+ if((*it).pointer() != 0) {
+ total += (*it).size();
+ freec++;
+ if(d == false) {
+ Output("CheckMemory++: CheckMemoryLeak: Memory leak detected!");
+ Output("Position |Size(bytes) |Allocated at");
+ d=true;
+ }
+ if(d==true)
+ Output("%p |%-13d|%s:%d",(*it).pointer(),(int)(*it).size(),(*it).file(),(*it).line());
+ }
+ }
+ if(d == true)
+ Output("You have forgotten to free %d object(s), %d bytes of memory.",freec, (int)total);
+ else
+ Output("CheckMemory++: CheckMemoryLeak: No memory leak detected.");
+ if(freeall == true)
+ FreeAll();
+ return true;
+}
+
+void _CheckMemory::FreeAll()
+{
+ size_t total=0;
+ int freec=0;
+ CheckMemoryTable::Iterator it;
+
+ for(it = table.begin(); it != table.end(); it = table.begin()) {
+ if((*it).pointer() != 0) {
+ total += (*it).size();
+ freec++;
+ Output("CheckMemory++: FreeAll: freed %d bytes of memory at %p.",(int)(*it).size(),(*it).pointer());
+ free((*it).pointer());
+ }
+ table.remove(it);
+ }
+ Output("CheckMemory++: FreeAll: Totally freed %d objects, %d bytes of memory.",freec,(int)total);
+}
+
+void _CheckMemory_Init(_CheckMemoryOutFunc *out)
+{
+ if(enable!=true) {
+ chkmem.Restart();
+ chkmem.SetOutFunc(out);
+ enable=true;
+ }
+}
+
+void _CheckMemory_End()
+{
+ if(enable!=false) {
+ chkmem.Restart();
+ chkmem.SetOutFunc(NULL);
+ enable=false;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void *operator new(size_t s,const char *file,int line) throw()
+{
+ void *p = malloc(s);
+
+ if(p == NULL) throw;
+ if(enable==true) {
+ _CheckMemoryEntry entry(p, line, s, file);
+ chkmem.table[p] = entry;
+ }
+ return p;
+}
+
+void * operator new [] (size_t s,const char *file,int line) throw()
+{
+ void *p = malloc(s);
+
+ if(p == NULL) throw;
+ if(enable==true) {
+ _CheckMemoryEntry entry(p, line, s, file);
+ chkmem.table[p] = entry;
+ }
+ return p;
+}
+
+void operator delete(void *p) throw()
+{
+ if(enable==true) {
+ CheckMemoryTable::Iterator it;
+ it = chkmem.table.find(p);
+ if(it != chkmem.table.end()) {
+ chkmem.table.remove(it);
+ }
+ }
+ free(p);
+}
+
+void operator delete [] (void *p) throw()
+{
+ if(enable==true) {
+ CheckMemoryTable::Iterator it;
+ it = chkmem.table.find(p);
+ if(it != chkmem.table.end()) {
+ chkmem.table.remove(it);
+ }
+ }
+ free(p);
+}
+
+#endif // _CHECK_MEMORY
+
+QString MyMoneyUtils::getFileExtension(QString strFileName)
+{
+ QString strTemp;
+ if(!strFileName.isEmpty())
+ {
+ //find last . delminator
+ int nLoc = strFileName.findRev('.');
+ if(nLoc != -1)
+ {
+ strTemp = strFileName.right(strFileName.length() - (nLoc + 1));
+ return strTemp.upper();
+ }
+ }
+ return strTemp;
+}
+
+int MyMoneyTracer::m_indentLevel = 0;
+int MyMoneyTracer::m_onoff = 0;
+
+MyMoneyTracer::MyMoneyTracer(const char* name)
+{
+ if(m_onoff) {
+ QRegExp exp("(.*)::(.*)");
+ if(exp.search(name) != -1) {
+ m_className = exp.cap(1);
+ m_memberName = exp.cap(2);
+ } else {
+ m_className = QString(name);
+ m_memberName = QString();
+ }
+ QString indent;
+ indent.fill(' ', m_indentLevel);
+ std::cerr << indent.latin1() << "ENTER: " << m_className.latin1() << "::" << m_memberName.latin1() << std::endl;
+ }
+ m_indentLevel += 2;
+}
+
+MyMoneyTracer::MyMoneyTracer(const QString& className, const QString& memberName) :
+ m_className(className),
+ m_memberName(memberName)
+{
+ if(m_onoff) {
+ QString indent;
+ indent.fill(' ', m_indentLevel);
+ std::cerr << indent.latin1() << "ENTER: " << m_className.latin1() << "::" << m_memberName.latin1() << std::endl;
+ }
+ m_indentLevel += 2;
+}
+
+MyMoneyTracer::~MyMoneyTracer()
+{
+ m_indentLevel -= 2;
+ if(m_onoff) {
+ QString indent;
+ indent.fill(' ', m_indentLevel);
+ std::cerr << indent.latin1() << "LEAVE: " << m_className.latin1() << "::" << m_memberName.latin1() << std::endl;
+ }
+}
+
+void MyMoneyTracer::printf(const char *format, ...) const
+{
+ if(m_onoff) {
+ va_list args;
+ va_start(args, format);
+ QString indent;
+ indent.fill(' ', m_indentLevel);
+ std::cerr << indent.latin1();
+
+ vfprintf(stderr,format,args);
+ putc('\n', stderr);
+ va_end(args);
+ }
+}
+
+void MyMoneyTracer::onOff(int onOff)
+{
+ m_onoff = onOff;
+}
+
+void MyMoneyTracer::on(void)
+{
+ m_onoff = 1;
+}
+
+void MyMoneyTracer::off(void)
+{
+ m_onoff = 0;
+}
+
+QString dateToString(const QDate& date)
+{
+ if(!date.isNull() && date.isValid())
+ return date.toString(Qt::ISODate);
+
+ return QString();
+}
+
+QDate stringToDate(const QString& str)
+{
+ if(str.length()) {
+ QDate date = QDate::fromString(str, Qt::ISODate);
+ if(!date.isNull() && date.isValid())
+ return date;
+ }
+ return QDate();
+}
+
+QString QStringEmpty(const QString& val)
+{
+ if(!val.isEmpty())
+ return QString(val);
+
+ return QString();
+}
+
+unsigned long extractId(const QString& txt)
+{
+ int pos;
+ unsigned long rc = 0;
+
+ pos = txt.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ rc = atol(txt.mid(pos));
+ }
+ return rc;
+}
diff --git a/kmymoney2/mymoney/mymoneyutils.h b/kmymoney2/mymoney/mymoneyutils.h
new file mode 100644
index 0000000..12bb95e
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyutils.h
@@ -0,0 +1,192 @@
+/***************************************************************************
+ mymoneyutils.h - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _MYMONEYUTILS_H_
+#define _MYMONEYUTILS_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+#include <kmymoney/export.h>
+#if 0
+
+//Includes for STL support below
+#include <vector>
+#include <map>
+#include <list>
+#include <string>
+using namespace std;
+
+#ifdef _UNICODE
+typedef std::wstring String;
+#else
+typedef std::string String;
+#endif
+
+#else
+
+//typedef for data type to store currency with.
+typedef long long DLONG;
+
+typedef QString String;
+#endif // 0
+
+void timetrace(const char *);
+void timestamp(const char *);
+
+//class that has utility functions to use throughout the application.
+class MyMoneyUtils
+{
+public:
+ MyMoneyUtils() {}
+ ~MyMoneyUtils() {}
+
+ //static function to add the correct file extension at the end of the file name
+ static QString getFileExtension(QString strFileName);
+
+};
+
+class KMYMONEY_EXPORT MyMoneyTracer
+{
+public:
+ MyMoneyTracer(const char* prettyName);
+#define MYMONEYTRACER(a) MyMoneyTracer a(__PRETTY_FUNCTION__)
+
+ MyMoneyTracer(const QString& className, const QString& methodName);
+ ~MyMoneyTracer();
+
+ /**
+ * This method allows to trace a printf like formatted text
+ *
+ * @param format format mask
+ */
+ void printf(const char *format, ...) const __attribute__ ((format (__printf__, 2, 3)));
+
+ static void off(void);
+ static void on(void);
+ static void onOff(int onOff);
+
+private:
+ QString m_className;
+ QString m_memberName;
+
+ static int m_indentLevel;
+ static int m_onoff;
+};
+
+#ifdef _CHECK_MEMORY
+
+#include <cstddef>
+#include <qmap.h>
+
+class _CheckMemoryEntry {
+public:
+ _CheckMemoryEntry();
+ _CheckMemoryEntry(void *p, int line, size_t size, const char *file);
+ ~_CheckMemoryEntry() {}
+
+ void * pointer(void) const { return m_p; };
+ int line(void) const { return m_line; };
+ size_t size(void) const { return m_size; };
+ const char* file(void) const { return m_file; };
+
+private:
+ void *m_p;
+ int m_line;
+ size_t m_size;
+ QString m_file;
+};
+
+typedef QMap<void *, _CheckMemoryEntry> CheckMemoryTable;
+
+typedef void _CheckMemoryOutFunc(const char *);
+
+class KMYMONEY_EXPORT _CheckMemory {
+ public:
+ _CheckMemory();
+ _CheckMemory(_CheckMemoryOutFunc *out);
+ virtual ~_CheckMemory();
+
+ _CheckMemoryOutFunc *SetOutFunc(_CheckMemoryOutFunc *out);
+ bool CheckMemoryLeak(bool freeall);
+ void FreeAll();
+ inline void Restart() { table.clear(); };
+
+ int TableCount(void);
+
+ private:
+ void Output(const char *fmt,...) __attribute__ ((format (__printf__, 2, 3)));
+
+ CheckMemoryTable table;
+ _CheckMemoryOutFunc *outfunc;
+
+ friend void * operator new(size_t s,const char *file,int line) throw();
+ friend void * operator new [] (size_t,const char *file,int line) throw();
+ friend void operator delete(void *p) throw();
+ friend void operator delete [] (void *p) throw();
+};
+
+KMYMONEY_EXPORT void * operator new(size_t s,const char *file,int line) throw(); // Normal new operator
+KMYMONEY_EXPORT void * operator new [] (size_t s,const char *file,int line) throw(); // Array new operator
+KMYMONEY_EXPORT void operator delete(void *p) throw();
+KMYMONEY_EXPORT void operator delete [] (void *p) throw();
+
+#define new new(__FILE__,__LINE__)
+
+KMYMONEY_EXPORT extern _CheckMemory chkmem;
+
+KMYMONEY_EXPORT void _CheckMemory_Init(_CheckMemoryOutFunc *out);
+KMYMONEY_EXPORT void _CheckMemory_End();
+#define _CheckMemory_Leak(freeall) chkmem.CheckMemoryLeak(freeall)
+#define _CheckMemory_FreeAll() chkmem.FreeAll()
+
+#endif // _CHECK_MEMORY
+
+/**
+ * This function returns a date in the form specified by Qt::ISODate.
+ * If the @p date is invalid an empty string will be returned.
+ *
+ * @param date const reference to date to be converted
+ * @return QString containing the converted date
+ */
+KMYMONEY_EXPORT QString dateToString(const QDate& date);
+
+/**
+ * This function returns a date as QDate object as specified by
+ * the parameter @p str. @p str must be in Qt::ISODate format.
+ * If @p str is empty or contains an invalid date, QDate() is
+ * returned.
+ *
+ * @param str date in Qt::ISODate format
+ * @return QDate object
+ */
+KMYMONEY_EXPORT QDate stringToDate(const QString& str);
+
+KMYMONEY_EXPORT QString QStringEmpty(const QString&);
+
+KMYMONEY_EXPORT unsigned long extractId(const QString& txt);
+
+#endif
diff --git a/kmymoney2/mymoney/storage/Makefile.am b/kmymoney2/mymoney/storage/Makefile.am
new file mode 100644
index 0000000..0055800
--- /dev/null
+++ b/kmymoney2/mymoney/storage/Makefile.am
@@ -0,0 +1,20 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I. -I$(top_builddir)/kmymoney2/dialogs
+
+noinst_LIBRARIES = libstorage.a
+libstorage_a_METASOURCES = AUTO
+
+libstorage_a_SOURCES = imymoneystorageformat.cpp mymoneystoragexml.cpp mymoneystoragedump.cpp mymoneyseqaccessmgr.cpp mymoneydatabasemgr.cpp imymoneystorage.cpp imymoneyserialize.cpp mymoneystorageanon.cpp mymoneystoragesql.cpp
+
+instdir=$(includedir)/kmymoney
+inst_HEADERS = imymoneystorage.h imymoneyserialize.h imymoneystorageformat.h
+
+noinst_HEADERS = mymoneyseqaccessmgr.h mymoneydatabasemgr.h mymoneystorageanon.h mymoneystoragedump.h mymoneystoragexml.h mymoneyseqaccessmgrtest.h mymoneydatabasemgrtest.h mymoneystoragesql.h mymoneystoragebin.h mymoneymap.h mymoneymaptest.h
+
+if CPPUNIT
+check_LIBRARIES = libstoragetest.a
+
+libstoragetest_a_SOURCES = mymoneyseqaccessmgrtest.cpp mymoneymaptest.cpp mymoneydatabasemgrtest.cpp
+endif
+
diff --git a/kmymoney2/mymoney/storage/imymoneyserialize.cpp b/kmymoney2/mymoney/storage/imymoneyserialize.cpp
new file mode 100644
index 0000000..14b76dd
--- /dev/null
+++ b/kmymoney2/mymoney/storage/imymoneyserialize.cpp
@@ -0,0 +1,31 @@
+/***************************************************************************
+ imymoneyserialize.cpp - description
+ -------------------
+ begin : Fri May 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "imymoneyserialize.h"
+
+IMyMoneySerialize::IMyMoneySerialize()
+{
+}
+IMyMoneySerialize::~IMyMoneySerialize()
+{
+}
+
diff --git a/kmymoney2/mymoney/storage/imymoneyserialize.h b/kmymoney2/mymoney/storage/imymoneyserialize.h
new file mode 100644
index 0000000..a0c12ca
--- /dev/null
+++ b/kmymoney2/mymoney/storage/imymoneyserialize.h
@@ -0,0 +1,374 @@
+/***************************************************************************
+ imymoneyserialize.h - description
+ -------------------
+ begin : Fri May 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMYMONEYSERIALIZE_H
+#define IMYMONEYSERIALIZE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qvaluelist.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneytransactionfilter.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/mymoneybudget.h>
+#include "mymoneystoragesql.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents the interface to serialize a MyMoneyStorage object
+ */
+class IMyMoneySerialize {
+public:
+ IMyMoneySerialize();
+ virtual ~IMyMoneySerialize();
+
+ // general get functions
+ virtual const MyMoneyPayee user(void) const = 0;
+ virtual const QDate creationDate(void) const = 0;
+ virtual const QDate lastModificationDate(void) const = 0;
+ virtual unsigned int currentFixVersion(void) const = 0;
+ virtual unsigned int fileFixVersion(void) const = 0;
+
+ // general set functions
+ virtual void setUser(const MyMoneyPayee& val) = 0;
+ virtual void setCreationDate(const QDate& val) = 0;
+ virtual void setFileFixVersion(const unsigned int v) = 0;
+ /**
+ * This method is used to get a SQL reader for subsequent database access
+ */
+ virtual KSharedPtr <MyMoneyStorageSql> connectToDatabase
+ (const KURL& url) = 0;
+ /**
+ * This method is used when a database file is open, and the data is to
+ * be saved in a different file or format. It will ensure that all data
+ * from the database is available in memory to enable it to be written.
+ */
+ virtual void fillStorage() = 0;
+
+ /**
+ * This method is used to set the last modification date of
+ * the storage object. It also clears the dirty flag and should
+ * therefor be called as last operation when loading from a
+ * file.
+ *
+ * @param val QDate of last modification
+ */
+ virtual void setLastModificationDate(const QDate& val) = 0;
+
+ /**
+ * This method returns a list of accounts inside the storage object.
+ *
+ * @param list reference to QValueList receiving the account objects
+ *
+ * @note The standard accounts will not be returned
+ */
+ virtual void accountList(QValueList<MyMoneyAccount>& list) const = 0;
+
+ /**
+ * This method returns a list of the institutions
+ * inside a MyMoneyStorage object
+ *
+ * @return QMap containing the institution information
+ */
+ virtual const QValueList<MyMoneyInstitution> institutionList(void) const = 0;
+
+ /**
+ * This method is used to pull a list of transactions from the file
+ * global transaction pool. It returns all those transactions
+ * that match the filter passed as argument. If the filter is empty,
+ * the whole journal will be returned.
+ *
+ * @param list reference to QValueList<MyMoneyTransaction> receiving
+ * the set of transactions
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ */
+ virtual void transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const = 0;
+
+
+ /**
+ * This method returns whether a given transaction is already in memory, to avoid
+ * reloading it from the database
+ */
+ virtual bool isDuplicateTransaction(const QString&) const = 0;
+ /**
+ * This method returns a list of the payees
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyPayee> containing the payee information
+ */
+ virtual const QValueList<MyMoneyPayee> payeeList(void) const = 0;
+
+ /**
+ * This method returns a list of the scheduled transactions
+ * inside a MyMoneyStorage object. In order to retrieve a complete
+ * list of the transactions, all arguments should be used with their
+ * default arguments.
+ */
+ virtual const QValueList<MyMoneySchedule> scheduleList(const QString& = QString(),
+ const MyMoneySchedule::typeE = MyMoneySchedule::TYPE_ANY,
+ const MyMoneySchedule::occurenceE = MyMoneySchedule::OCCUR_ANY,
+ const MyMoneySchedule::paymentTypeE = MyMoneySchedule::STYPE_ANY,
+ const QDate& = QDate(),
+ const QDate& = QDate(),
+ const bool = false) const = 0;
+
+ /**
+ * This method returns a list of security objects that the engine has
+ * knowledge of.
+ */
+ virtual const QValueList<MyMoneySecurity> securityList(void) const = 0;
+
+ /**
+ * This method is used to return the standard liability account
+ * @return MyMoneyAccount liability account(group)
+ */
+ virtual const MyMoneyAccount liability(void) const = 0;
+
+ /**
+ * This method is used to return the standard asset account
+ * @return MyMoneyAccount asset account(group)
+ */
+ virtual const MyMoneyAccount asset(void) const = 0;
+
+ /**
+ * This method is used to return the standard expense account
+ * @return MyMoneyAccount expense account(group)
+ */
+ virtual const MyMoneyAccount expense(void) const = 0;
+
+ /**
+ * This method is used to return the standard income account
+ * @return MyMoneyAccount income account(group)
+ */
+ virtual const MyMoneyAccount income(void) const = 0;
+
+ /**
+ * This method is used to return the standard equity account
+ * @return MyMoneyAccount equity account(group)
+ */
+ virtual const MyMoneyAccount equity(void) const = 0;
+
+ /**
+ * This method is used to create a new account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount filled with data
+ */
+ virtual void addAccount(MyMoneyAccount& account) = 0;
+
+ /**
+ * This method is used to add one account as sub-ordinate to another
+ * (parent) account. The objects that are passed will be modified
+ * accordingly.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param parent parent account the account should be added to
+ * @param account the account to be added
+ *
+ * @deprecated This method is only provided as long as we provide
+ * the version 0.4 binary reader. As soon as we deprecate
+ * this compatability mode this method will disappear from
+ * this interface!
+ */
+ virtual void addAccount(MyMoneyAccount& parent, MyMoneyAccount& account) = 0;
+
+ /**
+ * This method is used to create a new payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ *
+ * @deprecated This method is only provided as long as we provide
+ * the version 0.4 binary reader. As soon as we deprecate
+ * this compatability mode this method will disappear from
+ * this interface!
+ *
+ */
+ virtual void addPayee(MyMoneyPayee& payee) = 0;
+
+ /**
+ * Adds an institution to the storage. A
+ * respective institution-ID will be generated within this record.
+ * The ID is stored as QString in the object passed as argument.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete institution information in a
+ * MyMoneyInstitution object
+ *
+ * @deprecated This method is only provided as long as we provide
+ * the version 0.4 binary reader. As soon as we deprecate
+ * this compatability mode this method will disappear from
+ * this interface!
+ */
+ virtual void addInstitution(MyMoneyInstitution& institution) = 0;
+
+ /**
+ * Adds a transaction to the file-global transaction pool. A respective
+ * transaction-ID will be generated within this record. The ID is stored
+ * as QString with the object.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to the transaction
+ * @param skipAccountUpdate if set, the transaction lists of the accounts
+ * referenced in the splits are not updated. This is used for
+ * bulk loading a lot of transactions but not during normal operation.
+ * Refreshing the account's transaction list can be done using
+ * refreshAllAccountTransactionList().
+ *
+ * @deprecated This method is only provided as long as we provide
+ * the version 0.4 binary reader. As soon as we deprecate
+ * this compatability mode this method will disappear from
+ * this interface!
+ */
+ virtual void addTransaction(MyMoneyTransaction& transaction, const bool skipAccountUpdate = false) = 0;
+
+ virtual void loadAccounts(const QMap<QString, MyMoneyAccount>& map) = 0;
+ virtual void loadTransactions(const QMap<QString, MyMoneyTransaction>& map) = 0;
+ virtual void loadInstitutions(const QMap<QString, MyMoneyInstitution>& map) = 0;
+ virtual void loadPayees(const QMap<QString, MyMoneyPayee>& map) = 0;
+ virtual void loadSchedules(const QMap<QString, MyMoneySchedule>& map) = 0;
+ virtual void loadSecurities(const QMap<QString, MyMoneySecurity>& map) = 0;
+ virtual void loadCurrencies(const QMap<QString, MyMoneySecurity>& map) = 0;
+ virtual void loadReports( const QMap<QString, MyMoneyReport>& reports ) = 0;
+ virtual void loadBudgets( const QMap<QString, MyMoneyBudget>& budgets ) = 0;
+ virtual void loadPrices(const MyMoneyPriceList& list) = 0;
+
+ virtual unsigned long accountId(void) const = 0;
+ virtual unsigned long transactionId(void) const = 0;
+ virtual unsigned long payeeId(void) const = 0;
+ virtual unsigned long institutionId(void) const = 0;
+ virtual unsigned long scheduleId(void) const = 0;
+ virtual unsigned long securityId(void) const = 0;
+ virtual unsigned long reportId(void) const = 0;
+ virtual unsigned long budgetId(void) const = 0;
+
+ virtual void loadAccountId(const unsigned long id) = 0;
+ virtual void loadTransactionId(const unsigned long id) = 0;
+ virtual void loadPayeeId(const unsigned long id) = 0;
+ virtual void loadInstitutionId(const unsigned long id) = 0;
+ virtual void loadScheduleId(const unsigned long id) = 0;
+ virtual void loadSecurityId(const unsigned long id) = 0;
+ virtual void loadReportId(const unsigned long id) = 0;
+ virtual void loadBudgetId(const unsigned long id) = 0;
+
+ /**
+ * This method is used to retrieve the whole set of key/value pairs
+ * from the container. It is meant to be used for permanent storage
+ * functionality. See MyMoneyKeyValueContainer::pairs() for details.
+ *
+ * @return QMap<QString, QString> containing all key/value pairs of
+ * this container.
+ */
+ virtual const QMap<QString, QString> pairs(void) const = 0;
+
+ /**
+ * This method is used to initially store a set of key/value pairs
+ * in the container. It is meant to be used for loading functionality
+ * from permanent storage. See MyMoneyKeyValueContainer::setPairs()
+ * for details
+ *
+ * @param list const QMap<QString, QString> containing the set of
+ * key/value pairs to be loaded into the container.
+ *
+ * @note All existing key/value pairs in the container will be deleted.
+ */
+ virtual void setPairs(const QMap<QString, QString>& list) = 0;
+
+ virtual const QValueList<MyMoneySchedule> scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts=QStringList()) const = 0;
+
+ /**
+ * This method is used to retrieve the list of all currencies
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneySecurity objects representing a currency.
+ */
+ virtual const QValueList<MyMoneySecurity> currencyList(void) const = 0;
+
+ /**
+ * This method is used to retrieve the list of all reports
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyReport objects.
+ */
+ virtual const QValueList<MyMoneyReport> reportList( void ) const = 0;
+
+ /**
+ * This method is used to retrieve the list of all budgets
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyBudget objects.
+ */
+ virtual const QValueList<MyMoneyBudget> budgetList( void ) const = 0;
+
+
+ /**
+ * This method adds a price entry to the price list.
+ */
+ virtual void addPrice(const MyMoneyPrice& price) = 0;
+
+ /**
+ * This method returns a list of all prices.
+ *
+ * @return MyMoneyPriceList of all MyMoneyPrice objects.
+ */
+ virtual const MyMoneyPriceList priceList(void) const = 0;
+
+ /**
+ * This method recalculates the balances of all accounts
+ * based on the transactions stored in the engine.
+ */
+ virtual void rebuildAccountBalances(void) = 0;
+
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/imymoneystorage.cpp b/kmymoney2/mymoney/storage/imymoneystorage.cpp
new file mode 100644
index 0000000..dc67726
--- /dev/null
+++ b/kmymoney2/mymoney/storage/imymoneystorage.cpp
@@ -0,0 +1,38 @@
+/***************************************************************************
+ imymoneystorage.cpp - description
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "imymoneystorage.h"
+
+bool MyMoneyFileBitArray::testBit(uint index) const
+{
+ if(index < size())
+ return QBitArray::testBit(index);
+ return false;
+}
+
+
+IMyMoneyStorage::IMyMoneyStorage()
+{
+}
+IMyMoneyStorage::~IMyMoneyStorage()
+{
+}
diff --git a/kmymoney2/mymoney/storage/imymoneystorage.h b/kmymoney2/mymoney/storage/imymoneystorage.h
new file mode 100644
index 0000000..a4e55dd
--- /dev/null
+++ b/kmymoney2/mymoney/storage/imymoneystorage.h
@@ -0,0 +1,886 @@
+/***************************************************************************
+ imymoneystorage.h - description
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMYMONEYSTORAGE_H
+#define IMYMONEYSTORAGE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qbitarray.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneyobserver.h>
+#include <kmymoney/mymoneytransactionfilter.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/mymoneybudget.h>
+
+/**
+ * @author Thomas Baumgart
+ *
+ * A simple replacement for QBitArray that does not bark if testBit()
+ * is called with an index out of bounds. It silently returns false
+ * in that case, otherwise calls the base classes implementation.
+ */
+class MyMoneyFileBitArray : public QBitArray
+{
+public:
+ MyMoneyFileBitArray() : QBitArray() {}
+ MyMoneyFileBitArray(int size) : QBitArray(size) {}
+ bool testBit(uint index) const;
+ bool operator[](int index) const { return testBit(index); }
+ bool at(uint index) const { return testBit(index); }
+};
+
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * The IMyMoneyStorage class describes the interface between the MyMoneyFile class
+ * and the real storage manager.
+ *
+ * @see MyMoneySeqAccessMgr
+ */
+class IMyMoneyStorage {
+public:
+
+ typedef enum {
+ RefCheckAccount = 0,
+ RefCheckInstitution,
+ RefCheckPayee,
+ RefCheckTransaction,
+ RefCheckReport,
+ RefCheckBudget,
+ RefCheckSchedule,
+ RefCheckSecurity,
+ RefCheckCurrency,
+ RefCheckPrice,
+ // insert new entries above this line
+ MaxRefCheckBits
+ } ReferenceCheckBits;
+
+ // definitions for the ID's of the standard accounts
+#define STD_ACC_LIABILITY "AStd::Liability"
+#define STD_ACC_ASSET "AStd::Asset"
+#define STD_ACC_EXPENSE "AStd::Expense"
+#define STD_ACC_INCOME "AStd::Income"
+#define STD_ACC_EQUITY "AStd::Equity"
+
+ IMyMoneyStorage();
+ virtual ~IMyMoneyStorage();
+
+ // general get functions
+ virtual const MyMoneyPayee user(void) const = 0;
+ virtual const QDate creationDate(void) const = 0;
+ virtual const QDate lastModificationDate(void) const = 0;
+ virtual unsigned int currentFixVersion(void) const = 0;
+ virtual unsigned int fileFixVersion(void) const = 0;
+
+ // general set functions
+ virtual void setUser(const MyMoneyPayee& user) = 0;
+ virtual void setFileFixVersion(const unsigned int v) = 0;
+
+ // methods provided by MyMoneyKeyValueContainer
+ virtual void setValue(const QString& key, const QString& value) = 0;
+ virtual const QString value(const QString& key) const = 0;
+ virtual void deletePair(const QString& key) = 0;
+
+ /**
+ * This method is used to duplicate an IMyMoneyStorage object and return
+ * a pointer to the newly created copy. The caller of this method is the
+ * new owner of the object and must destroy it.
+ */
+ virtual IMyMoneyStorage const * duplicate(void) = 0;
+
+ /**
+ * This method is used to create a new account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount filled with data
+ */
+ virtual void addAccount(MyMoneyAccount& account) = 0;
+
+ /**
+ * This method is used to add one account as sub-ordinate to another
+ * (parent) account. The objects that are passed will be modified
+ * accordingly.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param parent parent account the account should be added to
+ * @param account the account to be added
+ */
+ virtual void addAccount(MyMoneyAccount& parent, MyMoneyAccount& account) = 0;
+
+ /**
+ * This method is used to create a new payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ virtual void addPayee(MyMoneyPayee& payee) = 0;
+
+ /**
+ * This method is used to retrieve information about a payee
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id QString reference to id of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ virtual const MyMoneyPayee payee(const QString& id) const = 0;
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a payee/receiver.
+ * An exception will be thrown upon error conditions.
+ *
+ * @param payee QString reference to name of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ virtual const MyMoneyPayee payeeByName(const QString& payee) const = 0;
+
+ /**
+ * This method is used to modify an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ virtual void modifyPayee(const MyMoneyPayee& payee) = 0;
+
+ /**
+ * This method is used to remove an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ virtual void removePayee(const MyMoneyPayee& payee) = 0;
+
+ /**
+ * This method returns a list of the payees
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyPayee> containing the payee information
+ */
+ virtual const QValueList<MyMoneyPayee> payeeList(void) const = 0;
+
+ /**
+ * Returns the account addressed by it's id.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id id of the account to locate.
+ * @return reference to MyMoneyAccount object. An exception is thrown
+ * if the id is unknown
+ */
+ virtual const MyMoneyAccount account(const QString& id) const = 0;
+
+ /**
+ * This method is used to check whether a given
+ * account id references one of the standard accounts or not.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id account id
+ * @return true if account-id is one of the standards, false otherwise
+ */
+ virtual bool isStandardAccount(const QString& id) const = 0;
+
+ /**
+ * This method is used to set the name for the specified standard account
+ * within the storage area. An exception will be thrown, if an error
+ * occurs
+ *
+ * @param id QString reference to one of the standard accounts.
+ * @param name QString reference to the name to be set
+ *
+ */
+ virtual void setAccountName(const QString& id, const QString& name) = 0;
+
+ /**
+ * Adds an institution to the storage. A
+ * respective institution-ID will be generated within this record.
+ * The ID is stored as QString in the object passed as argument.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete institution information in a
+ * MyMoneyInstitution object
+ */
+ virtual void addInstitution(MyMoneyInstitution& institution) = 0;
+
+ /**
+ * Adds a transaction to the file-global transaction pool. A respective
+ * transaction-ID will be generated within this record. The ID is stored
+ * QString with the object.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to the transaction
+ * @param skipAccountUpdate if set, the transaction lists of the accounts
+ * referenced in the splits are not updated. This is used for
+ * bulk loading a lot of transactions but not during normal operation
+ */
+ virtual void addTransaction(MyMoneyTransaction& transaction, const bool skipAccountUpdate = false) = 0;
+
+ /**
+ * This method is used to determince, if the account with the
+ * given ID is referenced by any split in m_transactionList.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id id of the account to be checked for
+ * @return true if account is referenced, false otherwise
+ */
+ virtual bool hasActiveSplits(const QString& id) const = 0;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * without it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+ virtual const MyMoneyMoney balance(const QString& id, const QDate& date) const= 0;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * including it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+ virtual const MyMoneyMoney totalBalance(const QString& id, const QDate& date) const = 0;
+
+ /**
+ * Returns the institution of a given ID
+ *
+ * @param id id of the institution to locate
+ * @return MyMoneyInstitution object filled with data. If the institution
+ * could not be found, an exception will be thrown
+ */
+ virtual const MyMoneyInstitution institution(const QString& id) const = 0;
+
+ /**
+ * This method returns an indicator if the storage object has been
+ * changed after it has last been saved to permanent storage.
+ *
+ * @return true if changed, false if not
+ */
+ virtual bool dirty(void) const = 0;
+
+ /**
+ * This method can be used by an external object to force the
+ * storage object to be dirty. This is used e.g. when an upload
+ * to an external destination failed but the previous storage
+ * to a local disk was ok.
+ */
+ virtual void setDirty(void) = 0;
+
+ /**
+ * This method returns the number of accounts currently known to this storage
+ * in the range 0..MAXUINT
+ *
+ * @return number of accounts currently known inside a MyMoneyFile object
+ */
+ virtual unsigned int accountCount(void) const = 0;
+
+ /**
+ * This method returns a list of the institutions
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyInstitution> containing the
+ * institution information
+ */
+ virtual const QValueList<MyMoneyInstitution> institutionList(void) const = 0;
+
+ /**
+ * Modifies an already existing account in the file global account pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account reference to the new account information
+ * @param skipCheck allows to skip the builtin consistency checks
+ */
+ virtual void modifyAccount(const MyMoneyAccount& account, const bool skipCheck = false) = 0;
+
+ /**
+ * Modifies an already existing institution in the file global
+ * institution pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete new institution information
+ */
+ virtual void modifyInstitution(const MyMoneyInstitution& institution) = 0;
+
+ /**
+ * This method is used to update a specific transaction in the
+ * transaction pool of the MyMoneyFile object
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to transaction to be changed
+ */
+ virtual void modifyTransaction(const MyMoneyTransaction& transaction) = 0;
+
+ /**
+ * This method re-parents an existing account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount reference to account to be re-parented
+ * @param parent MyMoneyAccount reference to new parent account
+ */
+ virtual void reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent) = 0;
+
+ /**
+ * This method is used to remove a transaction from the transaction
+ * pool (journal).
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction const reference to transaction to be deleted
+ */
+ virtual void removeTransaction(const MyMoneyTransaction& transaction) = 0;
+
+ /**
+ * This method returns the number of transactions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @param account QString reference to account id. If account is empty
+ + all transactions (the journal) will be counted. If account
+ * is not empty it returns the number of transactions
+ * that have splits in this account.
+ *
+ * @return number of transactions in journal/account
+ */
+ virtual unsigned int transactionCount(const QString& account = QString()) const = 0;
+
+ /**
+ * This method returns a QMap filled with the number of transactions
+ * per account. The account id serves as index into the map. If one
+ * needs to have all transactionCounts() for many accounts, this method
+ * is faster than calling transactionCount(const QString& account) many
+ * times.
+ *
+ * @return QMap with numbers of transactions per account
+ */
+ virtual const QMap<QString, unsigned long> transactionCountMap(void) const = 0;
+
+ /**
+ * This method is used to pull a list of transactions from the file
+ * global transaction pool. It returns all those transactions
+ * that match the filter passed as argument. If the filter is empty,
+ * the whole journal will be returned.
+ * The list returned is sorted according to the transactions posting date.
+ * If more than one transaction exists for the same date, the order among
+ * them is undefined.
+ *
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ *
+ * @return set of transactions in form of a QValueList<MyMoneyTransaction>
+ */
+ virtual const QValueList<MyMoneyTransaction> transactionList(MyMoneyTransactionFilter& filter) const = 0;
+
+ virtual void transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const = 0;
+
+ virtual void transactionList(QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const = 0;
+
+ /**
+ * Deletes an existing account from the file global account pool
+ * This method only allows to remove accounts that are not
+ * referenced by any split. Use moveSplits() to move splits
+ * to another account. An exception is thrown in case of a
+ * problem.
+ *
+ * @param account reference to the account to be deleted.
+ */
+ virtual void removeAccount(const MyMoneyAccount& account) = 0;
+
+ /**
+ * Deletes an existing institution from the file global institution pool
+ * Also modifies the accounts that reference this institution as
+ * their institution.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution institution to be deleted.
+ */
+ virtual void removeInstitution(const MyMoneyInstitution& institution) = 0;
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an id. In case of an invalid id, an
+ * exception will be thrown.
+ *
+ * @param id id of transaction as QString.
+ * @return reference to the requested transaction
+ */
+ virtual const MyMoneyTransaction transaction(const QString& id) const = 0;
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an index into an account.
+ *
+ * @param account id of the account as QString
+ * @param idx number of transaction in this account
+ * @return reference to MyMoneyTransaction object
+ */
+ virtual const MyMoneyTransaction transaction(const QString& account, const int idx) const = 0;
+
+ /**
+ * This method returns the number of institutions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of institutions known to file
+ */
+ virtual unsigned int institutionCount(void) const = 0;
+
+ /**
+ * This method returns a list of accounts inside the storage object.
+ *
+ * @param list reference to QValueList receiving the account objects
+ *
+ * @note The standard accounts will not be returned
+ */
+ virtual void accountList(QValueList<MyMoneyAccount>& list) const = 0;
+
+ /**
+ * This method is used to return the standard liability account
+ * @return MyMoneyAccount liability account(group)
+ */
+ virtual const MyMoneyAccount liability(void) const = 0;
+
+ /**
+ * This method is used to return the standard asset account
+ * @return MyMoneyAccount asset account(group)
+ */
+ virtual const MyMoneyAccount asset(void) const = 0;
+
+ /**
+ * This method is used to return the standard expense account
+ * @return MyMoneyAccount expense account(group)
+ */
+ virtual const MyMoneyAccount expense(void) const = 0;
+
+ /**
+ * This method is used to return the standard income account
+ * @return MyMoneyAccount income account(group)
+ */
+ virtual const MyMoneyAccount income(void) const = 0;
+
+ /**
+ * This method is used to return the standard equity account
+ * @return MyMoneyAccount equity account(group)
+ */
+ virtual const MyMoneyAccount equity(void) const = 0;
+
+ /**
+ * This method is used to create a new security object. The ID will be created
+ * automatically. The object passed with the parameter @p security is modified
+ * to contain the assigned id.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param security MyMoneySecurity filled with data
+ */
+ virtual void addSecurity(MyMoneySecurity& security) = 0;
+
+ /**
+ * This method is used to modify an existing MyMoneySecurity
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be updated
+ */
+ virtual void modifySecurity(const MyMoneySecurity& security) = 0;
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be removed
+ */
+ virtual void removeSecurity(const MyMoneySecurity& security) = 0;
+
+ /**
+ * This method is used to retrieve a single MyMoneySecurity object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySecurity object
+ * @return MyMoneySecurity object
+ */
+ virtual const MyMoneySecurity security(const QString& id) const = 0;
+
+ /**
+ * This method returns a list of the security objects
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneySecurity> containing objects
+ */
+ virtual const QValueList<MyMoneySecurity> securityList(void) const = 0;
+
+ virtual void addPrice(const MyMoneyPrice& price) = 0;
+ virtual void removePrice(const MyMoneyPrice& price) = 0;
+ virtual const MyMoneyPrice price(const QString& fromId, const QString& toId, const QDate& date, const bool exactDate) const = 0;
+
+ /**
+ * This method returns a list of all prices.
+ *
+ * @return MyMoneyPriceList of all MyMoneyPrice objects.
+ */
+ virtual const MyMoneyPriceList priceList(void) const = 0;
+
+ /**
+ * This method is used to add a scheduled transaction to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched reference to the MyMoneySchedule object
+ */
+ virtual void addSchedule(MyMoneySchedule& sched) = 0;
+
+ /**
+ * This method is used to modify an existing MyMoneySchedule
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ virtual void modifySchedule(const MyMoneySchedule& sched) = 0;
+
+ /**
+ * This method is used to remove an existing MyMoneySchedule object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ virtual void removeSchedule(const MyMoneySchedule& sched) = 0;
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ virtual const MyMoneySchedule schedule(const QString& id) const = 0;
+
+ /**
+ * This method is used to extract a list of scheduled transactions
+ * according to the filter criteria passed as arguments.
+ *
+ * @param accountId only search for scheduled transactions that reference
+ * accound @p accountId. If accountId is the empty string,
+ * this filter is off. Default is @p QString().
+ * @param type only schedules of type @p type are searched for.
+ * See MyMoneySchedule::typeE for details.
+ * Default is MyMoneySchedule::TYPE_ANY
+ * @param occurence only schedules of occurence type @p occurance are searched for.
+ * See MyMoneySchedule::occurenceE for details.
+ * Default is MyMoneySchedule::OCCUR_ANY
+ * @param paymentType only schedules of payment method @p paymentType
+ * are searched for.
+ * See MyMoneySchedule::paymentTypeE for details.
+ * Default is MyMoneySchedule::STYPE_ANY
+ * @param startDate only schedules with payment dates after @p startDate
+ * are searched for. Default is all dates (QDate()).
+ * @param endDate only schedules with payment dates ending prior to @p endDate
+ * are searched for. Default is all dates (QDate()).
+ * @param overdue if true, only those schedules that are overdue are
+ * searched for. Default is false (all schedules will be returned).
+ *
+ * @return const QValueList<MyMoneySchedule> list of schedule objects.
+ */
+ virtual const QValueList<MyMoneySchedule> scheduleList(const QString& accountId = QString(),
+ const MyMoneySchedule::typeE type = MyMoneySchedule::TYPE_ANY,
+ const MyMoneySchedule::occurenceE occurence = MyMoneySchedule::OCCUR_ANY,
+ const MyMoneySchedule::paymentTypeE paymentType = MyMoneySchedule::STYPE_ANY,
+ const QDate& startDate = QDate(),
+ const QDate& endDate = QDate(),
+ const bool overdue = false) const = 0;
+
+ virtual const QValueList<MyMoneySchedule> scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts=QStringList()) const = 0;
+
+ /**
+ * This method is used to add a new currency object to the engine.
+ * The ID of the object is the trading symbol, so there is no need for an additional
+ * ID since the symbol is guaranteed to be unique.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ virtual void addCurrency(const MyMoneySecurity& currency) = 0;
+
+ /**
+ * This method is used to modify an existing MyMoneySecurity
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneyCurrency object
+ */
+ virtual void modifyCurrency(const MyMoneySecurity& currency) = 0;
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ virtual void removeCurrency(const MyMoneySecurity& currency) = 0;
+
+ /**
+ * This method is used to retrieve a single MyMoneySecurity object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySecurity object
+ * @return MyMoneyCurrency object
+ */
+ virtual const MyMoneySecurity currency(const QString& id) const = 0;
+
+ /**
+ * This method is used to retrieve the list of all currencies
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneySecurity objects representing a currency.
+ */
+ virtual const QValueList<MyMoneySecurity> currencyList(void) const = 0;
+
+ /**
+ * This method is used to retrieve the list of all reports
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyReport objects.
+ */
+ virtual const QValueList<MyMoneyReport> reportList( void ) const = 0;
+
+ /**
+ * This method is used to add a new report to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report reference to the MyMoneyReport object
+ */
+ virtual void addReport( MyMoneyReport& report ) = 0;
+
+ /**
+ * This method is used to modify an existing MyMoneyReport
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ virtual void modifyReport( const MyMoneyReport& report ) = 0;
+
+ /**
+ * This method returns the number of reports currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of reports known to file
+ */
+ virtual unsigned countReports( void ) const = 0;
+
+ /**
+ * This method is used to retrieve a single MyMoneyReport object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyReport object
+ * @return MyMoneyReport object
+ */
+ virtual const MyMoneyReport report( const QString& id ) const = 0;
+
+ /**
+ * This method is used to remove an existing MyMoneyReport object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ virtual void removeReport(const MyMoneyReport& report) = 0;
+
+ /**
+ * This method is used to retrieve the list of all budgets
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyBudget objects.
+ */
+ virtual const QValueList<MyMoneyBudget> budgetList( void ) const = 0;
+
+ /**
+ * This method is used to add a new budget to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget reference to the MyMoneyBudget object
+ */
+ virtual void addBudget( MyMoneyBudget& budget ) = 0;
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a budget
+ * An exception will be thrown upon error conditions.
+ *
+ * @param budget QString reference to name of budget
+ *
+ * @return MyMoneyBudget object of budget
+ */
+ virtual const MyMoneyBudget budgetByName(const QString& budget) const = 0;
+
+ /**
+ * This method is used to modify an existing MyMoneyBudget
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ virtual void modifyBudget( const MyMoneyBudget& budget ) = 0;
+
+ /**
+ * This method returns the number of budgets currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of budgets known to file
+ */
+ virtual unsigned countBudgets( void ) const = 0;
+
+ /**
+ * This method is used to retrieve a single MyMoneyBudget object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyBudget object
+ * @return MyMoneyBudget object
+ */
+ virtual MyMoneyBudget budget( const QString& id ) const = 0;
+
+ /**
+ * This method is used to remove an existing MyMoneyBudget object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ virtual void removeBudget(const MyMoneyBudget& budget) = 0;
+
+
+
+ /**
+ * Clear all internal caches (used internally for performance measurements)
+ */
+ virtual void clearCache(void) = 0;
+
+ /**
+ * This method checks, if the given @p object is referenced
+ * by another engine object.
+ *
+ * @param obj const reference to object to be checked
+ * @param skipCheck MyMoneyFileBitArray with ReferenceCheckBits set for which
+ * the check should be skipped
+ *
+ * @retval false @p object is not referenced
+ * @retval true @p institution is referenced
+ */
+ virtual bool isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipCheck = MyMoneyFileBitArray()) const = 0;
+
+ /**
+ * This method is provided to allow closing of the database before logoff
+ */
+ virtual void close(void) = 0;
+
+ /**
+ * These methods have to be provided to allow transaction safe data handling.
+ */
+ virtual void startTransaction(void) = 0;
+ virtual bool commitTransaction(void) = 0;
+ virtual void rollbackTransaction(void) = 0;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/imymoneystorageformat.cpp b/kmymoney2/mymoney/storage/imymoneystorageformat.cpp
new file mode 100644
index 0000000..bc3bbb2
--- /dev/null
+++ b/kmymoney2/mymoney/storage/imymoneystorageformat.cpp
@@ -0,0 +1,31 @@
+/***************************************************************************
+ imymoneystorageformat.cpp - description
+ -------------------
+ begin : Sun Oct 27 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "imymoneystorageformat.h"
+
+IMyMoneyStorageFormat::IMyMoneyStorageFormat()
+{
+}
+
+IMyMoneyStorageFormat::~IMyMoneyStorageFormat()
+{
+}
diff --git a/kmymoney2/mymoney/storage/imymoneystorageformat.h b/kmymoney2/mymoney/storage/imymoneystorageformat.h
new file mode 100644
index 0000000..b045898
--- /dev/null
+++ b/kmymoney2/mymoney/storage/imymoneystorageformat.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ imymoneystorageformat.h - description
+ -------------------
+ begin : Sun Oct 27 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMYMONEYSTORAGEFORMAT_H
+#define IMYMONEYSTORAGEFORMAT_H
+
+
+/**
+ * @author Kevin Tambascio (ktambascio@yahoo.com)
+ */
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QString;
+class QIODevice;
+class QProgressDialog;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class IMyMoneySerialize;
+
+
+class IMyMoneyStorageFormat
+{
+public:
+ IMyMoneyStorageFormat();
+ virtual ~IMyMoneyStorageFormat();
+
+ enum fileVersionDirectionType {
+ Reading = 0, /**< version of file to be read */
+ Writing = 1 /**< version to be used when writing a file */
+ };
+
+ virtual void readFile(QIODevice* qf, IMyMoneySerialize* storage) = 0;
+ // virtual void readStream(QDataStream& s, IMyMoneySerialize* storage) = 0;
+
+ virtual void writeFile(QIODevice* qf, IMyMoneySerialize* storage) = 0;
+ //virtual void writeStream(QDataStream& s, IMyMoneySerialize* storage) = 0;
+
+ virtual void setProgressCallback(void(*callback)(int, int, const QString&)) = 0;
+ /**
+ * This member is used to store the file version information
+ * obtained while reading a file.
+ */
+ static unsigned int fileVersionRead;
+
+ /**
+ * This member is used to store the file version information
+ * to be used when writing a file.
+ */
+ static unsigned int fileVersionWrite;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneydatabasemgr.cpp b/kmymoney2/mymoney/storage/mymoneydatabasemgr.cpp
new file mode 100644
index 0000000..e845094
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneydatabasemgr.cpp
@@ -0,0 +1,1880 @@
+/***************************************************************************
+ mymoneydatabasemgr.cpp
+ -------------------
+ begin : June 5 2007
+ copyright : (C) 2007 by Fernando Vilas
+ email : Fernando Vilas <fvilas@iname.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include <typeinfo>
+#include <algorithm>
+
+#include "mymoneydatabasemgr.h"
+#include "../mymoneytransactionfilter.h"
+#include "../mymoneycategory.h"
+
+#define TRY try {
+#define CATCH } catch (MyMoneyException *e) {
+#define PASS } catch (MyMoneyException *e) { throw; }
+
+MyMoneyDatabaseMgr::MyMoneyDatabaseMgr() :
+m_creationDate (QDate::currentDate ()),
+m_lastModificationDate (QDate::currentDate ()),
+m_sql (0)
+{ }
+
+MyMoneyDatabaseMgr::~MyMoneyDatabaseMgr()
+{ }
+
+ // general get functions
+const MyMoneyPayee MyMoneyDatabaseMgr::user(void) const
+{ return m_user; }
+
+const QDate MyMoneyDatabaseMgr::creationDate(void) const
+{ return m_creationDate; }
+
+const QDate MyMoneyDatabaseMgr::lastModificationDate(void) const
+{ return m_lastModificationDate; }
+
+unsigned int MyMoneyDatabaseMgr::currentFixVersion(void) const
+{ return CURRENT_FIX_VERSION; }
+
+unsigned int MyMoneyDatabaseMgr::fileFixVersion(void) const
+{ return m_fileFixVersion; }
+
+ // general set functions
+void MyMoneyDatabaseMgr::setUser(const MyMoneyPayee& user)
+{
+ m_user = user;
+ if (m_sql != 0) m_sql->modifyUserInfo(user);
+}
+
+void MyMoneyDatabaseMgr::setFileFixVersion(const unsigned int v)
+{ m_fileFixVersion = v; }
+
+ // methods provided by MyMoneyKeyValueContainer
+const QString MyMoneyDatabaseMgr::value(const QString& key) const
+{
+ return MyMoneyKeyValueContainer::value(key);
+}
+
+void MyMoneyDatabaseMgr::setValue(const QString& key, const QString& val)
+{
+ MyMoneyKeyValueContainer::setValue(key, val);
+}
+
+void MyMoneyDatabaseMgr::deletePair(const QString& key)
+{
+ MyMoneyKeyValueContainer::deletePair(key);
+}
+
+const QMap<QString, QString> MyMoneyDatabaseMgr::pairs(void) const
+{
+ return MyMoneyKeyValueContainer::pairs();
+}
+
+void MyMoneyDatabaseMgr::setPairs(const QMap<QString, QString>& list)
+{
+ MyMoneyKeyValueContainer::setPairs(list);
+}
+
+MyMoneyDatabaseMgr const * MyMoneyDatabaseMgr::duplicate(void)
+{
+ MyMoneyDatabaseMgr* that = new MyMoneyDatabaseMgr();
+ *that = *this;
+ return that;
+}
+
+void MyMoneyDatabaseMgr::addAccount(MyMoneyAccount& account)
+{
+ if (m_sql) {
+ // create the account.
+ MyMoneyAccount newAccount(nextAccountID(), account);
+
+ m_sql->addAccount(newAccount);
+ account = newAccount;
+ }
+}
+
+void MyMoneyDatabaseMgr::addAccount(MyMoneyAccount& parent, MyMoneyAccount& account)
+{
+ QMap<QString, MyMoneyAccount> accountList;
+ QStringList accountIdList;
+ QMap<QString, MyMoneyAccount>::ConstIterator theParent;
+ QMap<QString, MyMoneyAccount>::ConstIterator theChild;
+
+ accountIdList << parent.id() << account.id();
+ startTransaction();
+ accountList = m_sql->fetchAccounts(accountIdList, true);
+
+ theParent = accountList.find(parent.id());
+ if(theParent == accountList.end()) {
+ QString msg = "Unknown parent account '";
+ msg += parent.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ theChild = accountList.find(account.id());
+ if(theChild == accountList.end()) {
+ QString msg = "Unknown child account '";
+ msg += account.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ MyMoneyAccount acc = *theParent;
+ acc.addAccountId(account.id());
+ parent = acc;
+
+ acc = *theChild;
+ acc.setParentAccountId(parent.id());
+ account = acc;
+
+//FIXME: MyMoneyBalanceCacheItem balance;
+//FIXME: m_balanceCache[account.id()] = balance;
+
+ m_sql->modifyAccount(parent);
+ m_sql->modifyAccount(account);
+ commitTransaction();
+}
+
+void MyMoneyDatabaseMgr::addPayee(MyMoneyPayee& payee)
+{
+ if (m_sql) {
+ // create the payee
+ MyMoneyPayee newPayee(nextPayeeID(), payee);
+
+ m_sql->addPayee(newPayee);
+ payee = newPayee;
+ }
+}
+
+const MyMoneyPayee MyMoneyDatabaseMgr::payee(const QString& id) const
+{
+ QMap<QString, MyMoneyPayee>::ConstIterator it;
+ QMap<QString, MyMoneyPayee> payeeList = m_sql->fetchPayees(QString(id));
+ it = payeeList.find(id);
+ if(it == payeeList.end())
+ throw new MYMONEYEXCEPTION("Unknown payee '" + id + "'");
+
+ return *it;
+}
+
+const MyMoneyPayee MyMoneyDatabaseMgr::payeeByName(const QString& payee) const
+{
+ if(payee.isEmpty())
+ return MyMoneyPayee::null;
+
+ QMap<QString, MyMoneyPayee> payeeList;
+
+ TRY
+ payeeList = m_sql->fetchPayees();
+ PASS
+
+ QMap<QString, MyMoneyPayee>::ConstIterator it_p;
+
+ for(it_p = payeeList.begin(); it_p != payeeList.end(); ++it_p) {
+ if((*it_p).name() == payee) {
+ return *it_p;
+ }
+ }
+
+ throw new MYMONEYEXCEPTION("Unknown payee '" + payee + "'");
+}
+
+void MyMoneyDatabaseMgr::modifyPayee(const MyMoneyPayee& payee)
+{
+ QMap<QString, MyMoneyPayee> payeeList = m_sql->fetchPayees(QString(payee.id()), true);
+ QMap<QString, MyMoneyPayee>::ConstIterator it;
+
+ it = payeeList.find(payee.id());
+ if(it == payeeList.end()) {
+ QString msg = "Unknown payee '" + payee.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_sql->modifyPayee(payee);
+}
+
+void MyMoneyDatabaseMgr::removePayee(const MyMoneyPayee& payee)
+{
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ QMap<QString, MyMoneySchedule>::ConstIterator it_s;
+ QMap<QString, MyMoneyPayee> payeeList = m_sql->fetchPayees(QString(payee.id()));
+ QMap<QString, MyMoneyPayee>::ConstIterator it_p;
+
+ it_p = payeeList.find(payee.id());
+ if(it_p == payeeList.end()) {
+ QString msg = "Unknown payee '" + payee.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ // scan all transactions to check if the payee is still referenced
+ QMap<QString, MyMoneyTransaction> transactionList = m_sql->fetchTransactions(); // make sure they're all here
+ for(it_t = transactionList.begin(); it_t != transactionList.end(); ++it_t) {
+ if((*it_t).hasReferenceTo(payee.id())) {
+ throw new MYMONEYEXCEPTION(QString("Cannot remove payee that is still referenced to a %1").arg("transaction"));
+ }
+ }
+
+ // check referential integrity in schedules
+ QMap<QString, MyMoneySchedule> scheduleList = m_sql->fetchSchedules(); // make sure they're all here
+ for(it_s = scheduleList.begin(); it_s != scheduleList.end(); ++it_s) {
+ if((*it_s).hasReferenceTo(payee.id())) {
+ throw new MYMONEYEXCEPTION(QString("Cannot remove payee that is still referenced to a %1").arg("schedule"));
+ }
+ }
+ // remove any reference to report and/or budget
+ removeReferences(payee.id());
+
+ m_sql->removePayee(payee);
+}
+
+const QValueList<MyMoneyPayee> MyMoneyDatabaseMgr::payeeList(void) const
+{
+ if (m_sql)
+ return m_sql->fetchPayees().values();
+ else
+ return QValueList<MyMoneyPayee> ();
+}
+
+const MyMoneyAccount MyMoneyDatabaseMgr::account(const QString& id) const
+{
+ if (m_sql)
+ {
+ QMap <QString, MyMoneyAccount> accountList = m_sql->fetchAccounts(QString(id));
+ QMap <QString, MyMoneyAccount>::ConstIterator pos = accountList.find(id);
+
+ // locate the account and if present, return it's data
+ if(pos != accountList.end())
+ return *pos;
+ }
+
+ // throw an exception, if it does not exist
+ QString msg = "Unknown account id '" + id + "'";
+ throw new MYMONEYEXCEPTION(msg);
+}
+
+bool MyMoneyDatabaseMgr::isStandardAccount(const QString& id) const
+{
+ return id == STD_ACC_LIABILITY
+ || id == STD_ACC_ASSET
+ || id == STD_ACC_EXPENSE
+ || id == STD_ACC_INCOME
+ || id == STD_ACC_EQUITY;
+}
+
+void MyMoneyDatabaseMgr::setAccountName(const QString& id, const QString& name)
+{
+ if(!isStandardAccount(id))
+ throw new MYMONEYEXCEPTION("Only standard accounts can be modified using setAccountName()");
+
+ if (m_sql) {
+ startTransaction();
+ MyMoneyAccount acc = m_sql->fetchAccounts(QString(id), true) [id];
+ acc.setName(name);
+ m_sql->modifyAccount(acc);
+ commitTransaction();
+ }
+}
+
+void MyMoneyDatabaseMgr::addInstitution(MyMoneyInstitution& institution)
+{
+ if (m_sql) {
+ MyMoneyInstitution newInstitution(nextInstitutionID(), institution);
+
+ // mark file as changed
+ m_sql->addInstitution (newInstitution);
+
+ // return new data
+ institution = newInstitution;
+ }
+}
+
+const QString MyMoneyDatabaseMgr::nextPayeeID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementPayeeId()));
+ id = "P" + id.rightJustify(PAYEE_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextInstitutionID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementInstitutionId()));
+ id = "I" + id.rightJustify(INSTITUTION_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextAccountID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementAccountId()));
+ id = "A" + id.rightJustify(ACCOUNT_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextBudgetID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementBudgetId()));
+ id = "B" + id.rightJustify(BUDGET_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextReportID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementReportId()));
+ id = "R" + id.rightJustify(REPORT_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextTransactionID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementTransactionId()));
+ id = "T" + id.rightJustify(TRANSACTION_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextScheduleID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementScheduleId()));
+ id = "SCH" + id.rightJustify(SCHEDULE_ID_SIZE, '0');
+ }
+ return id;
+}
+
+const QString MyMoneyDatabaseMgr::nextSecurityID(void)
+{
+ QString id;
+ if (m_sql) {
+ id.setNum(ulong(m_sql->incrementSecurityId()));
+ id = "E" + id.rightJustify(SECURITY_ID_SIZE, '0');
+ }
+ return id;
+}
+
+void MyMoneyDatabaseMgr::addTransaction(MyMoneyTransaction& transaction, const bool skipAccountUpdate)
+{
+ // perform some checks to see that the transaction stuff is OK. For
+ // now we assume that
+ // * no ids are assigned
+ // * the date valid (must not be empty)
+ // * the referenced accounts in the splits exist
+
+ // first perform all the checks
+ if(!transaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION("transaction already contains an id");
+ if(!transaction.postDate().isValid())
+ throw new MYMONEYEXCEPTION("invalid post date");
+
+ // now check the splits
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following lines will throw an exception if the
+ // account or payee do not exist
+ account((*it_s).accountId());
+ if(!(*it_s).payeeId().isEmpty())
+ payee((*it_s).payeeId());
+ }
+
+ MyMoneyTransaction newTransaction(nextTransactionID(), transaction);
+ QString key = newTransaction.uniqueSortKey();
+
+ m_sql->addTransaction(newTransaction);
+
+ transaction = newTransaction;
+
+ // adjust the balance of all affected accounts
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ acc.adjustBalance((*it_s));
+ if(!skipAccountUpdate) {
+ acc.touch();
+//FIXME: invalidateBalanceCache(acc.id());
+ }
+ m_sql->modifyAccount(acc);
+ }
+}
+
+bool MyMoneyDatabaseMgr::hasActiveSplits(const QString& id) const
+{
+ QMap<QString, MyMoneyTransaction>::ConstIterator it;
+
+ MyMoneyTransactionFilter f(id);
+ QMap<QString, MyMoneyTransaction> transactionList = m_sql->fetchTransactions(f);
+
+ for(it = transactionList.begin(); it != transactionList.end(); ++it) {
+ if((*it).accountReferenced(id)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ /**
+ * This method is used to return the actual balance of an account
+ * without it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+//const MyMoneyMoney MyMoneyDatabaseMgr::balance(const QString& id, const QDate& date);
+
+const MyMoneyMoney MyMoneyDatabaseMgr::totalBalance(const QString& id, const QDate& date) const
+{
+ QStringList accounts;
+ QStringList::ConstIterator it_a;
+
+ MyMoneyMoney result; //(balance(id, date));
+
+ accounts = MyMoneyFile::instance()->account(id).accountList();
+ for (it_a = accounts.begin(); it_a != accounts.end(); ++it_a) {
+ accounts += MyMoneyFile::instance()->account(*it_a).accountList();
+ }
+ std::list <QString> tempList (accounts.begin(), accounts.end());
+ tempList.sort();;
+ tempList.unique();
+
+ accounts = QStringList(tempList);
+
+ QMap<QString, MyMoneyMoney> balanceMap = m_sql->fetchBalance(accounts, date);
+ for (QMap<QString, MyMoneyMoney>::ConstIterator it_b = balanceMap.begin(); it_b != balanceMap.end(); ++it_b) {
+ result += it_b.data();
+ }
+
+ return result;
+}
+
+const MyMoneyInstitution MyMoneyDatabaseMgr::institution(const QString& id) const
+{
+ QMap<QString, MyMoneyInstitution>::ConstIterator pos;
+ QMap<QString, MyMoneyInstitution> institutionList = m_sql->fetchInstitutions(QString(id));
+
+ pos = institutionList.find(id);
+ if(pos != institutionList.end())
+ return *pos;
+ throw new MYMONEYEXCEPTION("unknown institution");
+}
+
+bool MyMoneyDatabaseMgr::dirty(void) const
+{ return false; }
+
+void MyMoneyDatabaseMgr::setDirty(void)
+{}
+
+unsigned int MyMoneyDatabaseMgr::accountCount(void) const
+{
+ return m_sql->getRecCount("kmmAccounts");
+}
+
+const QValueList<MyMoneyInstitution> MyMoneyDatabaseMgr::institutionList(void) const
+{
+ if (m_sql) {
+ return m_sql->fetchInstitutions().values();
+ } else {
+ return QValueList<MyMoneyInstitution> ();
+ }
+}
+
+void MyMoneyDatabaseMgr::modifyAccount(const MyMoneyAccount& account, const bool skipCheck)
+{
+ QMap<QString, MyMoneyAccount>::ConstIterator pos;
+
+ // locate the account in the file global pool
+ startTransaction();
+ QMap<QString, MyMoneyAccount> accountList = m_sql->fetchAccounts (QString(account.id()), true);
+ pos = accountList.find(account.id());
+ if(pos != accountList.end()) {
+ // check if the new info is based on the old one.
+ // this is the case, when the file and the id
+ // as well as the type are equal.
+ if(((*pos).parentAccountId() == account.parentAccountId()
+ && (*pos).accountType() == account.accountType())
+ || skipCheck == true) {
+ // make sure that all the referenced objects exist
+ if(!account.institutionId().isEmpty())
+ institution(account.institutionId());
+
+ QValueList<QString>::ConstIterator it_a;
+ for(it_a = account.accountList().begin(); it_a != account.accountList().end(); ++it_a) {
+ this->account(*it_a);
+ }
+
+ // update information in account list
+ //m_accountList.modify(account.id(), account);
+
+ // invalidate cached balance
+//FIXME: invalidateBalanceCache(account.id());
+
+ // mark file as changed
+ m_sql->modifyAccount(account);
+ commitTransaction();
+ } else {
+ rollbackTransaction();
+ throw new MYMONEYEXCEPTION("Invalid information for update");
+ }
+
+ } else {
+ rollbackTransaction();
+ throw new MYMONEYEXCEPTION("Unknown account id");
+ }
+}
+
+void MyMoneyDatabaseMgr::modifyInstitution(const MyMoneyInstitution& institution)
+{
+ QMap<QString, MyMoneyInstitution> institutionList = m_sql->fetchInstitutions(QString(institution.id()));
+ QMap<QString, MyMoneyInstitution>::ConstIterator pos;
+
+ // locate the institution in the file global pool
+ pos = institutionList.find(institution.id());
+ if(pos != institutionList.end()) {
+ m_sql->modifyInstitution(institution);
+ } else
+ throw new MYMONEYEXCEPTION("unknown institution");
+}
+
+ /**
+ * This method is used to update a specific transaction in the
+ * transaction pool of the MyMoneyFile object
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to transaction to be changed
+ */
+void MyMoneyDatabaseMgr::modifyTransaction(const MyMoneyTransaction& transaction)
+{
+ QMap<QString, bool> modifiedAccounts;
+
+ // perform some checks to see that the transaction stuff is OK. For
+ // now we assume that
+ // * ids are assigned
+ // * the pointer to the MyMoneyFile object is not 0
+ // * the date valid (must not be empty)
+ // * the splits must have valid account ids
+
+ // first perform all the checks
+ if(transaction.id().isEmpty()
+// || transaction.file() != this
+ || !transaction.postDate().isValid())
+ throw new MYMONEYEXCEPTION("invalid transaction to be modified");
+
+ // now check the splits
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following lines will throw an exception if the
+ // account or payee do not exist
+ MyMoneyFile::instance()->account((*it_s).accountId());
+ if(!(*it_s).payeeId().isEmpty())
+ MyMoneyFile::instance()->payee((*it_s).payeeId());
+ }
+
+ // new data seems to be ok. find old version of transaction
+ // in our pool. Throw exception if unknown.
+// if(!m_transactionKeys.contains(transaction.id()))
+// throw new MYMONEYEXCEPTION("invalid transaction id");
+
+// QString oldKey = m_transactionKeys[transaction.id()];
+ QMap <QString, MyMoneyTransaction> transactionList = m_sql->fetchTransactions("('" + QString(transaction.id()) + "')");
+// if(transactionList.size() != 1)
+// throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+
+// it_t = transactionList.find(oldKey);
+ it_t = transactionList.begin();
+ if(it_t == transactionList.end())
+ throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ // mark all accounts referenced in old and new transaction data
+ // as modified
+ QMap<QString, MyMoneyAccount> accountList = m_sql->fetchAccounts();
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ MyMoneyAccount acc = accountList[(*it_s).accountId()];
+ acc.adjustBalance((*it_s), true);
+ acc.touch();
+//FIXME: invalidateBalanceCache(acc.id());
+ //m_accountList.modify(acc.id(), acc);
+ m_sql->modifyAccount(acc);
+ //modifiedAccounts[(*it_s).accountId()] = true;
+ }
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = accountList[(*it_s).accountId()];
+ acc.adjustBalance((*it_s));
+ acc.touch();
+//FIXME: invalidateBalanceCache(acc.id());
+ //m_accountList.modify(acc.id(), acc);
+ m_sql->modifyAccount(acc);
+ //modifiedAccounts[(*it_s).accountId()] = true;
+ }
+
+ // remove old transaction from lists
+// m_sql->removeTransaction(oldKey);
+
+ // add new transaction to lists
+ // QString newKey = transaction.uniqueSortKey();
+// m_sql->insertTransaction(newKey, transaction);
+ //m_transactionKeys.modify(transaction.id(), newKey);
+
+ // mark file as changed
+ m_sql->modifyTransaction(transaction);
+}
+
+void MyMoneyDatabaseMgr::reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent)
+{
+ if(account.accountType() == MyMoneyAccount::Stock && parent.accountType() != MyMoneyAccount::Investment)
+ throw new MYMONEYEXCEPTION("Cannot move a stock acocunt into a non-investment account");
+
+ QStringList accountIdList;
+ QMap<QString, MyMoneyAccount>::ConstIterator oldParent;
+ QMap<QString, MyMoneyAccount>::ConstIterator newParent;
+ QMap<QString, MyMoneyAccount>::ConstIterator childAccount;
+
+ // verify that accounts exist. If one does not,
+ // an exception is thrown
+ accountIdList << account.id() << parent.id();
+ MyMoneyDatabaseMgr::account(account.id());
+ MyMoneyDatabaseMgr::account(parent.id());
+
+ if(!account.parentAccountId().isEmpty()) {
+ accountIdList << account.parentAccountId();
+ }
+
+ startTransaction();
+ QMap<QString, MyMoneyAccount> accountList = m_sql->fetchAccounts(accountIdList, true);
+
+ if(!account.parentAccountId().isEmpty()) {
+ MyMoneyDatabaseMgr::account(account.parentAccountId());
+ oldParent = accountList.find(account.parentAccountId());
+ }
+
+ newParent = accountList.find(parent.id());
+ childAccount = accountList.find(account.id());
+
+ MyMoneyAccount acc;
+ if(!account.parentAccountId().isEmpty()) {
+ acc = (*oldParent);
+ acc.removeAccountId(account.id());
+ m_sql->modifyAccount(acc);
+ }
+
+ parent = (*newParent);
+ parent.addAccountId(account.id());
+
+ account = (*childAccount);
+ account.setParentAccountId(parent.id());
+
+ m_sql->modifyAccount(parent);
+ m_sql->modifyAccount(account);
+ commitTransaction();
+}
+
+void MyMoneyDatabaseMgr::removeTransaction(const MyMoneyTransaction& transaction)
+{
+ QMap<QString, bool> modifiedAccounts;
+
+ // first perform all the checks
+ if(transaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION("invalid transaction to be deleted");
+
+ QMap<QString, QString>::ConstIterator it_k;
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+
+// it_k = m_transactionKeys.find(transaction.id());
+// if(it_k == m_transactionKeys.end())
+// throw new MYMONEYEXCEPTION("invalid transaction to be deleted");
+
+ QMap <QString, MyMoneyTransaction> transactionList = m_sql->fetchTransactions("('" + QString(transaction.id()) + "')");
+// it_t = transactionList.find(*it_k);
+ it_t = transactionList.begin();
+ if(it_t == transactionList.end())
+ throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ // scan the splits and collect all accounts that need
+ // to be updated after the removal of this transaction
+ QMap<QString, MyMoneyAccount> accountList = m_sql->fetchAccounts();
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ MyMoneyAccount acc = accountList[(*it_s).accountId()];
+// modifiedAccounts[(*it_s).accountId()] = true;
+ acc.adjustBalance((*it_s), true);
+ acc.touch();
+ m_sql->modifyAccount(acc);
+//FIXME: invalidateBalanceCache(acc.id());
+ }
+
+ // FIXME: check if any split is frozen and throw exception
+
+ // remove the transaction from the two lists
+ //m_transactionList.remove(*it_k);
+// m_transactionKeys.remove(transaction.id());
+
+ // mark file as changed
+ m_sql->removeTransaction(transaction);
+}
+
+unsigned int MyMoneyDatabaseMgr::transactionCount(const QString& account) const
+{ return (m_sql->transactionCount(account)); }
+
+const QMap<QString, unsigned long> MyMoneyDatabaseMgr::transactionCountMap(void) const
+{ return (m_sql->transactionCountMap()); }
+
+const QValueList<MyMoneyTransaction> MyMoneyDatabaseMgr::transactionList(MyMoneyTransactionFilter& filter) const
+{
+ QValueList<MyMoneyTransaction> list;
+ transactionList(list, filter);
+ return list;
+}
+
+void MyMoneyDatabaseMgr::transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const
+{
+ list.clear();
+
+ TRY
+ if (m_sql) list = m_sql->fetchTransactions(filter).values();
+ PASS
+}
+
+void MyMoneyDatabaseMgr::transactionList(QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const
+{
+ list.clear();
+ MyMoneyMap<QString, MyMoneyTransaction> transactionList;
+ TRY
+ if (m_sql) transactionList = m_sql->fetchTransactions(filter);
+ PASS
+
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ QMap<QString, MyMoneyTransaction>::ConstIterator txEnd = transactionList.end();
+
+ for(it_t = transactionList.begin(); it_t != txEnd; ++it_t) {
+ if(filter.match(*it_t)) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = filter.matchingSplits().begin(); it_s != filter.matchingSplits().end(); ++it_s) {
+ list.append(qMakePair(*it_t, *it_s));
+ }
+ }
+ }
+}
+
+void MyMoneyDatabaseMgr::removeAccount(const MyMoneyAccount& account)
+{
+ MyMoneyAccount parent;
+
+ // check that the account and it's parent exist
+ // this will throw an exception if the id is unknown
+ MyMoneyDatabaseMgr::account(account.id());
+ parent = MyMoneyDatabaseMgr::account(account.parentAccountId());
+
+ // check that it's not one of the standard account groups
+ if(isStandardAccount(account.id()))
+ throw new MYMONEYEXCEPTION("Unable to remove the standard account groups");
+
+ if(hasActiveSplits(account.id())) {
+ throw new MYMONEYEXCEPTION("Unable to remove account with active splits");
+ }
+
+ // re-parent all sub-ordinate accounts to the parent of the account
+ // to be deleted. First round check that all accounts exist, second
+ // round do the re-parenting.
+ QStringList::ConstIterator it;
+ for(it = account.accountList().begin(); it != account.accountList().end(); ++it) {
+ MyMoneyDatabaseMgr::account(*it);
+ }
+
+ // if one of the accounts did not exist, an exception had been
+ // thrown and we would not make it until here.
+
+ QStringList accountIdList;
+ accountIdList << parent.id() << account.id();
+ startTransaction();
+ QMap<QString, MyMoneyAccount> accountList = m_sql->fetchAccounts(accountIdList, true);
+
+ QMap<QString, MyMoneyAccount>::ConstIterator it_a;
+ QMap<QString, MyMoneyAccount>::ConstIterator it_p;
+
+ // locate the account in the file global pool
+
+ it_a = accountList.find(account.id());
+ if(it_a == accountList.end())
+ throw new MYMONEYEXCEPTION("Internal error: account not found in list");
+
+ it_p = accountList.find(parent.id());
+ if(it_p == accountList.end())
+ throw new MYMONEYEXCEPTION("Internal error: parent account not found in list");
+
+ if(!account.institutionId().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot remove account still attached to an institution");
+
+ // FIXME: check referential integrity for the account to be removed
+
+ // check if the new info is based on the old one.
+ // this is the case, when the file and the id
+ // as well as the type are equal.
+ if((*it_a).id() == account.id()
+ && (*it_a).accountType() == account.accountType()) {
+
+ // second round over sub-ordinate accounts: do re-parenting
+ // but only if the list contains at least one entry
+ // FIXME: move this logic to MyMoneyFile
+ if((*it_a).accountList().count() > 0) {
+ for(it = (*it_a).accountList().begin(); it != (*it_a).accountList().end(); ++it) {
+ MyMoneyAccount acc(MyMoneyDatabaseMgr::account(*it));
+ reparentAccount(acc, parent);//, false);
+ }
+ }
+ // remove account from parent's list
+ parent.removeAccountId(account.id());
+ m_sql->modifyAccount(parent);
+
+ // remove account from the global account pool
+ //m_accountList.remove(account.id());
+
+ // remove from balance list
+//FIXME: m_balanceCache.remove(account.id());
+//FIXME: invalidateBalanceCache(parent.id());
+
+ m_sql->removeAccount(account);
+ }
+ commitTransaction();
+}
+
+void MyMoneyDatabaseMgr::removeInstitution(const MyMoneyInstitution& institution)
+{
+ QMap<QString, MyMoneyInstitution> institutionList = m_sql->fetchInstitutions(QString(institution.id()));
+ QMap<QString, MyMoneyInstitution>::ConstIterator it_i;
+
+ it_i = institutionList.find(institution.id());
+ if(it_i != institutionList.end()) {
+ // mark file as changed
+ m_sql->removeInstitution(institution);
+ } else
+ throw new MYMONEYEXCEPTION("invalid institution");
+}
+
+const MyMoneyTransaction MyMoneyDatabaseMgr::transaction(const QString& id) const
+{
+ // get the full key of this transaction, throw exception
+ // if it's invalid (unknown)
+ //if(!m_transactionKeys.contains(id))
+ // throw new MYMONEYEXCEPTION("invalid transaction id");
+
+ // check if this key is in the list, throw exception if not
+ //QString key = m_transactionKeys[id];
+ QMap <QString, MyMoneyTransaction> transactionList = m_sql->fetchTransactions("('" + QString(id) + "')");
+
+ //there should only be one transaction in the map, if it was found, so check the size of the map
+ //return the first element.
+ //if(!transactionList.contains(key))
+ if(!transactionList.size())
+ throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ return transactionList.begin().data();
+}
+
+const MyMoneyMoney MyMoneyDatabaseMgr::balance(const QString& id, const QDate& date) const
+{
+ QStringList idList;
+ idList.append(id);
+ QMap<QString,MyMoneyMoney> tempMap = m_sql->fetchBalance(idList, date);
+
+ MyMoneyMoney returnValue = tempMap[id];
+ if (returnValue != MyMoneyMoney()) {
+ return returnValue;
+ }
+
+//DEBUG
+ QDate date_ (date);
+ //if (date_ == QDate()) date_ = QDate::currentDate();
+// END DEBUG
+
+ MyMoneyMoney result(0);
+ MyMoneyAccount acc;
+ QMap<QString, MyMoneyAccount> accountList = m_sql->fetchAccounts(/*QString(id)*/);
+ //QMap<QString, MyMoneyAccount>::const_iterator accpos = accountList.find(id);
+ if (date_ != QDate()) qDebug ("request balance for %s at %s", id.data(), date_.toString(Qt::ISODate).latin1());
+// if(!date_.isValid() && MyMoneyFile::instance()->account(id).accountType() != MyMoneyAccount::Stock) {
+// if(accountList.find(id) != accountList.end())
+// return accountList[id].balance();
+// return MyMoneyMoney(0);
+// }
+ if(/*m_balanceCache[id].valid == false || date != m_balanceCacheDate) || */ m_sql != 0) {
+ QMap<QString, MyMoneyMoney> balances;
+ QMap<QString, MyMoneyMoney>::ConstIterator it_b;
+//FIXME: if (date != m_balanceCacheDate) {
+//FIXME: m_balanceCache.clear();
+//FIXME: m_balanceCacheDate = date;
+//FIXME: }
+
+ QValueList<MyMoneyTransaction>::ConstIterator it_t;
+ QValueList<MyMoneyTransaction>::ConstIterator txEnd;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ MyMoneyTransactionFilter filter;
+ filter.addAccount(id);
+ filter.setDateFilter(QDate(), date_);
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> list = transactionList(filter);
+
+ txEnd = list.end();
+ for(it_t = list.begin(); it_t != txEnd; ++it_t) {
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s){
+ const QString aid = (*it_s).accountId();
+ if((*it_s).action() == MyMoneySplit::ActionSplitShares) {
+ balances[aid] = balances[aid] * (*it_s).shares();
+ } else {
+ balances[aid] += (*it_s).value((*it_t).commodity(), accountList[aid].currencyId());
+ }
+ }
+ }
+
+ // fill the found balances into the cache
+//FIXME: for(it_b = balances.begin(); it_b != balances.end(); ++it_b) {
+//FIXME: MyMoneyBalanceCacheItem balance(*it_b);
+//FIXME: m_balanceCache[it_b.key()] = balance;
+//FIXME: }
+
+ // fill all accounts w/o transactions to zero
+// if (m_sql != 0) {
+// QMap<QString, MyMoneyAccount>::ConstIterator it_a;
+// for(it_a = m_accountList.begin(); it_a != m_accountList.end(); ++it_a) {
+//FIXME: if(m_balanceCache[(*it_a).id()].valid == false) {
+//FIXME: MyMoneyBalanceCacheItem balance(MyMoneyMoney(0,1));
+//FIXME: m_balanceCache[(*it_a).id()] = balance;
+//FIXME: }
+// }
+// }
+
+ result = balances[id];
+
+ }
+
+//FIXME: if(m_balanceCache[id].valid == true)
+//FIXME: result = m_balanceCache[id].balance;
+//FIXME: else
+//FIXME: qDebug("Cache mishit should never happen at this point");
+
+ return result;
+}
+
+const MyMoneyTransaction MyMoneyDatabaseMgr::transaction(const QString& account, const int idx) const
+{
+/* removed with MyMoneyAccount::Transaction
+ QMap<QString, MyMoneyAccount>::ConstIterator acc;
+
+ // find account object in list, throw exception if unknown
+ acc = m_accountList.find(account);
+ if(acc == m_accountList.end())
+ throw new MYMONEYEXCEPTION("unknown account id");
+
+ // get the transaction info from the account
+ MyMoneyAccount::Transaction t = (*acc).transaction(idx);
+
+ // return the transaction, throw exception if not found
+ return transaction(t.transactionID());
+*/
+
+ // new implementation if the above code does not work anymore
+ QValueList<MyMoneyTransaction> list;
+ //MyMoneyAccount acc = m_accountList[account];
+ MyMoneyAccount acc = m_sql->fetchAccounts(QString(account)) [account];
+ MyMoneyTransactionFilter filter;
+
+ if(acc.accountGroup() == MyMoneyAccount::Income
+ || acc.accountGroup() == MyMoneyAccount::Expense)
+ filter.addCategory(account);
+ else
+ filter.addAccount(account);
+
+ transactionList(list, filter);
+ if(idx < 0 || idx >= static_cast<int> (list.count()))
+ throw new MYMONEYEXCEPTION("Unknown idx for transaction");
+
+ return transaction(list[idx].id());
+}
+
+unsigned int MyMoneyDatabaseMgr::institutionCount(void) const
+{
+ return m_sql->getRecCount("kmmInstitutions");
+}
+
+void MyMoneyDatabaseMgr::accountList(QValueList<MyMoneyAccount>& list) const
+{
+ QMap <QString, MyMoneyAccount> accountList;
+ if (m_sql) accountList = m_sql->fetchAccounts();
+ QMap<QString, MyMoneyAccount>::ConstIterator it;
+ QMap<QString, MyMoneyAccount>::ConstIterator accEnd = accountList.end();
+ for(it = accountList.begin(); it != accEnd; ++it) {
+ if(!isStandardAccount((*it).id())) {
+ list.append(*it);
+ }
+ }
+}
+
+const MyMoneyAccount MyMoneyDatabaseMgr::liability(void) const
+{ return MyMoneyFile::instance()->account(STD_ACC_LIABILITY); }
+
+const MyMoneyAccount MyMoneyDatabaseMgr::asset(void) const
+{ return MyMoneyFile::instance()->account(STD_ACC_ASSET); }
+
+const MyMoneyAccount MyMoneyDatabaseMgr::expense(void) const
+{ return MyMoneyFile::instance()->account(STD_ACC_EXPENSE); }
+
+const MyMoneyAccount MyMoneyDatabaseMgr::income(void) const
+{ return MyMoneyFile::instance()->account(STD_ACC_INCOME); }
+
+const MyMoneyAccount MyMoneyDatabaseMgr::equity(void) const
+{ return MyMoneyFile::instance()->account(STD_ACC_EQUITY); }
+
+void MyMoneyDatabaseMgr::addSecurity(MyMoneySecurity& security)
+{
+ // create the account
+ MyMoneySecurity newSecurity(nextSecurityID(), security);
+
+ m_sql->addSecurity(newSecurity);
+ security = newSecurity;
+}
+
+void MyMoneyDatabaseMgr::modifySecurity(const MyMoneySecurity& security)
+{
+ QMap<QString, MyMoneySecurity> securitiesList = m_sql->fetchSecurities(QString(security.id()), true);
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = securitiesList.find(security.id());
+ if(it == securitiesList.end())
+ {
+ QString msg = "Unknown security '";
+ msg += security.id() + "' during modifySecurity()";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_sql->modifySecurity(security);
+}
+
+void MyMoneyDatabaseMgr::removeSecurity(const MyMoneySecurity& security)
+{
+ QMap<QString, MyMoneySecurity> securitiesList = m_sql->fetchSecurities(QString(security.id()));
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ // FIXME: check referential integrity
+
+ it = securitiesList.find(security.id());
+ if(it == securitiesList.end())
+ {
+ QString msg = "Unknown security '";
+ msg += security.id() + "' during removeSecurity()";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_sql->removeSecurity(security);
+}
+
+const MyMoneySecurity MyMoneyDatabaseMgr::security(const QString& id) const
+{
+ QMap<QString, MyMoneySecurity> securitiesList = m_sql->fetchSecurities(QString(id));
+ QMap<QString, MyMoneySecurity>::ConstIterator it = securitiesList.find(id);
+ if(it != securitiesList.end())
+ {
+ return it.data();
+ }
+
+ return MyMoneySecurity();
+}
+
+const QValueList<MyMoneySecurity> MyMoneyDatabaseMgr::securityList(void) const
+{ return m_sql->fetchSecurities().values(); }
+
+void MyMoneyDatabaseMgr::addPrice(const MyMoneyPrice& price)
+{
+ MyMoneyPriceEntries::ConstIterator it;
+ MyMoneyPriceList priceList = m_sql->fetchPrices();
+ it = priceList[MyMoneySecurityPair(price.from(), price.to())].find(price.date());
+ // do not replace, if the information did not change.
+ if(it != priceList[MyMoneySecurityPair(price.from(), price.to())].end()) {
+ if((*it).rate((*it).to()) == price.rate(price.to())
+ && (*it).source() == price.source())
+ return;
+ }
+
+ m_sql->addPrice(price);
+}
+
+void MyMoneyDatabaseMgr::removePrice(const MyMoneyPrice& price)
+{
+ m_sql->removePrice(price);
+}
+
+const MyMoneyPrice MyMoneyDatabaseMgr::price(const QString& fromId, const QString& toId, const QDate& _date, const bool exactDate) const
+{
+ return m_sql->fetchSinglePrice(fromId, toId, _date, exactDate);
+}
+
+const MyMoneyPriceList MyMoneyDatabaseMgr::priceList(void) const
+{ return m_sql->fetchPrices(); }
+
+void MyMoneyDatabaseMgr::addSchedule(MyMoneySchedule& sched)
+{
+ // first perform all the checks
+ if(!sched.id().isEmpty())
+ throw new MYMONEYEXCEPTION("schedule already contains an id");
+
+ // The following will throw an exception when it fails
+ sched.validate(false);
+
+ if (m_sql) {
+ startTransaction();
+ sched = MyMoneySchedule (nextScheduleID(), sched);
+
+ m_sql->addSchedule(sched);
+ commitTransaction();
+ }
+}
+
+void MyMoneyDatabaseMgr::modifySchedule(const MyMoneySchedule& sched)
+{
+ QMap<QString, MyMoneySchedule> scheduleList = m_sql->fetchSchedules(QString(sched.id()));
+ QMap<QString, MyMoneySchedule>::ConstIterator it;
+
+ it = scheduleList.find(sched.id());
+ if(it == scheduleList.end()) {
+ QString msg = "Unknown schedule '" + sched.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_sql->modifySchedule(sched);
+}
+
+void MyMoneyDatabaseMgr::removeSchedule(const MyMoneySchedule& sched)
+{
+ QMap<QString, MyMoneySchedule> scheduleList = m_sql->fetchSchedules(QString(sched.id()));
+ QMap<QString, MyMoneySchedule>::ConstIterator it;
+
+ it = scheduleList.find(sched.id());
+ if(it == scheduleList.end()) {
+ QString msg = "Unknown schedule '" + sched.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ // FIXME: check referential integrity for loan accounts
+
+ m_sql->removeSchedule(sched);
+}
+
+const MyMoneySchedule MyMoneyDatabaseMgr::schedule(const QString& id) const
+{
+ QMap<QString, MyMoneySchedule> scheduleList = m_sql->fetchSchedules(QString(id));
+ QMap<QString, MyMoneySchedule>::ConstIterator pos;
+
+ // locate the schedule and if present, return it's data
+ pos = scheduleList.find(id);
+ if(pos != scheduleList.end())
+ return (*pos);
+
+ // throw an exception, if it does not exist
+ QString msg = "Unknown schedule id '" + id + "'";
+ throw new MYMONEYEXCEPTION(msg);
+}
+
+const QValueList<MyMoneySchedule> MyMoneyDatabaseMgr::scheduleList(const QString& accountId,
+ const MyMoneySchedule::typeE type,
+ const MyMoneySchedule::occurenceE occurence,
+ const MyMoneySchedule::paymentTypeE paymentType,
+ const QDate& startDate,
+ const QDate& endDate,
+ const bool overdue) const
+{
+ QMap<QString, MyMoneySchedule> scheduleList;
+ if (m_sql) scheduleList = m_sql->fetchSchedules();
+ QMap<QString, MyMoneySchedule>::ConstIterator pos;
+ QValueList<MyMoneySchedule> list;
+
+ // qDebug("scheduleList()");
+
+ for(pos = scheduleList.begin(); pos != scheduleList.end(); ++pos) {
+ // qDebug(" '%s'", (*pos).id().data());
+
+ if(type != MyMoneySchedule::TYPE_ANY) {
+ if(type != (*pos).type()) {
+ continue;
+ }
+ }
+
+ if(occurence != MyMoneySchedule::OCCUR_ANY) {
+ if(occurence != (*pos).occurence()) {
+ continue;
+ }
+ }
+
+ if(paymentType != MyMoneySchedule::STYPE_ANY) {
+ if(paymentType != (*pos).paymentType()) {
+ continue;
+ }
+ }
+
+ if(!accountId.isEmpty()) {
+ MyMoneyTransaction t = (*pos).transaction();
+ QValueList<MyMoneySplit>::ConstIterator it;
+ QValueList<MyMoneySplit> splits;
+ splits = t.splits();
+ for(it = splits.begin(); it != splits.end(); ++it) {
+ if((*it).accountId() == accountId)
+ break;
+ }
+ if(it == splits.end()) {
+ continue;
+ }
+ }
+
+ if(startDate.isValid() && endDate.isValid()) {
+ if((*pos).paymentDates(startDate, endDate).count() == 0) {
+ continue;
+ }
+ }
+
+ if(startDate.isValid() && !endDate.isValid()) {
+ if(!(*pos).nextPayment(startDate.addDays(-1)).isValid()) {
+ continue;
+ }
+ }
+
+ if(!startDate.isValid() && endDate.isValid()) {
+ if((*pos).startDate() > endDate) {
+ continue;
+ }
+ }
+
+ if(overdue) {
+ if (!(*pos).isOverdue())
+ continue;
+/*
+ QDate nextPayment = (*pos).nextPayment((*pos).lastPayment());
+ if(!nextPayment.isValid())
+ continue;
+ if(nextPayment >= QDate::currentDate())
+ continue;
+*/
+ }
+
+ // qDebug("Adding '%s'", (*pos).name().latin1());
+ list << *pos;
+ }
+ return list;
+}
+
+const QValueList<MyMoneySchedule> MyMoneyDatabaseMgr::scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts) const
+{
+// qDebug("scheduleListEx");
+ QMap<QString, MyMoneySchedule> scheduleList = m_sql->fetchSchedules();
+ QMap<QString, MyMoneySchedule>::ConstIterator pos;
+ QValueList<MyMoneySchedule> list;
+
+ if (!startDate.isValid())
+ return list;
+
+ for(pos = scheduleList.begin(); pos != scheduleList.end(); ++pos)
+ {
+ if (scheduleTypes && !(scheduleTypes & (*pos).type()))
+ continue;
+
+ if (scheduleOcurrences && !(scheduleOcurrences & (*pos).occurence()))
+ continue;
+
+ if (schedulePaymentTypes && !(schedulePaymentTypes & (*pos).paymentType()))
+ continue;
+
+ if((*pos).paymentDates(startDate, startDate).count() == 0)
+ continue;
+
+ if ((*pos).isFinished())
+ continue;
+
+ if ((*pos).hasRecordedPayment(startDate))
+ continue;
+
+ if (accounts.count() > 0)
+ {
+ if (accounts.contains((*pos).account().id()))
+ continue;
+ }
+
+// qDebug("\tAdding '%s'", (*pos).name().latin1());
+ list << *pos;
+ }
+
+ return list;
+}
+
+void MyMoneyDatabaseMgr::addCurrency(const MyMoneySecurity& currency)
+{
+ if (m_sql) {
+ QMap<QString, MyMoneySecurity> currencyList = m_sql->fetchCurrencies(QString(currency.id()));
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = currencyList.find(currency.id());
+ if(it != currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot add currency with existing id %1").arg(currency.id().data()));
+ }
+
+ m_sql->addCurrency(currency);
+ }
+}
+
+void MyMoneyDatabaseMgr::modifyCurrency(const MyMoneySecurity& currency)
+{
+ QMap<QString, MyMoneySecurity> currencyList = m_sql->fetchCurrencies(QString(currency.id()));
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = currencyList.find(currency.id());
+ if(it == currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot modify currency with unknown id %1").arg(currency.id().data()));
+ }
+
+ m_sql->modifyCurrency(currency);
+}
+
+void MyMoneyDatabaseMgr::removeCurrency(const MyMoneySecurity& currency)
+{
+ QMap<QString, MyMoneySecurity> currencyList = m_sql->fetchCurrencies(QString(currency.id()));
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ // FIXME: check referential integrity
+
+ it = currencyList.find(currency.id());
+ if(it == currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot remove currency with unknown id %1").arg(currency.id().data()));
+ }
+
+ m_sql->removeCurrency(currency);
+}
+
+const MyMoneySecurity MyMoneyDatabaseMgr::currency(const QString& id) const
+{
+ if(id.isEmpty()) {
+
+ }
+ QMap<QString, MyMoneySecurity> currencyList = m_sql->fetchCurrencies(QString(id));
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = currencyList.find(id);
+ if(it == currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot retrieve currency with unknown id '%1'").arg(id.data()));
+ }
+
+ return *it;
+}
+
+const QValueList<MyMoneySecurity> MyMoneyDatabaseMgr::currencyList(void) const
+{
+ if (m_sql) {
+ return m_sql->fetchCurrencies().values();
+ } else {
+ return QValueList<MyMoneySecurity> ();
+ }
+}
+
+const QValueList<MyMoneyReport> MyMoneyDatabaseMgr::reportList( void ) const
+{
+ if (m_sql) {
+ return m_sql->fetchReports().values();
+ } else {
+ return QValueList<MyMoneyReport> ();
+ }
+}
+
+void MyMoneyDatabaseMgr::addReport( MyMoneyReport& report )
+{
+ if(!report.id().isEmpty())
+ throw new MYMONEYEXCEPTION("transaction already contains an id");
+
+ MyMoneyReport newReport(nextReportID(), report);
+ report = newReport;
+ m_sql->addReport(newReport);
+ //m_sql->addReport(MyMoneyReport (nextReportID(), report));
+}
+
+void MyMoneyDatabaseMgr::modifyReport( const MyMoneyReport& report )
+{
+ QMap<QString, MyMoneyReport> reportList = m_sql->fetchReports(QString(report.id()));
+ QMap<QString, MyMoneyReport>::ConstIterator it;
+
+ it = reportList.find(report.id());
+ if(it == reportList.end()) {
+ QString msg = "Unknown report '" + report.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_sql->modifyReport(report);
+}
+
+unsigned MyMoneyDatabaseMgr::countReports( void ) const
+{
+ return m_sql->getRecCount("kmmReports");
+}
+
+const MyMoneyReport MyMoneyDatabaseMgr::report( const QString& id ) const
+{
+ return m_sql->fetchReports(QString(id))[id];
+}
+
+void MyMoneyDatabaseMgr::removeReport(const MyMoneyReport& report)
+{
+ QMap<QString, MyMoneyReport> reportList = m_sql->fetchReports(QString(report.id()));
+ QMap<QString, MyMoneyReport>::ConstIterator it;
+
+ it = reportList.find(report.id());
+ if(it == reportList.end()) {
+ QString msg = "Unknown report '" + report.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_sql->removeReport(report);
+}
+
+const QValueList<MyMoneyBudget> MyMoneyDatabaseMgr::budgetList( void ) const
+{
+ return m_sql->fetchBudgets().values();
+}
+
+void MyMoneyDatabaseMgr::addBudget( MyMoneyBudget& budget )
+{
+ MyMoneyBudget newBudget(nextBudgetID(), budget);
+ m_sql->addBudget(newBudget);
+}
+
+const MyMoneyBudget MyMoneyDatabaseMgr::budgetByName(const QString& budget) const
+{
+ QMap<QString, MyMoneyBudget> budgets = m_sql->fetchBudgets();
+ QMap<QString, MyMoneyBudget>::ConstIterator it_p;
+
+ for(it_p = budgets.begin(); it_p != budgets.end(); ++it_p) {
+ if((*it_p).name() == budget) {
+ return *it_p;
+ }
+ }
+
+ throw new MYMONEYEXCEPTION("Unknown budget '" + budget + "'");
+}
+
+void MyMoneyDatabaseMgr::modifyBudget( const MyMoneyBudget& budget )
+{
+ //QMap<QString, MyMoneyBudget>::ConstIterator it;
+
+ //it = m_budgetList.find(budget.id());
+ //if(it == m_budgetList.end()) {
+ // QString msg = "Unknown budget '" + budget.id() + "'";
+ // throw new MYMONEYEXCEPTION(msg);
+ //}
+ //m_budgetList.modify(budget.id(), budget);
+
+ startTransaction();
+ if (m_sql->fetchBudgets(QString(budget.id()), true).empty()) {
+ QString msg = "Unknown budget '" + budget.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+ m_sql->modifyBudget(budget);
+ commitTransaction();
+}
+
+unsigned MyMoneyDatabaseMgr::countBudgets( void ) const
+{
+ return m_sql->getRecCount("kmmBudgetConfig");
+}
+
+MyMoneyBudget MyMoneyDatabaseMgr::budget( const QString& id ) const
+{
+ return m_sql->fetchBudgets(QString(id)) [id];
+}
+
+void MyMoneyDatabaseMgr::removeBudget(const MyMoneyBudget& budget)
+{
+// QMap<QString, MyMoneyBudget>::ConstIterator it;
+//
+// it = m_budgetList.find(budget.id());
+// if(it == m_budgetList.end()) {
+// QString msg = "Unknown budget '" + budget.id() + "'";
+// throw new MYMONEYEXCEPTION(msg);
+// }
+//
+ m_sql->removeBudget(budget);
+}
+
+void MyMoneyDatabaseMgr::clearCache(void)
+{
+ //m_balanceCache.clear();
+}
+
+class isReferencedHelper {
+ public:
+ isReferencedHelper(const QString& id)
+ : m_id (id)
+ {}
+
+ inline bool operator() (const MyMoneyObject& obj) const
+ { return obj.hasReferenceTo(m_id); }
+
+ private:
+ QString m_id;
+};
+
+bool MyMoneyDatabaseMgr::isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipCheck) const
+{
+ bool rc = false;
+ const QString& id = obj.id();
+
+ MyMoneyPriceList::const_iterator it_pr;
+
+ MyMoneyPriceList::const_iterator priceEnd;
+
+ // FIXME optimize the list of objects we have to checks
+ // with a bit of knowledge of the internal structure, we
+ // could optimize the number of objects we check for references
+
+ // Scan all engine objects for a reference
+ if(!skipCheck[RefCheckTransaction]) {
+ bool skipTransactions = false;
+ MyMoneyTransactionFilter f;
+ if (typeid(obj) == typeid(MyMoneyAccount)) {
+ f.addAccount(obj.id());
+ } else if (typeid(obj) == typeid(MyMoneyCategory)) {
+ f.addCategory(obj.id());
+ } else if (typeid(obj) == typeid(MyMoneyPayee)) {
+ f.addPayee(obj.id());
+ } // if it's anything else, I guess we just read everything
+ //FIXME: correction, transactions can only have a reference to an account or payee,
+ // so, read nothing.
+ else {
+ skipTransactions = true;
+ }
+ if (! skipTransactions) {
+ //QMap <QString, MyMoneyTransaction> transactionList = m_sql->fetchTransactions(f);
+ //rc = (transactionList.end() != std::find_if(transactionList.begin(), transactionList.end(), isReferencedHelper(id)));
+ //if (rc != m_sql->isReferencedByTransaction(obj.id()))
+ // qDebug ("Transaction match inconsistency.");
+ rc = m_sql->isReferencedByTransaction(obj.id());
+ }
+ }
+
+ if(!skipCheck[RefCheckAccount] && !rc) {
+ QValueList<MyMoneyAccount> accountList;
+ MyMoneyFile::instance()->accountList(accountList);
+ rc = (accountList.end() != std::find_if(accountList.begin(), accountList.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckInstitution] && !rc) {
+ QValueList<MyMoneyInstitution> institutionList;
+ MyMoneyFile::instance()->institutionList(institutionList);
+ rc = (institutionList.end() != std::find_if(institutionList.begin(), institutionList.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckPayee] && !rc) {
+ QValueList<MyMoneyPayee> payeeList = MyMoneyFile::instance()->payeeList();
+ rc = (payeeList.end() != std::find_if(payeeList.begin(), payeeList.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckReport] && !rc) {
+ QMap<QString, MyMoneyReport> reportList = m_sql->fetchReports();
+ rc = (reportList.end() != std::find_if(reportList.begin(), reportList.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckBudget] && !rc) {
+ QMap<QString, MyMoneyBudget> budgets = m_sql->fetchBudgets();
+ rc = (budgets.end() != std::find_if(budgets.begin(), budgets.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckSchedule] && !rc) {
+ QMap<QString, MyMoneySchedule> scheduleList = m_sql->fetchSchedules();
+ rc = (scheduleList.end() != std::find_if(scheduleList.begin(), scheduleList.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckSecurity] && !rc) {
+ QValueList<MyMoneySecurity> securitiesList = MyMoneyFile::instance()->securityList();
+ rc = (securitiesList.end() != std::find_if(securitiesList.begin(), securitiesList.end(), isReferencedHelper(id)));
+ }
+ if(!skipCheck[RefCheckCurrency] && !rc) {
+ QValueList<MyMoneySecurity> currencyList = m_sql->fetchCurrencies().values();
+ rc = (currencyList.end() != std::find_if(currencyList.begin(), currencyList.end(), isReferencedHelper(id)));
+ }
+ // within the pricelist we don't have to scan each entry. Checking the QPair
+ // members of the MyMoneySecurityPair is enough as they are identical to the
+ // two security ids
+ if(!skipCheck[RefCheckPrice] && !rc) {
+ MyMoneyPriceList priceList = m_sql->fetchPrices();
+ priceEnd = priceList.end();
+ for(it_pr = priceList.begin(); !rc && it_pr != priceEnd; ++it_pr) {
+ rc = (it_pr.key().first == id) || (it_pr.key().second == id);
+ }
+ }
+ return rc;
+}
+
+void MyMoneyDatabaseMgr::close(void) {
+ if (m_sql != 0) {
+ m_sql->close(true);
+ m_sql = 0;
+ }
+}
+
+void MyMoneyDatabaseMgr::startTransaction(void)
+{ if (m_sql) m_sql->startCommitUnit ("databasetransaction"); }
+
+bool MyMoneyDatabaseMgr::commitTransaction(void)
+{
+ if (m_sql)
+ return m_sql->endCommitUnit ("databasetransaction");
+ return false;
+}
+
+void MyMoneyDatabaseMgr::rollbackTransaction(void)
+{ if (m_sql) m_sql->cancelCommitUnit ("databasetransaction"); }
+
+void MyMoneyDatabaseMgr::setCreationDate(const QDate& val)
+{ m_creationDate = val; }
+
+KSharedPtr <MyMoneyStorageSql> MyMoneyDatabaseMgr::connectToDatabase(const KURL& url) {
+ m_sql = new MyMoneyStorageSql (this, url);
+ return m_sql;
+}
+
+ void MyMoneyDatabaseMgr::fillStorage()
+{ m_sql->fillStorage(); }
+
+void MyMoneyDatabaseMgr::setLastModificationDate(const QDate& val)
+{ m_lastModificationDate = val; }
+
+bool MyMoneyDatabaseMgr::isDuplicateTransaction(const QString& /*id*/) const
+{
+ //FIXME: figure out the real id from the key and check the DB.
+//return m_transactionKeys.contains(id);
+ return false;
+}
+
+void MyMoneyDatabaseMgr::loadAccounts(const QMap<QString, MyMoneyAccount>& /*map*/)
+{
+// m_accountList = map;
+//FIXME: update the database.
+// startTransaction
+// DELETE FROM kmmAccounts
+// for each account in the map
+// m_sql->addAccount(...)
+// commitTransaction
+// on error, rollbackTransaction
+}
+
+void MyMoneyDatabaseMgr::loadTransactions(const QMap<QString, MyMoneyTransaction>& /*map*/)
+{
+// m_transactionList = map;
+//FIXME: update the database.
+
+// // now fill the key map
+// QMap<QString, QString> keys;
+// QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+// for(it_t = map.begin(); it_t != map.end(); ++it_t) {
+// keys[(*it_t).id()] = it_t.key();
+// }
+// m_transactionKeys = keys;
+}
+
+void MyMoneyDatabaseMgr::loadInstitutions(const QMap<QString, MyMoneyInstitution>& /*map*/)
+{
+// m_institutionList = map;
+//FIXME: update the database.
+
+// // now fill the key map
+// QMap<QString, QString> keys;
+// QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+// for(it_t = map.begin(); it_t != map.end(); ++it_t) {
+// keys[(*it_t).id()] = it_t.key();
+// }
+// m_transactionKeys = keys;
+}
+
+void MyMoneyDatabaseMgr::loadPayees(const QMap<QString, MyMoneyPayee>& /*map*/)
+{
+// m_payeeList = map;
+}
+
+void MyMoneyDatabaseMgr::loadSchedules(const QMap<QString, MyMoneySchedule>& /*map*/)
+{
+// m_scheduleList = map;
+}
+
+void MyMoneyDatabaseMgr::loadSecurities(const QMap<QString, MyMoneySecurity>& /*map*/)
+{
+// m_securitiesList = map;
+}
+
+void MyMoneyDatabaseMgr::loadCurrencies(const QMap<QString, MyMoneySecurity>& /*map*/)
+{
+// m_currencyList = map;
+//FIXME: update the database.
+// startTransaction
+// DELETE FROM kmmBudgetConfig
+// for each budget in the map
+// m_sql->addBudget(...)
+// commitTransaction
+// on error, rollbackTransaction
+}
+
+void MyMoneyDatabaseMgr::loadReports( const QMap<QString, MyMoneyReport>& /*reports*/ )
+{
+// m_reportList = reports;
+//FIXME: update the database.
+// startTransaction
+// DELETE FROM kmmBudgetConfig
+// for each budget in the map
+// m_sql->addBudget(...)
+// commitTransaction
+// on error, rollbackTransaction
+}
+
+void MyMoneyDatabaseMgr::loadBudgets( const QMap<QString, MyMoneyBudget>& /*budgets*/ )
+{
+// m_budgetList = budgets;
+//FIXME: update the database.
+// startTransaction
+// DELETE FROM kmmBudgetConfig
+// for each budget in the map
+// m_sql->addBudget(...)
+// commitTransaction
+// on error, rollbackTransaction
+}
+
+void MyMoneyDatabaseMgr::loadPrices(const MyMoneyPriceList& list)
+{
+ Q_UNUSED(list);
+}
+
+unsigned long MyMoneyDatabaseMgr::accountId(void) const
+{ return m_sql->getNextAccountId(); }
+
+unsigned long MyMoneyDatabaseMgr::transactionId(void) const
+{ return m_sql->getNextTransactionId(); }
+
+unsigned long MyMoneyDatabaseMgr::payeeId(void) const
+{ return m_sql->getNextPayeeId(); }
+
+unsigned long MyMoneyDatabaseMgr::institutionId(void) const
+{ return m_sql->getNextInstitutionId(); }
+
+unsigned long MyMoneyDatabaseMgr::scheduleId(void) const
+{ return m_sql->getNextScheduleId(); }
+
+unsigned long MyMoneyDatabaseMgr::securityId(void) const
+{ return m_sql->getNextSecurityId(); }
+
+unsigned long MyMoneyDatabaseMgr::reportId(void) const
+{ return m_sql->getNextReportId(); }
+
+unsigned long MyMoneyDatabaseMgr::budgetId(void) const
+{ return m_sql->getNextBudgetId(); }
+
+void MyMoneyDatabaseMgr::loadAccountId(const unsigned long id)
+{
+ m_sql->loadAccountId(id);
+}
+
+void MyMoneyDatabaseMgr::loadTransactionId(const unsigned long id)
+{
+ m_sql->loadTransactionId(id);
+}
+
+void MyMoneyDatabaseMgr::loadPayeeId(const unsigned long id)
+{
+ m_sql->loadPayeeId(id);
+}
+
+void MyMoneyDatabaseMgr::loadInstitutionId(const unsigned long id)
+{
+ m_sql->loadInstitutionId(id);
+}
+
+void MyMoneyDatabaseMgr::loadScheduleId(const unsigned long id)
+{
+ m_sql->loadScheduleId(id);
+}
+
+void MyMoneyDatabaseMgr::loadSecurityId(const unsigned long id)
+{
+ m_sql->loadSecurityId(id);
+}
+
+void MyMoneyDatabaseMgr::loadReportId(const unsigned long id)
+{
+ m_sql->loadReportId(id);
+}
+
+void MyMoneyDatabaseMgr::loadBudgetId(const unsigned long id)
+{
+ m_sql->loadBudgetId(id);
+}
+
+void MyMoneyDatabaseMgr::rebuildAccountBalances(void)
+{
+ startTransaction();
+ QMap<QString, MyMoneyAccount> accountMap = m_sql->fetchAccounts(QStringList(), true);
+
+ QMap<QString, MyMoneyMoney> balanceMap = m_sql->fetchBalance(accountMap.keys(), QDate());
+
+ for (QMap<QString, MyMoneyMoney>::const_iterator it_b = balanceMap.begin();
+ it_b != balanceMap.end(); ++it_b) {
+ accountMap[it_b.key()].setBalance(it_b.data());
+ }
+
+ for (QMap<QString, MyMoneyAccount>::const_iterator it_a = accountMap.begin();
+ it_a != accountMap.end(); ++it_a) {
+ m_sql->modifyAccount(it_a.data());
+ }
+ commitTransaction();
+}
+
+void MyMoneyDatabaseMgr::removeReferences(const QString& id)
+{
+ QMap<QString, MyMoneyReport>::const_iterator it_r;
+ QMap<QString, MyMoneyBudget>::const_iterator it_b;
+
+ // remove from reports
+ QMap<QString, MyMoneyReport> reportList = m_sql->fetchReports();
+ for(it_r = reportList.begin(); it_r != reportList.end(); ++it_r) {
+ MyMoneyReport r = *it_r;
+ r.removeReference(id);
+// reportList.modify(r.id(), r);
+ }
+
+ // remove from budgets
+ QMap<QString, MyMoneyBudget> budgetList = m_sql->fetchBudgets();
+ for(it_b = budgetList.begin(); it_b != budgetList.end(); ++it_b) {
+ MyMoneyBudget b = *it_b;
+ b.removeReference(id);
+// budgetList.modify(b.id(), b);
+ }
+}
+
+#undef TRY
+#undef CATCH
+#undef PASS
diff --git a/kmymoney2/mymoney/storage/mymoneydatabasemgr.h b/kmymoney2/mymoney/storage/mymoneydatabasemgr.h
new file mode 100644
index 0000000..21bf8d6
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneydatabasemgr.h
@@ -0,0 +1,1038 @@
+/***************************************************************************
+ mymoneydatabasemgr.h - description
+ -------------------
+ begin : June 5 2007
+ copyright : (C) 2007 by Fernando Vilas
+ email : Fernando Vilas <fvilas@iname.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYDATABASEMGR_H
+#define MYMONEYDATABASEMGR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "imymoneyserialize.h"
+#include "imymoneystorage.h"
+#include "mymoneymap.h"
+#include "mymoneystoragesql.h"
+
+/**
+ * The MyMoneyDatabaseMgr class represents the storage engine for databases.
+ * The actual connection and internal storage is handled through the
+ * MyMoneyStorageSql interface.
+ *
+ * The MyMoneyDatabaseMgr must have a MyMoneyStorageSql connected to a
+ * database to be useful. Once connected, data will be loaded from/sent to the
+ * database synchronously. The method dirty() will always return false. Making
+ * this many trips to the database is not very fast, so when possible, the
+ * data cache in MyMoneyFile is used.
+ *
+ */
+class MyMoneyDatabaseMgr : public IMyMoneyStorage, public IMyMoneySerialize,
+ public MyMoneyKeyValueContainer
+{
+public:
+ MyMoneyDatabaseMgr();
+ ~MyMoneyDatabaseMgr();
+
+ // general get functions
+ virtual const MyMoneyPayee user(void) const;
+ virtual const QDate creationDate(void) const;
+ virtual const QDate lastModificationDate(void) const;
+ virtual unsigned int currentFixVersion(void) const;
+ virtual unsigned int fileFixVersion(void) const;
+
+ // general set functions
+ virtual void setUser(const MyMoneyPayee& user);
+ virtual void setFileFixVersion(const unsigned int v);
+
+ // methods provided by MyMoneyKeyValueContainer
+ virtual void setValue(const QString& key, const QString& value);
+ virtual const QString value(const QString& key) const;
+ virtual void deletePair(const QString& key);
+
+ /**
+ * This method is used to duplicate an IMyMoneyStorage object and return
+ * a pointer to the newly created copy. The caller of this method is the
+ * new owner of the object and must destroy it.
+ */
+ virtual MyMoneyDatabaseMgr const * duplicate(void);
+
+ /**
+ * This method is used to create a new account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount filled with data
+ */
+ virtual void addAccount(MyMoneyAccount& account);
+
+ /**
+ * This method is used to add one account as sub-ordinate to another
+ * (parent) account. The objects that are passed will be modified
+ * accordingly.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param parent parent account the account should be added to
+ * @param account the account to be added
+ */
+ virtual void addAccount(MyMoneyAccount& parent, MyMoneyAccount& account);
+
+ /**
+ * This method is used to create a new payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ virtual void addPayee(MyMoneyPayee& payee);
+
+ /**
+ * This method is used to retrieve information about a payee
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id QString reference to id of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ virtual const MyMoneyPayee payee(const QString& id) const;
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a payee/receiver.
+ * An exception will be thrown upon error conditions.
+ *
+ * @param payee QString reference to name of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ virtual const MyMoneyPayee payeeByName(const QString& payee) const;
+
+ /**
+ * This method is used to modify an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ virtual void modifyPayee(const MyMoneyPayee& payee);
+
+ /**
+ * This method is used to remove an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ virtual void removePayee(const MyMoneyPayee& payee);
+
+ /**
+ * This method returns a list of the payees
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyPayee> containing the payee information
+ */
+ virtual const QValueList<MyMoneyPayee> payeeList(void) const;
+
+ /**
+ * Returns the account addressed by it's id.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id id of the account to locate.
+ * @return reference to MyMoneyAccount object. An exception is thrown
+ * if the id is unknown
+ */
+ virtual const MyMoneyAccount account(const QString& id) const;
+
+ /**
+ * This method is used to check whether a given
+ * account id references one of the standard accounts or not.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id account id
+ * @return true if account-id is one of the standards, false otherwise
+ */
+ virtual bool isStandardAccount(const QString& id) const;
+
+ /**
+ * This method is used to set the name for the specified standard account
+ * within the storage area. An exception will be thrown, if an error
+ * occurs
+ *
+ * @param id QString reference to one of the standard accounts.
+ * @param name QString reference to the name to be set
+ *
+ */
+ virtual void setAccountName(const QString& id, const QString& name);
+
+ /**
+ * Adds an institution to the storage. A
+ * respective institution-ID will be generated within this record.
+ * The ID is stored as QString in the object passed as argument.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete institution information in a
+ * MyMoneyInstitution object
+ */
+ virtual void addInstitution(MyMoneyInstitution& institution);
+
+ /**
+ * Adds a transaction to the file-global transaction pool. A respective
+ * transaction-ID will be generated within this record. The ID is stored
+ * QString with the object.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to the transaction
+ * @param skipAccountUpdate if set, the transaction lists of the accounts
+ * referenced in the splits are not updated. This is used for
+ * bulk loading a lot of transactions but not during normal operation
+ */
+ virtual void addTransaction(MyMoneyTransaction& transaction, const bool skipAccountUpdate = false);
+
+ /**
+ * This method is used to determince, if the account with the
+ * given ID is referenced by any split in m_transactionList.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id id of the account to be checked for
+ * @return true if account is referenced, false otherwise
+ */
+ virtual bool hasActiveSplits(const QString& id) const;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * without it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+ virtual const MyMoneyMoney balance(const QString& id, const QDate& date) const;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * including it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+ virtual const MyMoneyMoney totalBalance(const QString& id, const QDate& date) const;
+
+ /**
+ * Returns the institution of a given ID
+ *
+ * @param id id of the institution to locate
+ * @return MyMoneyInstitution object filled with data. If the institution
+ * could not be found, an exception will be thrown
+ */
+ virtual const MyMoneyInstitution institution(const QString& id) const;
+
+ /**
+ * This method returns an indicator if the storage object has been
+ * changed after it has last been saved to permanent storage.
+ *
+ * @return true if changed, false if not (for a database, always false).
+ */
+ virtual bool dirty(void) const;
+
+ /**
+ * This method can be used by an external object to force the
+ * storage object to be dirty. This is used e.g. when an upload
+ * to an external destination failed but the previous storage
+ * to a local disk was ok.
+ *
+ * Since the database is synchronized with the application, this method
+ * is a no-op.
+ */
+ virtual void setDirty(void);
+
+ /**
+ * This method returns the number of accounts currently known to this storage
+ * in the range 0..MAXUINT
+ *
+ * @return number of accounts currently known inside a MyMoneyFile object
+ */
+ virtual unsigned int accountCount(void) const;
+
+ /**
+ * This method returns a list of the institutions
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyInstitution> containing the
+ * institution information
+ */
+ virtual const QValueList<MyMoneyInstitution> institutionList(void) const;
+
+ /**
+ * Modifies an already existing account in the file global account pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account reference to the new account information
+ * @param skipCheck allows to skip the builtin consistency checks
+ */
+ virtual void modifyAccount(const MyMoneyAccount& account, const bool skipCheck = false);
+
+ /**
+ * Modifies an already existing institution in the file global
+ * institution pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete new institution information
+ */
+ virtual void modifyInstitution(const MyMoneyInstitution& institution);
+
+ /**
+ * This method is used to update a specific transaction in the
+ * transaction pool of the MyMoneyFile object
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to transaction to be changed
+ */
+ virtual void modifyTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * This method re-parents an existing account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount reference to account to be re-parented
+ * @param parent MyMoneyAccount reference to new parent account
+ */
+ virtual void reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent);
+
+ /**
+ * This method is used to remove a transaction from the transaction
+ * pool (journal).
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction const reference to transaction to be deleted
+ */
+ virtual void removeTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * This method returns the number of transactions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @param account QString reference to account id. If account is empty
+ + all transactions (the journal) will be counted. If account
+ * is not empty it returns the number of transactions
+ * that have splits in this account.
+ *
+ * @return number of transactions in journal/account
+ */
+ virtual unsigned int transactionCount(const QString& account = QString()) const;
+
+ /**
+ * This method returns a QMap filled with the number of transactions
+ * per account. The account id serves as index into the map. If one
+ * needs to have all transactionCounts() for many accounts, this method
+ * is faster than calling transactionCount(const QString& account) many
+ * times.
+ *
+ * @return QMap with numbers of transactions per account
+ */
+ virtual const QMap<QString, unsigned long> transactionCountMap(void) const;
+
+ /**
+ * This method is used to pull a list of transactions from the file
+ * global transaction pool. It returns all those transactions
+ * that match the filter passed as argument. If the filter is empty,
+ * the whole journal will be returned.
+ * The list returned is sorted according to the transactions posting date.
+ * If more than one transaction exists for the same date, the order among
+ * them is undefined.
+ *
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ *
+ * @return set of transactions in form of a QValueList<MyMoneyTransaction>
+ */
+ virtual const QValueList<MyMoneyTransaction> transactionList(MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * This method is the same as above, but instead of a return value, a
+ * parameter is used.
+ *
+ * @param list The set of transactions returned. The list passed in will
+ * be cleared before filling with results.
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ */
+ virtual void transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * This method is the same as above, but the list contains pairs of
+ * transactions and splits.
+ *
+ * @param list The set of transactions returned. The list passed in will
+ * be cleared before filling with results.
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ */
+ virtual void transactionList(QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * Deletes an existing account from the file global account pool
+ * This method only allows to remove accounts that are not
+ * referenced by any split. Use moveSplits() to move splits
+ * to another account. An exception is thrown in case of a
+ * problem.
+ *
+ * @param account reference to the account to be deleted.
+ */
+ virtual void removeAccount(const MyMoneyAccount& account);
+
+ /**
+ * Deletes an existing institution from the file global institution pool
+ * Also modifies the accounts that reference this institution as
+ * their institution.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution institution to be deleted.
+ */
+ virtual void removeInstitution(const MyMoneyInstitution& institution);
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an id. In case of an invalid id, an
+ * exception will be thrown.
+ *
+ * @param id id of transaction as QString.
+ * @return the requested transaction
+ */
+ virtual const MyMoneyTransaction transaction(const QString& id) const;
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an index into an account.
+ *
+ * @param account id of the account as QString
+ * @param idx number of transaction in this account
+ * @return MyMoneyTransaction object
+ */
+ virtual const MyMoneyTransaction transaction(const QString& account, const int idx) const;
+
+ /**
+ * This method returns the number of institutions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of institutions known to file
+ */
+ virtual unsigned int institutionCount(void) const;
+
+ /**
+ * This method returns a list of accounts inside the storage object.
+ *
+ * @param list reference to QValueList receiving the account objects
+ *
+ * @note The standard accounts will not be returned
+ */
+ virtual void accountList(QValueList<MyMoneyAccount>& list) const;
+
+ /**
+ * This method is used to return the standard liability account
+ * @return MyMoneyAccount liability account(group)
+ */
+ virtual const MyMoneyAccount liability(void) const;
+
+ /**
+ * This method is used to return the standard asset account
+ * @return MyMoneyAccount asset account(group)
+ */
+ virtual const MyMoneyAccount asset(void) const;
+
+ /**
+ * This method is used to return the standard expense account
+ * @return MyMoneyAccount expense account(group)
+ */
+ virtual const MyMoneyAccount expense(void) const;
+
+ /**
+ * This method is used to return the standard income account
+ * @return MyMoneyAccount income account(group)
+ */
+ virtual const MyMoneyAccount income(void) const;
+
+ /**
+ * This method is used to return the standard equity account
+ * @return MyMoneyAccount equity account(group)
+ */
+ virtual const MyMoneyAccount equity(void) const;
+
+ /**
+ * This method is used to create a new security object. The ID will be
+ * created automatically. The object passed with the parameter @p security
+ * is modified to contain the assigned id.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param security MyMoneySecurity filled with data
+ */
+ virtual void addSecurity(MyMoneySecurity& security);
+
+ /**
+ * This method is used to modify an existing MyMoneySecurity
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be updated
+ */
+ virtual void modifySecurity(const MyMoneySecurity& security);
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be removed
+ */
+ virtual void removeSecurity(const MyMoneySecurity& security);
+
+ /**
+ * This method is used to retrieve a single MyMoneySecurity object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySecurity object
+ * @return MyMoneySecurity object
+ */
+ virtual const MyMoneySecurity security(const QString& id) const;
+
+ /**
+ * This method returns a list of the security objects
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneySecurity> containing objects
+ */
+ virtual const QValueList<MyMoneySecurity> securityList(void) const;
+
+ virtual void addPrice(const MyMoneyPrice& price);
+ virtual void removePrice(const MyMoneyPrice& price);
+ virtual const MyMoneyPrice price(const QString& fromId, const QString& toId, const QDate& date, const bool exactDate) const;
+
+ /**
+ * This method returns a list of all prices.
+ *
+ * @return MyMoneyPriceList of all MyMoneyPrice objects.
+ */
+ virtual const MyMoneyPriceList priceList(void) const;
+
+ /**
+ * This method is used to add a scheduled transaction to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched reference to the MyMoneySchedule object
+ */
+ virtual void addSchedule(MyMoneySchedule& sched);
+
+ /**
+ * This method is used to modify an existing MyMoneySchedule
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ virtual void modifySchedule(const MyMoneySchedule& sched);
+
+ /**
+ * This method is used to remove an existing MyMoneySchedule object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ virtual void removeSchedule(const MyMoneySchedule& sched);
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ virtual const MyMoneySchedule schedule(const QString& id) const;
+
+ /**
+ * This method is used to extract a list of scheduled transactions
+ * according to the filter criteria passed as arguments.
+ *
+ * @param accountId only search for scheduled transactions that reference
+ * accound @p accountId. If accountId is the empty string,
+ * this filter is off. Default is @p QString().
+ * @param type only schedules of type @p type are searched for.
+ * See MyMoneySchedule::typeE for details.
+ * Default is MyMoneySchedule::TYPE_ANY
+ * @param occurence only schedules of occurence type @p occurance are searched for.
+ * See MyMoneySchedule::occurenceE for details.
+ * Default is MyMoneySchedule::OCCUR_ANY
+ * @param paymentType only schedules of payment method @p paymentType
+ * are searched for.
+ * See MyMoneySchedule::paymentTypeE for details.
+ * Default is MyMoneySchedule::STYPE_ANY
+ * @param startDate only schedules with payment dates after @p startDate
+ * are searched for. Default is all dates (QDate()).
+ * @param endDate only schedules with payment dates ending prior to @p endDate
+ * are searched for. Default is all dates (QDate()).
+ * @param overdue if true, only those schedules that are overdue are
+ * searched for. Default is false (all schedules will be returned).
+ *
+ * @return const QValueList<MyMoneySchedule> list of schedule objects.
+ */
+ virtual const QValueList<MyMoneySchedule> scheduleList(const QString& accountId = QString(),
+ const MyMoneySchedule::typeE type = MyMoneySchedule::TYPE_ANY,
+ const MyMoneySchedule::occurenceE occurence = MyMoneySchedule::OCCUR_ANY,
+ const MyMoneySchedule::paymentTypeE paymentType = MyMoneySchedule::STYPE_ANY,
+ const QDate& startDate = QDate(),
+ const QDate& endDate = QDate(),
+ const bool overdue = false) const;
+
+ virtual const QValueList<MyMoneySchedule> scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts=QStringList()) const;
+
+ /**
+ * This method is used to add a new currency object to the engine.
+ * The ID of the object is the trading symbol, so there is no need for an additional
+ * ID since the symbol is guaranteed to be unique.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ virtual void addCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to modify an existing MyMoneySecurity
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneyCurrency object
+ */
+ virtual void modifyCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneySecurity object
+ */
+ virtual void removeCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to retrieve a single MyMoneySecurity object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySecurity object
+ * @return MyMoneyCurrency object
+ */
+ virtual const MyMoneySecurity currency(const QString& id) const;
+
+ /**
+ * This method is used to retrieve the list of all currencies
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneySecurity objects representing a currency.
+ */
+ virtual const QValueList<MyMoneySecurity> currencyList(void) const;
+
+ /**
+ * This method is used to retrieve the list of all reports
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyReport objects.
+ */
+ virtual const QValueList<MyMoneyReport> reportList( void ) const;
+
+ /**
+ * This method is used to add a new report to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report reference to the MyMoneyReport object
+ */
+ virtual void addReport( MyMoneyReport& report );
+
+ /**
+ * This method is used to modify an existing MyMoneyReport
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ virtual void modifyReport( const MyMoneyReport& report );
+
+ /**
+ * This method returns the number of reports currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of reports known to file
+ */
+ virtual unsigned countReports( void ) const;
+
+ /**
+ * This method is used to retrieve a single MyMoneyReport object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyReport object
+ * @return MyMoneyReport object
+ */
+ virtual const MyMoneyReport report( const QString& id ) const;
+
+ /**
+ * This method is used to remove an existing MyMoneyReport object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ virtual void removeReport(const MyMoneyReport& report);
+
+ /**
+ * This method is used to retrieve the list of all budgets
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyBudget objects.
+ */
+ virtual const QValueList<MyMoneyBudget> budgetList( void ) const;
+
+ /**
+ * This method is used to add a new budget to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget reference to the MyMoneyBudget object
+ */
+ virtual void addBudget( MyMoneyBudget& budget );
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a budget
+ * An exception will be thrown upon error conditions.
+ *
+ * @param budget QString reference to name of budget
+ *
+ * @return MyMoneyBudget object of budget
+ */
+ virtual const MyMoneyBudget budgetByName(const QString& budget) const;
+
+ /**
+ * This method is used to modify an existing MyMoneyBudget
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ virtual void modifyBudget( const MyMoneyBudget& budget );
+
+ /**
+ * This method returns the number of budgets currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of budgets known to file
+ */
+ virtual unsigned countBudgets( void ) const;
+
+ /**
+ * This method is used to retrieve a single MyMoneyBudget object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyBudget object
+ * @return MyMoneyBudget object
+ */
+ virtual MyMoneyBudget budget( const QString& id ) const;
+
+ /**
+ * This method is used to remove an existing MyMoneyBudget object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ virtual void removeBudget(const MyMoneyBudget& budget);
+
+
+
+ /**
+ * Clear all internal caches (used internally for performance measurements)
+ */
+ virtual void clearCache(void);
+
+ /**
+ * This method checks, if the given @p object is referenced
+ * by another engine object.
+ *
+ * @param obj const reference to object to be checked
+ * @param skipCheck MyMoneyFileBitArray with ReferenceCheckBits set for which
+ * the check should be skipped
+ *
+ * @retval false @p object is not referenced
+ * @retval true @p institution is referenced
+ */
+ virtual bool isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipCheck = MyMoneyFileBitArray()) const;
+
+ /**
+ * This method is provided to allow closing of the database before logoff
+ */
+ virtual void close(void);
+
+ /**
+ * These methods have to be provided to allow transaction safe data handling.
+ */
+ virtual void startTransaction(void);
+ virtual bool commitTransaction(void);
+ virtual void rollbackTransaction(void);
+
+ // general set functions
+ virtual void setCreationDate(const QDate& val);
+
+ /**
+ * This method is used to get a SQL reader for subsequent database access
+ */
+ virtual KSharedPtr <MyMoneyStorageSql> connectToDatabase
+ (const KURL& url);
+ /**
+ * This method is used when a database file is open, and the data is to
+ * be saved in a different file or format. It will ensure that all data
+ * from the database is available in memory to enable it to be written.
+ */
+ virtual void fillStorage();
+
+ /**
+ * This method is used to set the last modification date of
+ * the storage object. It also clears the dirty flag and should
+ * therefor be called as last operation when loading from a
+ * file.
+ *
+ * @param val QDate of last modification
+ */
+ virtual void setLastModificationDate(const QDate& val);
+
+ /**
+ * This method returns whether a given transaction is already in memory, to avoid
+ * reloading it from the database
+ */
+ virtual bool isDuplicateTransaction(const QString&) const;
+
+ virtual void loadAccounts(const QMap<QString, MyMoneyAccount>& map);
+ virtual void loadTransactions(const QMap<QString, MyMoneyTransaction>& map);
+ virtual void loadInstitutions(const QMap<QString, MyMoneyInstitution>& map);
+ virtual void loadPayees(const QMap<QString, MyMoneyPayee>& map);
+ virtual void loadSchedules(const QMap<QString, MyMoneySchedule>& map);
+ virtual void loadSecurities(const QMap<QString, MyMoneySecurity>& map);
+ virtual void loadCurrencies(const QMap<QString, MyMoneySecurity>& map);
+ virtual void loadReports( const QMap<QString, MyMoneyReport>& reports );
+ virtual void loadBudgets( const QMap<QString, MyMoneyBudget>& budgets );
+ virtual void loadPrices(const MyMoneyPriceList& list);
+
+ virtual unsigned long accountId(void) const;
+ virtual unsigned long transactionId(void) const;
+ virtual unsigned long payeeId(void) const;
+ virtual unsigned long institutionId(void) const;
+ virtual unsigned long scheduleId(void) const;
+ virtual unsigned long securityId(void) const;
+ virtual unsigned long reportId(void) const;
+ virtual unsigned long budgetId(void) const;
+
+ virtual void loadAccountId(const unsigned long id);
+ virtual void loadTransactionId(const unsigned long id);
+ virtual void loadPayeeId(const unsigned long id);
+ virtual void loadInstitutionId(const unsigned long id);
+ virtual void loadScheduleId(const unsigned long id);
+ virtual void loadSecurityId(const unsigned long id);
+ virtual void loadReportId(const unsigned long id);
+ virtual void loadBudgetId(const unsigned long id);
+
+ /**
+ * This method is used to retrieve the whole set of key/value pairs
+ * from the container. It is meant to be used for permanent storage
+ * functionality. See MyMoneyKeyValueContainer::pairs() for details.
+ *
+ * @return QMap<QString, QString> containing all key/value pairs of
+ * this container.
+ */
+ virtual const QMap<QString, QString> pairs(void) const;
+
+ /**
+ * This method is used to initially store a set of key/value pairs
+ * in the container. It is meant to be used for loading functionality
+ * from permanent storage. See MyMoneyKeyValueContainer::setPairs()
+ * for details
+ *
+ * @param list const QMap<QString, QString> containing the set of
+ * key/value pairs to be loaded into the container.
+ *
+ * @note All existing key/value pairs in the container will be deleted.
+ */
+ virtual void setPairs(const QMap<QString, QString>& list);
+
+ /**
+ * This method recalculates the balances of all accounts
+ * based on the transactions stored in the engine.
+ */
+ virtual void rebuildAccountBalances(void);
+
+private:
+ /**
+ * This member variable keeps the creation date of this MyMoneySeqAccessMgr
+ * object. It is set during the constructor and can only be modified using
+ * the stream read operator.
+ */
+ QDate m_creationDate;
+
+ /**
+ * This member variable contains the current fix level of application
+ * data files. (see kmymoneyview.cpp)
+ */
+ unsigned int m_currentFixVersion;
+
+ /**
+ * This member variable contains the current fix level of the
+ * presently open data file. (see kmymoneyview.cpp)
+ */
+ unsigned int m_fileFixVersion;
+
+ /**
+ * This member variable keeps the date of the last modification of
+ * the MyMoneySeqAccessMgr object.
+ */
+ QDate m_lastModificationDate;
+
+ /**
+ * This contains the interface with SQL reader for database access
+ */
+ KSharedPtr <MyMoneyStorageSql> m_sql;
+
+ /**
+ * This member variable keeps the User information.
+ * @see setUser()
+ */
+ MyMoneyPayee m_user;
+
+ /**
+ * This method is used to get the next valid ID for a institution
+ * @return id for a institution
+ */
+ const QString nextInstitutionID(void);
+
+ /**
+ * This method is used to get the next valid ID for an account
+ * @return id for an account
+ */
+ const QString nextAccountID(void);
+
+ /**
+ * This method is used to get the next valid ID for a transaction
+ * @return id for a transaction
+ */
+ const QString nextTransactionID(void);
+
+ /**
+ * This method is used to get the next valid ID for a payee
+ * @return id for a payee
+ */
+ const QString nextPayeeID(void);
+
+ /**
+ * This method is used to get the next valid ID for a scheduled transaction
+ * @return id for a scheduled transaction
+ */
+ const QString nextScheduleID(void);
+
+ /**
+ * This method is used to get the next valid ID for an security object.
+ * @return id for an security object
+ */
+ const QString nextSecurityID(void);
+
+ const QString nextReportID(void);
+
+ /**
+ * This method is used to get the next valid ID for a budget object.
+ * @return id for an budget object
+ */
+ const QString nextBudgetID(void);
+
+ void removeReferences(const QString& id);
+
+ static const int INSTITUTION_ID_SIZE = 6;
+ static const int ACCOUNT_ID_SIZE = 6;
+ static const int TRANSACTION_ID_SIZE = 18;
+ static const int PAYEE_ID_SIZE = 6;
+ static const int SCHEDULE_ID_SIZE = 6;
+ static const int SECURITY_ID_SIZE = 6;
+ static const int REPORT_ID_SIZE = 6;
+ static const int BUDGET_ID_SIZE = 6;
+
+ // Increment this to force an update in KMMView.
+ // This is different from the db schema version stored in
+ // MMStorageSql::m_majorVersion
+ static const int CURRENT_FIX_VERSION = 3;
+
+};
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneydatabasemgrtest.cpp b/kmymoney2/mymoney/storage/mymoneydatabasemgrtest.cpp
new file mode 100644
index 0000000..f6a2bba
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneydatabasemgrtest.cpp
@@ -0,0 +1,1996 @@
+/***************************************************************************
+ mymoneydatabasemgrtest.cpp
+ -------------------
+ copyright : (C) 2008 by Fernando Vilas
+ email : fvilas@iname.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneydatabasemgrtest.h"
+#include <pwd.h>
+#include <iostream>
+
+MyMoneyDatabaseMgrTest::MyMoneyDatabaseMgrTest()
+ : m_dbAttached (false),
+ m_canOpen (true)
+{}
+
+void MyMoneyDatabaseMgrTest::setUp()
+{
+ m = new MyMoneyDatabaseMgr;
+
+ m->startTransaction();
+}
+
+void MyMoneyDatabaseMgrTest::tearDown()
+{
+ if (m_canOpen) {
+ m->commitTransaction();
+ }
+ if (MyMoneyFile::instance()->storageAttached()) {
+ MyMoneyFile::instance()->detachStorage(m);
+ }
+ delete m;
+}
+
+void MyMoneyDatabaseMgrTest::testEmptyConstructor()
+{
+ MyMoneyPayee user = m->user();
+
+ CPPUNIT_ASSERT(user.name().isEmpty());
+ CPPUNIT_ASSERT(user.address().isEmpty());
+ CPPUNIT_ASSERT(user.city().isEmpty());
+ CPPUNIT_ASSERT(user.state().isEmpty());
+ CPPUNIT_ASSERT(user.postcode().isEmpty());
+ CPPUNIT_ASSERT(user.telephone().isEmpty());
+ CPPUNIT_ASSERT(user.email().isEmpty());
+ CPPUNIT_ASSERT(m->nextInstitutionID() == 0);
+ CPPUNIT_ASSERT(m->nextAccountID() == 0);
+ CPPUNIT_ASSERT(m->nextTransactionID() == 0);
+ CPPUNIT_ASSERT(m->nextPayeeID() == 0);
+ CPPUNIT_ASSERT(m->nextScheduleID() == 0);
+ CPPUNIT_ASSERT(m->nextReportID() == 0);
+ CPPUNIT_ASSERT(m->institutionList().count() == 0);
+
+ QValueList<MyMoneyAccount> accList;
+ m->accountList(accList);
+ CPPUNIT_ASSERT(accList.count() == 0);
+
+ MyMoneyTransactionFilter f;
+ CPPUNIT_ASSERT(m->transactionList(f).count() == 0);
+
+ CPPUNIT_ASSERT(m->payeeList().count() == 0);
+ CPPUNIT_ASSERT(m->scheduleList().count() == 0);
+
+ CPPUNIT_ASSERT(m->m_creationDate == QDate::currentDate());
+}
+
+void MyMoneyDatabaseMgrTest::testCreateDb() {
+ m->commitTransaction();
+
+ // Fetch the list of available drivers
+ QStringList list = QSqlDatabase::drivers();
+ QStringList::Iterator it = list.begin();
+
+ if (it == list.end()) {
+ m_canOpen = false;
+ } else {
+ struct passwd * pwd = getpwuid(geteuid());
+ QString userName;
+ if (pwd != 0) {
+ userName = QString(pwd->pw_name);
+ }
+ //"QMYSQL3"
+ //"QPSQL7"
+ //"QSQLITE3"
+ m_url = "sql://" + userName + "@localhost/kmm_test_driver?driver="
+ //"QPSQL7&mode=single";
+ //"QSQLITE3&mode=single";
+ //"QMYSQL3&mode=single";
+ + *it + "&mode=single";
+ KSharedPtr <MyMoneyStorageSql> sql = m->connectToDatabase(m_url);
+ CPPUNIT_ASSERT(0 != sql);
+ //qDebug("Database driver is %s", sql->driverName().ascii());
+ // Clear the database, so there is a fresh start on each run.
+ if (0 == sql->open(m_url, IO_WriteOnly, true)) {
+ MyMoneyFile::instance()->attachStorage(m);
+ CPPUNIT_ASSERT(sql->writeFile());
+ m->startTransaction();
+ CPPUNIT_ASSERT(0 == sql->upgradeDb());
+ } else {
+ m_canOpen = false;
+ }
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAttachDb() {
+ if (!m_dbAttached) {
+ testCreateDb();
+ if (m_canOpen) {
+ MyMoneyFile::instance()->detachStorage();
+ KSharedPtr <MyMoneyStorageSql> sql = m->connectToDatabase(m_url);
+ CPPUNIT_ASSERT(sql);
+ int openStatus = sql->open(m_url, IO_ReadWrite);
+ CPPUNIT_ASSERT(0 == openStatus);
+ MyMoneyFile::instance()->attachStorage(m);
+ m->startTransaction();
+ m_dbAttached = true;
+ }
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testSetFunctions() {
+ testAttachDb();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyPayee user = m->user();
+
+ user.setName("Name");
+ m->setUser(user);
+ user.setAddress("Street");
+ m->setUser(user);
+ user.setCity("Town");
+ m->setUser(user);
+ user.setState("County");
+ m->setUser(user);
+ user.setPostcode("Postcode");
+ m->setUser(user);
+ user.setTelephone("Telephone");
+ m->setUser(user);
+ user.setEmail("Email");
+ m->setUser(user);
+ m->setValue("key", "value");
+
+ user = m->user();
+ CPPUNIT_ASSERT(user.name() == "Name");
+ CPPUNIT_ASSERT(user.address() == "Street");
+ CPPUNIT_ASSERT(user.city() == "Town");
+ CPPUNIT_ASSERT(user.state() == "County");
+ CPPUNIT_ASSERT(user.postcode() == "Postcode");
+ CPPUNIT_ASSERT(user.telephone() == "Telephone");
+ CPPUNIT_ASSERT(user.email() == "Email");
+ CPPUNIT_ASSERT(m->value("key") == "value");
+
+ m->setDirty();
+ m->deletePair("key");
+ CPPUNIT_ASSERT(m->dirty() == false);
+}
+
+void MyMoneyDatabaseMgrTest::testSupportFunctions()
+{
+ testAttachDb();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ CPPUNIT_ASSERT(m->nextInstitutionID() == "I000001");
+ CPPUNIT_ASSERT(m->nextAccountID() == "A000001");
+ CPPUNIT_ASSERT(m->nextTransactionID() == "T000000000000000001");
+ CPPUNIT_ASSERT(m->nextPayeeID() == "P000001");
+ CPPUNIT_ASSERT(m->nextScheduleID() == "SCH000001");
+ CPPUNIT_ASSERT(m->nextReportID() == "R000001");
+
+ CPPUNIT_ASSERT(m->liability().name() == "Liability");
+ CPPUNIT_ASSERT(m->asset().name() == "Asset");
+ CPPUNIT_ASSERT(m->expense().name() == "Expense");
+ CPPUNIT_ASSERT(m->income().name() == "Income");
+ CPPUNIT_ASSERT(m->equity().name() == "Equity");
+ CPPUNIT_ASSERT(m->dirty() == false);
+}
+
+void MyMoneyDatabaseMgrTest::testIsStandardAccount()
+{
+ testAttachDb();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_LIABILITY) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_ASSET) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_EXPENSE) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_INCOME) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_EQUITY) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount("A0002") == false);
+}
+
+void MyMoneyDatabaseMgrTest::testNewAccount() {
+ testAttachDb();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyAccount a;
+
+ a.setName("AccountName");
+ a.setNumber("AccountNumber");
+
+ m->addAccount(a);
+
+ CPPUNIT_ASSERT(m->accountId() == 1);
+ QValueList<MyMoneyAccount> accList;
+ m->accountList(accList);
+ CPPUNIT_ASSERT(accList.count() == 1);
+ CPPUNIT_ASSERT((*(accList.begin())).name() == "AccountName");
+ CPPUNIT_ASSERT((*(accList.begin())).id() == "A000001");
+}
+
+void MyMoneyDatabaseMgrTest::testAccount() {
+ testNewAccount();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ m->setDirty();
+
+ MyMoneyAccount a;
+
+ // make sure that an invalid ID causes an exception
+ try {
+ a = m->account("Unknown ID");
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ CPPUNIT_ASSERT(m->dirty() == false);
+
+ // now make sure, that a real ID works
+ try {
+ a = m->account("A000001");
+ CPPUNIT_ASSERT(a.name() == "AccountName");
+ CPPUNIT_ASSERT(a.id() == "A000001");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAddNewAccount() {
+ testNewAccount();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyAccount a,b;
+ b.setName("Account2");
+ b.setNumber("Acc2");
+ m->addAccount(b);
+
+ m->setDirty();
+
+ CPPUNIT_ASSERT(m->accountId() == 2);
+ QValueList<MyMoneyAccount> accList;
+ m->accountList(accList);
+ CPPUNIT_ASSERT(accList.count() == 2);
+
+ // try to add account to undefined account
+ try {
+ MyMoneyAccount c("UnknownID", b);
+ m->addAccount(c, a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+ // now try to add account 1 as sub-account to account 2
+ a = m->account("A000001");
+ try {
+ CPPUNIT_ASSERT(m->asset().accountList().count() == 0);
+ m->addAccount(b, a);
+ MyMoneyAccount acc (m->account("A000002"));
+ CPPUNIT_ASSERT(acc.accountList()[0] == "A000001");
+ CPPUNIT_ASSERT(acc.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->asset().accountList().count() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAddInstitution() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyInstitution i;
+
+ i.setName("Inst Name");
+
+ m->addInstitution(i);
+ CPPUNIT_ASSERT(m->institutionList().count() == 1);
+ CPPUNIT_ASSERT(m->institutionId() == 1);
+ CPPUNIT_ASSERT((*(m->institutionList().begin())).name() == "Inst Name");
+ CPPUNIT_ASSERT((*(m->institutionList().begin())).id() == "I000001");
+}
+
+void MyMoneyDatabaseMgrTest::testInstitution() {
+ testAddInstitution();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyInstitution i;
+
+ m->setDirty();
+
+ // try to find unknown institution
+ try {
+ i = m->institution("Unknown ID");
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+
+ // now try to find real institution
+ try {
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.name() == "Inst Name");
+ CPPUNIT_ASSERT(m->dirty() == false);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAccount2Institution() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddInstitution();
+ testAddNewAccount();
+
+ MyMoneyInstitution i;
+ MyMoneyAccount a, b;
+
+ try {
+ i = m->institution("I000001");
+ a = m->account("A000001");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->setDirty();
+
+ // try to add to a false institution
+ MyMoneyInstitution fake("Unknown ID", i);
+ a.setInstitutionId(fake.id());
+ try {
+ m->modifyAccount(a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+ // now try to do it with a real institution
+ try {
+ CPPUNIT_ASSERT(i.accountList().count() == 0);
+ a.setInstitutionId(i.id());
+ m->modifyAccount(a);
+ CPPUNIT_ASSERT(a.institutionId() == i.id());
+ b = m->account("A000001");
+ CPPUNIT_ASSERT(b.institutionId() == i.id());
+ CPPUNIT_ASSERT(i.accountList().count() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testModifyAccount() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAccount2Institution();
+
+ // test the OK case
+ MyMoneyAccount a = m->account("A000001");
+ a.setName("New account name");
+ m->setDirty();
+ try {
+ m->modifyAccount(a);
+ MyMoneyAccount b = m->account("A000001");
+ CPPUNIT_ASSERT(b.parentAccountId() == a.parentAccountId());
+ CPPUNIT_ASSERT(b.name() == "New account name");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // modify institution to unknown id
+ MyMoneyAccount c("Unknown ID", a);
+ m->setDirty();
+ try {
+ m->modifyAccount(c);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // use different account type
+ MyMoneyAccount d;
+ d.setAccountType(MyMoneyAccount::CreditCard);
+ MyMoneyAccount f("A000001", d);
+ try {
+ m->modifyAccount(f);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // use different parent
+ a.setParentAccountId("A000002");
+ try {
+ m->modifyAccount(c);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testModifyInstitution() {
+ testAddInstitution();
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyInstitution i = m->institution("I000001");
+
+ m->setDirty();
+ i.setName("New inst name");
+ try {
+ m->modifyInstitution(i);
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.name() == "New inst name");
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // try to modify an institution that does not exist
+ MyMoneyInstitution f("Unknown ID", i);
+ try {
+ m->modifyInstitution(f);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testReparentAccount() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ // this one adds some accounts to the database
+ MyMoneyAccount ex1;
+ ex1.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount ex2;
+ ex2.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount ex3;
+ ex3.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount ex4;
+ ex4.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount in;
+ in.setAccountType(MyMoneyAccount::Income);
+ MyMoneyAccount ch;
+ ch.setAccountType(MyMoneyAccount::Checkings);
+
+ ex1.setName("Sales Tax");
+ ex2.setName("Sales Tax 16%");
+ ex3.setName("Sales Tax 7%");
+ ex4.setName("Grosseries");
+
+ in.setName("Salary");
+ ch.setName("My checkings account");
+
+ try {
+ m->addAccount(ex1);
+ m->addAccount(ex2);
+ m->addAccount(ex3);
+ m->addAccount(ex4);
+ m->addAccount(in);
+ m->addAccount(ch);
+
+ CPPUNIT_ASSERT(ex1.id() == "A000001");
+ CPPUNIT_ASSERT(ex2.id() == "A000002");
+ CPPUNIT_ASSERT(ex3.id() == "A000003");
+ CPPUNIT_ASSERT(ex4.id() == "A000004");
+ CPPUNIT_ASSERT(in.id() == "A000005");
+ CPPUNIT_ASSERT(ch.id() == "A000006");
+
+ MyMoneyAccount parent = m->expense();
+
+ m->addAccount(parent, ex1);
+ m->addAccount(ex1, ex2);
+ m->addAccount(parent, ex3);
+ m->addAccount(parent, ex4);
+
+ parent = m->income();
+ m->addAccount(parent, in);
+
+ parent = m->asset();
+ m->addAccount(parent, ch);
+
+ MyMoneyFile::instance()->preloadCache();
+ CPPUNIT_ASSERT(m->expense().accountCount() == 3);
+ CPPUNIT_ASSERT(m->account(ex1.id()).accountCount() == 1);
+ CPPUNIT_ASSERT(ex3.parentAccountId() == STD_ACC_EXPENSE);
+
+ //for (int i = 0; i < 100; ++i) {
+ m->reparentAccount(ex3, ex1);
+ //}
+ MyMoneyFile::instance()->preloadCache();
+ CPPUNIT_ASSERT(m->expense().accountCount() == 2);
+ CPPUNIT_ASSERT(m->account(ex1.id()).accountCount() == 2);
+ CPPUNIT_ASSERT(ex3.parentAccountId() == ex1.id());
+ } catch (MyMoneyException *e) {
+ std::cout << std::endl << e->what() << std::endl;
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAddTransactions() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testReparentAccount();
+
+ MyMoneyAccount ch;
+ MyMoneyTransaction t1, t2;
+ MyMoneySplit s;
+
+ try {
+ // I made some money, great
+ s.setAccountId("A000006"); // Checkings
+ s.setShares(100000);
+ s.setValue(100000);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t1.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000005"); // Salary
+ s.setShares(-100000);
+ s.setValue(-100000);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t1.addSplit(s);
+
+ t1.setPostDate(QDate(2002,5,10));
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ m->setDirty();
+ try {
+ m->addTransaction(t1);
+ CPPUNIT_ASSERT(t1.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(t1.splitCount() == 2);
+ CPPUNIT_ASSERT(m->transactionCount() == 1);
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ try {
+ // I spent some money, not so great
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000004"); // Grosseries
+ s.setShares(10000);
+ s.setValue(10000);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000002"); // 16% sales tax
+ s.setShares(1200);
+ s.setValue(1200);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000003"); // 7% sales tax
+ s.setShares(400);
+ s.setValue(400);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000006"); // Checkings account
+ s.setShares(-11600);
+ s.setValue(-11600);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ t2.setPostDate(QDate(2002,5,9));
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+ m->setDirty();
+ try {
+ m->addTransaction(t2);
+ CPPUNIT_ASSERT(t2.id() == "T000000000000000002");
+ CPPUNIT_ASSERT(t2.splitCount() == 4);
+ CPPUNIT_ASSERT(m->transactionCount() == 2);
+
+ //QMap<QString, QString>::ConstIterator it_k;
+ MyMoneyTransactionFilter f;
+ QValueList<MyMoneyTransaction> transactionList (m->transactionList(f));
+ QValueList<MyMoneyTransaction>::ConstIterator it_t (transactionList.begin());
+
+ //CPPUNIT_ASSERT((*it_k) == "2002-05-10-T000000000000000001");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000002");
+ //++it_k;
+ ++it_t;
+ //CPPUNIT_ASSERT((*it_k) == "2002-05-09-T000000000000000002");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000001");
+ //++it_k;
+ ++it_t;
+ //CPPUNIT_ASSERT(it_k == m->m_transactionKeys.end());
+ CPPUNIT_ASSERT(it_t == transactionList.end());
+
+ ch = m->account("A000006");
+
+ // check that the account's transaction list is updated
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyTransactionFilter filter("A000006");
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.size() == 2);
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ it = list.begin();
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000002");
+ ++it;
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000001");
+ ++it;
+ CPPUNIT_ASSERT(it == list.end());
+
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testTransactionCount() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+ CPPUNIT_ASSERT(m->transactionCount("A000001") == 0);
+ CPPUNIT_ASSERT(m->transactionCount("A000002") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000003") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000004") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000005") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000006") == 2);
+}
+
+void MyMoneyDatabaseMgrTest::testAddBudget() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyBudget budget;
+
+ budget.setName("TestBudget");
+ budget.setBudgetStart(QDate::currentDate(Qt::LocalTime));
+
+ m->addBudget(budget);
+
+ CPPUNIT_ASSERT(m->budgetList().count() == 1);
+ CPPUNIT_ASSERT(m->budgetId() == 1);
+ MyMoneyBudget newBudget = m->budgetByName("TestBudget");
+
+ CPPUNIT_ASSERT(budget.budgetStart() == newBudget.budgetStart());
+ CPPUNIT_ASSERT(budget.name() == newBudget.name());
+}
+
+void MyMoneyDatabaseMgrTest::testCopyBudget() {
+ testAddBudget();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ try {
+ MyMoneyBudget oldBudget = m->budgetByName("TestBudget");
+ MyMoneyBudget newBudget = oldBudget;
+
+ newBudget.clearId();
+ newBudget.setName(QString("Copy of %1").arg(oldBudget.name()));
+ m->addBudget(newBudget);
+
+ CPPUNIT_ASSERT(m->budgetList().count() == 2);
+ CPPUNIT_ASSERT(m->budgetId() == 2);
+
+ MyMoneyBudget testBudget = m->budgetByName("TestBudget");
+
+ CPPUNIT_ASSERT(oldBudget.budgetStart() == testBudget.budgetStart());
+ CPPUNIT_ASSERT(oldBudget.name() == testBudget.name());
+
+ testBudget = m->budgetByName("Copy of TestBudget");
+
+ CPPUNIT_ASSERT(testBudget.budgetStart() == newBudget.budgetStart());
+ CPPUNIT_ASSERT(testBudget.name() == newBudget.name());
+ } catch (QString& s) {
+ std::cout << "Error in testCopyBudget(): " << s << std::endl;
+ CPPUNIT_ASSERT(false);
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testModifyBudget() {
+ testAddBudget();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyBudget budget = m->budgetByName("TestBudget");
+
+ budget.setBudgetStart(QDate::currentDate(Qt::LocalTime).addDays(-1));
+
+ m->modifyBudget(budget);
+
+ MyMoneyBudget newBudget = m->budgetByName("TestBudget");
+
+ CPPUNIT_ASSERT(budget.id() == newBudget.id());
+ CPPUNIT_ASSERT(budget.budgetStart() == newBudget.budgetStart());
+ CPPUNIT_ASSERT(budget.name() == newBudget.name());
+}
+
+void MyMoneyDatabaseMgrTest::testRemoveBudget() {
+ testAddBudget();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyBudget budget = m->budgetByName("TestBudget");
+ m->removeBudget(budget);
+
+ try {
+ budget = m->budgetByName("TestBudget");
+ // exception should be thrown if budget not found.
+ CPPUNIT_ASSERT(false);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_ASSERT(true);
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testBalance() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+
+ CPPUNIT_ASSERT(m->balance("A000001", QDate()).isZero());
+ CPPUNIT_ASSERT(m->balance("A000002", QDate()) == MyMoneyMoney(1200));
+ CPPUNIT_ASSERT(m->balance("A000003", QDate()) == MyMoneyMoney(400));
+ //Add a transaction to zero account A000003
+ MyMoneyTransaction t1;
+ MyMoneySplit s;
+
+ s.setAccountId("A000003");
+ s.setShares(-400);
+ s.setValue(-400);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t1.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000002");
+ s.setShares(400);
+ s.setValue(400);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t1.addSplit(s);
+
+ t1.setPostDate(QDate(2007,5,10));
+
+ m->addTransaction(t1);
+
+ //qDebug ("Balance of A000003 is 0 = %s", m->balance("A000003", QDate()).toString().ascii());
+ CPPUNIT_ASSERT(m->balance("A000003", QDate()).isZero());
+
+ //qDebug ("Balance of A000001 is 1600 = %s", m->balance("A000001", QDate()).toString().ascii());
+ CPPUNIT_ASSERT(m->totalBalance("A000001", QDate()) == MyMoneyMoney(1600));
+
+ //qDebug ("Balance of A000006 is -11600 = %s", m->balance("A000006", QDate(2002,5,9)).toString().ascii());
+ CPPUNIT_ASSERT(m->balance("A000006", QDate(2002,5,9)) == MyMoneyMoney(-11600));
+
+ //qDebug ("Balance of A000005 is -100000 = %s", m->balance("A000005", QDate(2002,5,10)).toString().ascii());
+ CPPUNIT_ASSERT(m->balance("A000005", QDate(2002,5,10)) == MyMoneyMoney(-100000));
+
+ //qDebug ("Balance of A000006 is 88400 = %s", m->balance("A000006", QDate(2002,5,10)).toString().ascii());
+ CPPUNIT_ASSERT(m->balance("A000006", QDate(2002,5,10)) == MyMoneyMoney(88400));
+}
+
+void MyMoneyDatabaseMgrTest::testModifyTransaction() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000002");
+ MyMoneySplit s;
+ MyMoneyAccount ch;
+
+ // just modify simple stuff (splits)
+ CPPUNIT_ASSERT(t.splitCount() == 4);
+
+ s = t.splits()[0];
+ s.setShares(11000);
+ s.setValue(11000);
+ t.modifySplit(s);
+
+ CPPUNIT_ASSERT(t.splitCount() == 4);
+ s = t.splits()[3];
+ s.setShares(-12600);
+ s.setValue(-12600);
+ t.modifySplit(s);
+
+ try {
+ CPPUNIT_ASSERT(m->balance("A000004", QDate()) == MyMoneyMoney(10000));
+ CPPUNIT_ASSERT(m->balance("A000006", QDate()) == MyMoneyMoney(100000-11600));
+ CPPUNIT_ASSERT(m->totalBalance("A000001", QDate()) == MyMoneyMoney(1600));
+ m->modifyTransaction(t);
+ CPPUNIT_ASSERT(m->balance("A000004", QDate()) == MyMoneyMoney(11000));
+ CPPUNIT_ASSERT(m->balance("A000006", QDate()) == MyMoneyMoney(100000-12600));
+ CPPUNIT_ASSERT(m->totalBalance("A000001", QDate()) == MyMoneyMoney(1600));
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // now modify the date
+ t.setPostDate(QDate(2002,5,11));
+ try {
+ m->modifyTransaction(t);
+ CPPUNIT_ASSERT(m->balance("A000004", QDate()) == MyMoneyMoney(11000));
+ CPPUNIT_ASSERT(m->balance("A000006", QDate()) == MyMoneyMoney(100000-12600));
+ CPPUNIT_ASSERT(m->totalBalance("A000001", QDate()) == MyMoneyMoney(1600));
+
+ //QMap<QString, QString>::ConstIterator it_k;
+ MyMoneyTransactionFilter f;
+ QValueList<MyMoneyTransaction> transactionList (m->transactionList(f));
+ QValueList<MyMoneyTransaction>::ConstIterator it_t (transactionList.begin());
+ //it_k = m->m_transactionKeys.begin();
+ //CPPUNIT_ASSERT((*it_k) == "2002-05-10-T000000000000000001");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000001");
+ //++it_k;
+ ++it_t;
+ //CPPUNIT_ASSERT((*it_k) == "2002-05-11-T000000000000000002");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000002");
+ //++it_k;
+ ++it_t;
+ //CPPUNIT_ASSERT(it_k == m->m_transactionKeys.end());
+ CPPUNIT_ASSERT(it_t == transactionList.end());
+
+ ch = m->account("A000006");
+
+ // check that the account's transaction list is updated
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyTransactionFilter filter("A000006");
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.size() == 2);
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ it = list.begin();
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000001");
+ ++it;
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000002");
+ ++it;
+ CPPUNIT_ASSERT(it == list.end());
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+
+void MyMoneyDatabaseMgrTest::testRemoveUnusedAccount() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAccount2Institution();
+
+ MyMoneyAccount a = m->account("A000001");
+ MyMoneyInstitution i = m->institution("I000001");
+
+ m->setDirty();
+ // make sure, we cannot remove the standard account groups
+ try {
+ m->removeAccount(m->liability());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->removeAccount(m->asset());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->removeAccount(m->expense());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->removeAccount(m->income());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // try to remove the account still attached to the institution
+ try {
+ m->removeAccount(a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // now really remove an account
+
+ try {
+ MyMoneyFile::instance()->preloadCache();
+ i = m->institution("I000001");
+
+ //CPPUNIT_ASSERT(i.accountCount() == 0);
+ CPPUNIT_ASSERT(i.accountCount() == 1);
+ CPPUNIT_ASSERT(m->accountCount() == 7);
+
+ a.setInstitutionId(QString());
+ m->modifyAccount(a);
+ m->removeAccount(a);
+ CPPUNIT_ASSERT(m->accountCount() == 6);
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.accountCount() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testRemoveUsedAccount() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+
+ MyMoneyAccount a = m->account("A000006");
+
+ try {
+ m->removeAccount(a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testRemoveInstitution() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testModifyInstitution();
+ testReparentAccount();
+
+ MyMoneyInstitution i;
+ MyMoneyAccount a;
+
+ // assign the checkings account to the institution
+ try {
+ i = m->institution("I000001");
+ a = m->account("A000006");
+ a.setInstitutionId(i.id());
+ m->modifyAccount(a);
+ CPPUNIT_ASSERT(i.accountCount() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->setDirty();
+ // now remove the institution and see if the account survived ;-)
+ try {
+ m->removeInstitution(i);
+ a.setInstitutionId(QString());
+ m->modifyAccount(a);
+ a = m->account("A000006");
+ CPPUNIT_ASSERT(a.institutionId().isEmpty());
+ CPPUNIT_ASSERT(m->institutionCount() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testRemoveTransaction() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000002");
+
+ m->setDirty();
+ try {
+ m->removeTransaction(t);
+ CPPUNIT_ASSERT(m->transactionCount() == 1);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testTransactionList() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyTransactionFilter filter("A000006");
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT((*(list.at(0))).id() == "T000000000000000002");
+ CPPUNIT_ASSERT((*(list.at(1))).id() == "T000000000000000001");
+
+ filter.clear();
+ filter.addAccount(QString("A000003"));
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT((*(list.at(0))).id() == "T000000000000000002");
+
+ filter.clear();
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT((*(list.at(0))).id() == "T000000000000000002");
+ CPPUNIT_ASSERT((*(list.at(1))).id() == "T000000000000000001");
+}
+
+void MyMoneyDatabaseMgrTest::testAddPayee() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyPayee p;
+
+ p.setName("THB");
+ m->setDirty();
+ try {
+ CPPUNIT_ASSERT(m->payeeId() == 0);
+ m->addPayee(p);
+ CPPUNIT_ASSERT(m->payeeId() == 1);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+}
+
+void MyMoneyDatabaseMgrTest::testSetAccountName() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ try {
+ m->setAccountName(STD_ACC_LIABILITY, "Verbindlichkeiten");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ m->setAccountName(STD_ACC_ASSET, "Verm�gen");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ m->setAccountName(STD_ACC_EXPENSE, "Ausgaben");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ m->setAccountName(STD_ACC_INCOME, "Einnahmen");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ MyMoneyFile::instance()->preloadCache();
+
+ CPPUNIT_ASSERT(m->liability().name() == "Verbindlichkeiten");
+ CPPUNIT_ASSERT(m->asset().name() == "Verm�gen");
+ CPPUNIT_ASSERT(m->expense().name() == "Ausgaben");
+ CPPUNIT_ASSERT(m->income().name() == "Einnahmen");
+
+ try {
+ m->setAccountName("A000001", "New account name");
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testModifyPayee() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyPayee p;
+
+ testAddPayee();
+
+ p = m->payee("P000001");
+ p.setName("New name");
+ m->setDirty();
+ try {
+ m->modifyPayee(p);
+ p = m->payee("P000001");
+ CPPUNIT_ASSERT(p.name() == "New name");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testRemovePayee() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddPayee();
+ m->setDirty();
+
+ // check that we can remove an unreferenced payee
+ MyMoneyPayee p = m->payee("P000001");
+ try {
+ CPPUNIT_ASSERT(m->payeeList().count() == 1);
+ m->removePayee(p);
+ CPPUNIT_ASSERT(m->payeeList().count() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // add transaction
+ testAddTransactions();
+
+ MyMoneyTransaction tr = m->transaction("T000000000000000001");
+ MyMoneySplit sp;
+ sp = tr.splits()[0];
+ sp.setPayeeId("P000001");
+ tr.modifySplit(sp);
+
+ // check that we cannot add a transaction referencing
+ // an unknown payee
+ try {
+ m->modifyTransaction(tr);
+ CPPUNIT_FAIL("Expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // reset here, so that the
+ // testAddPayee will not fail
+ m->loadPayeeId(0);
+ testAddPayee();
+
+ // check that it works when the payee exists
+ try {
+ m->modifyTransaction(tr);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->setDirty();
+
+ // now check, that we cannot remove the payee
+ try {
+ m->removePayee(p);
+ CPPUNIT_FAIL("Expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ CPPUNIT_ASSERT(m->payeeList().count() == 1);
+}
+
+
+void MyMoneyDatabaseMgrTest::testRemoveAccountFromTree() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneyAccount a, b, c;
+ a.setName("Acc A");
+ b.setName("Acc B");
+ c.setName("Acc C");
+
+ // build a tree A -> B -> C, remove B and see if A -> C
+ // remains in the storage manager
+
+ try {
+ m->addAccount(a);
+ m->addAccount(b);
+ m->addAccount(c);
+ m->reparentAccount(b, a);
+ m->reparentAccount(c, b);
+
+ CPPUNIT_ASSERT(a.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->account(a.accountList()[0]).name() == "Acc B");
+
+ CPPUNIT_ASSERT(b.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->account(b.accountList()[0]).name() == "Acc C");
+
+ CPPUNIT_ASSERT(c.accountList().count() == 0);
+
+ m->removeAccount(b);
+
+ // reload account info from titutionIDtorage
+ a = m->account(a.id());
+ c = m->account(c.id());
+
+ try {
+ b = m->account(b.id());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ CPPUNIT_ASSERT(a.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->account(a.accountList()[0]).name() == "Acc C");
+
+ CPPUNIT_ASSERT(c.accountList().count() == 0);
+
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testPayeeName() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddPayee();
+
+ MyMoneyPayee p;
+ QString name("THB");
+
+ // OK case
+ try {
+ p = m->payeeByName(name);
+ CPPUNIT_ASSERT(p.name() == "THB");
+ CPPUNIT_ASSERT(p.id() == "P000001");
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ // Not OK case
+ name = "Thb";
+ try {
+ p = m->payeeByName(name);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAssignment() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddTransactions();
+
+ MyMoneyPayee user;
+ user.setName("Thomas");
+ m->setUser(user);
+
+ MyMoneyDatabaseMgr test = *m;
+ testEquality(&test);
+}
+
+void MyMoneyDatabaseMgrTest::testEquality(const MyMoneyDatabaseMgr *t)
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ CPPUNIT_ASSERT(m->user().name() == t->user().name());
+ CPPUNIT_ASSERT(m->user().address() == t->user().address());
+ CPPUNIT_ASSERT(m->user().city() == t->user().city());
+ CPPUNIT_ASSERT(m->user().state() == t->user().state());
+ CPPUNIT_ASSERT(m->user().postcode() == t->user().postcode());
+ CPPUNIT_ASSERT(m->user().telephone() == t->user().telephone());
+ CPPUNIT_ASSERT(m->user().email() == t->user().email());
+ //CPPUNIT_ASSERT(m->nextInstitutionID() == t->nextInstitutionID());
+ //CPPUNIT_ASSERT(m->nextAccountID() == t->nextAccountID());
+ //CPPUNIT_ASSERT(m->m_nextTransactionID == t->m_nextTransactionID);
+ //CPPUNIT_ASSERT(m->nextPayeeID() == t->nextPayeeID());
+ //CPPUNIT_ASSERT(m->m_nextScheduleID == t->m_nextScheduleID);
+ CPPUNIT_ASSERT(m->dirty() == t->dirty());
+ CPPUNIT_ASSERT(m->m_creationDate == t->m_creationDate);
+ CPPUNIT_ASSERT(m->m_lastModificationDate == t->m_lastModificationDate);
+
+ /*
+ * make sure, that the keys and values are the same
+ * on the left and the right side
+ */
+ //CPPUNIT_ASSERT(m->payeeList().keys() == t->payeeList().keys());
+ //CPPUNIT_ASSERT(m->payeeList().values() == t->payeeList().values());
+ CPPUNIT_ASSERT(m->payeeList() == t->payeeList());
+ //CPPUNIT_ASSERT(m->m_transactionKeys.keys() == t->m_transactionKeys.keys());
+ //CPPUNIT_ASSERT(m->m_transactionKeys.values() == t->m_transactionKeys.values());
+ //CPPUNIT_ASSERT(m->institutionList().keys() == t->institutionList().keys());
+ //CPPUNIT_ASSERT(m->institutionList().values() == t->institutionList().values());
+ //CPPUNIT_ASSERT(m->m_accountList.keys() == t->m_accountList.keys());
+ //CPPUNIT_ASSERT(m->m_accountList.values() == t->m_accountList.values());
+ //CPPUNIT_ASSERT(m->m_transactionList.keys() == t->m_transactionList.keys());
+ //CPPUNIT_ASSERT(m->m_transactionList.values() == t->m_transactionList.values());
+ //CPPUNIT_ASSERT(m->m_balanceCache.keys() == t->m_balanceCache.keys());
+ //CPPUNIT_ASSERT(m->m_balanceCache.values() == t->m_balanceCache.values());
+
+// CPPUNIT_ASSERT(m->scheduleList().keys() == t->scheduleList().keys());
+// CPPUNIT_ASSERT(m->scheduleList().values() == t->scheduleList().values());
+}
+
+void MyMoneyDatabaseMgrTest::testDuplicate() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ const MyMoneyDatabaseMgr* t;
+
+ testModifyTransaction();
+
+ t = m->duplicate();
+ testEquality(t);
+ delete t;
+}
+
+void MyMoneyDatabaseMgrTest::testAddSchedule() {
+ /* Note addSchedule() now calls validate as it should
+ * so we need an account id. Later this will
+ * be checked to make sure its a valid account id. The
+ * tests currently fail because no splits are defined
+ * for the schedules transaction.
+ */
+
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ // put some accounts in the db, so the tests don't break
+ testReparentAccount();
+
+ try {
+ CPPUNIT_ASSERT(m->scheduleList().count() == 0);
+ MyMoneyTransaction t1;
+ MyMoneySplit s1, s2;
+ s1.setAccountId("A000001");
+ t1.addSplit(s1);
+ s2.setAccountId("A000002");
+ t1.addSplit(s2);
+ MyMoneySchedule schedule("Sched-Name",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_DAILY, 1,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ QDate(),
+ QDate(),
+ true,
+ false);
+ t1.setPostDate(QDate(2003,7,10));
+ schedule.setTransaction(t1);
+
+ m->addSchedule(schedule);
+
+ CPPUNIT_ASSERT(m->scheduleList().count() == 1);
+ CPPUNIT_ASSERT(schedule.id() == "SCH000001");
+ MyMoneyFile::instance()->clearCache();
+ CPPUNIT_ASSERT(m->schedule("SCH000001").id() == "SCH000001");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ try {
+ MyMoneySchedule schedule("Sched-Name",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_DAILY, 1,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ QDate(),
+ QDate(),
+ true,
+ false);
+ m->addSchedule(schedule);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ // now try with a bad account, so this should cause an exception
+ // TODO: enable this check without corrupting other tests
+// try {
+// MyMoneyTransaction t1;
+// MyMoneySplit s1, s2;
+// s1.setAccountId("Abadaccount1");
+// t1.addSplit(s1);
+// s2.setAccountId("Abadaccount2");
+// t1.addSplit(s2);
+// MyMoneySchedule schedule("Sched-Name",
+// MyMoneySchedule::TYPE_DEPOSIT,
+// MyMoneySchedule::OCCUR_DAILY, 1,
+// MyMoneySchedule::STYPE_MANUALDEPOSIT,
+// QDate(),
+// QDate(),
+// true,
+// false);
+// t1.setPostDate(QDate(2003,7,10));
+// schedule.setTransaction(t1);
+
+// m->addSchedule(schedule);
+// CPPUNIT_FAIL("Exception expected, but not thrown");
+// } catch(MyMoneyException *e) {
+// delete e;
+// // Exception caught as expected.
+// }
+
+}
+
+void MyMoneyDatabaseMgrTest::testSchedule() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddSchedule();
+ MyMoneySchedule sched;
+
+ sched = m->schedule("SCH000001");
+ CPPUNIT_ASSERT(sched.name() == "Sched-Name");
+ CPPUNIT_ASSERT(sched.id() == "SCH000001");
+
+ try {
+ m->schedule("SCH000002");
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testModifySchedule() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddSchedule();
+ MyMoneySchedule sched;
+
+ sched = m->schedule("SCH000001");
+ sched.setId("SCH000002");
+ try {
+ m->modifySchedule(sched);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ sched = m->schedule("SCH000001");
+ sched.setName("New Sched-Name");
+ try {
+ m->modifySchedule(sched);
+ CPPUNIT_ASSERT(m->scheduleList().count() == 1);
+ CPPUNIT_ASSERT((*(m->scheduleList().begin())).name() == "New Sched-Name");
+ CPPUNIT_ASSERT((*(m->scheduleList().begin())).id() == "SCH000001");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+}
+
+void MyMoneyDatabaseMgrTest::testRemoveSchedule() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ testAddSchedule();
+ MyMoneySchedule sched;
+
+ sched = m->schedule("SCH000001");
+ sched.setId("SCH000002");
+ try {
+ m->removeSchedule(sched);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ sched = m->schedule("SCH000001");
+ try {
+ m->removeSchedule(sched);
+ CPPUNIT_ASSERT(m->scheduleList().count() == 0);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testScheduleList() {
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ // put some accounts in the db, so the tests don't break
+ testReparentAccount();
+
+ QDate testDate = QDate::currentDate();
+ QDate notOverdue = testDate.addDays(2);
+ QDate overdue = testDate.addDays(-2);
+
+ MyMoneyTransaction t1;
+ MyMoneySplit s1, s2;
+ s1.setAccountId("A000001");
+ t1.addSplit(s1);
+ s2.setAccountId("A000002");
+ t1.addSplit(s2);
+ MyMoneySchedule schedule1("Schedule 1",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_ONCE, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate(),
+ QDate(),
+ false,
+ false);
+ t1.setPostDate(notOverdue);
+ schedule1.setTransaction(t1);
+ schedule1.setLastPayment(notOverdue);
+
+ MyMoneyTransaction t2;
+ MyMoneySplit s3, s4;
+ s3.setAccountId("A000001");
+ t2.addSplit(s3);
+ s4.setAccountId("A000003");
+ t2.addSplit(s4);
+ MyMoneySchedule schedule2("Schedule 2",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_DAILY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEPOSIT,
+ QDate(),
+ QDate(),
+ false,
+ false);
+ t2.setPostDate(notOverdue.addDays(1));
+ schedule2.setTransaction(t2);
+ schedule2.setLastPayment(notOverdue.addDays(1));
+
+ MyMoneyTransaction t3;
+ MyMoneySplit s5, s6;
+ s5.setAccountId("A000005");
+ t3.addSplit(s5);
+ s6.setAccountId("A000006");
+ t3.addSplit(s6);
+ MyMoneySchedule schedule3("Schedule 3",
+ MyMoneySchedule::TYPE_TRANSFER,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_OTHER,
+ QDate(),
+ QDate(),
+ false,
+ false);
+ t3.setPostDate(notOverdue.addDays(2));
+ schedule3.setTransaction(t3);
+ schedule3.setLastPayment(notOverdue.addDays(2));
+
+ MyMoneyTransaction t4;
+ MyMoneySplit s7, s8;
+ s7.setAccountId("A000005");
+ t4.addSplit(s7);
+ s8.setAccountId("A000006");
+ t4.addSplit(s8);
+ MyMoneySchedule schedule4("Schedule 4",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_WRITECHEQUE,
+ QDate(),
+ notOverdue.addDays(31),
+ false,
+ false);
+ t4.setPostDate(overdue.addDays(-7));
+ schedule4.setTransaction(t4);
+
+ try {
+ m->addSchedule(schedule1);
+ m->addSchedule(schedule2);
+ m->addSchedule(schedule3);
+ m->addSchedule(schedule4);
+ } catch(MyMoneyException *e) {
+ qDebug("Error: %s", e->what().latin1());
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ QValueList<MyMoneySchedule> list;
+
+ // no filter
+ list = m->scheduleList();
+ CPPUNIT_ASSERT(list.count() == 4);
+
+ // filter by type
+ list = m->scheduleList("", MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 1");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 4");
+
+ // filter by occurence
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 2");
+
+ // filter by payment type
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_DIRECTDEPOSIT);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 2");
+
+ // filter by account
+ list = m->scheduleList("A01");
+ CPPUNIT_ASSERT(list.count() == 0);
+ list = m->scheduleList("A000001");
+ CPPUNIT_ASSERT(list.count() == 2);
+ list = m->scheduleList("A000002");
+ CPPUNIT_ASSERT(list.count() == 1);
+
+ // filter by start date
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ notOverdue.addDays(31));
+ CPPUNIT_ASSERT(list.count() == 3);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 2");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 3");
+ CPPUNIT_ASSERT(list[2].name() == "Schedule 4");
+
+ // filter by end date
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate(),
+ notOverdue.addDays(1));
+ CPPUNIT_ASSERT(list.count() == 3);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 1");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 2");
+ CPPUNIT_ASSERT(list[2].name() == "Schedule 4");
+
+ // filter by start and end date
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ notOverdue.addDays(-1),
+ notOverdue.addDays(1));
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 1");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 2");
+
+ // filter by overdue status
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate(),
+ QDate(),
+ true);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 4");
+}
+
+void MyMoneyDatabaseMgrTest::testAddCurrency()
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ CPPUNIT_ASSERT(m->currencyList().count() == 0);
+ m->setDirty();
+ try {
+ m->addCurrency(curr);
+ CPPUNIT_ASSERT(m->currencyList().count() == 1);
+ CPPUNIT_ASSERT((*(m->currencyList().begin())).name() == "Euro");
+ CPPUNIT_ASSERT((*(m->currencyList().begin())).id() == "EUR");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->setDirty();
+ try {
+ m->addCurrency(curr);
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testModifyCurrency()
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ testAddCurrency();
+ m->setDirty();
+ curr.setName("EURO");
+ try {
+ m->modifyCurrency(curr);
+ CPPUNIT_ASSERT(m->currencyList().count() == 1);
+ CPPUNIT_ASSERT((*(m->currencyList().begin())).name() == "EURO");
+ CPPUNIT_ASSERT((*(m->currencyList().begin())).id() == "EUR");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->setDirty();
+
+ MyMoneySecurity unknownCurr("DEM", "Deutsche Mark", "DM", 100, 100);
+ try {
+ m->modifyCurrency(unknownCurr);
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testRemoveCurrency()
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ testAddCurrency();
+ m->setDirty();
+ try {
+ m->removeCurrency(curr);
+ CPPUNIT_ASSERT(m->currencyList().count() == 0);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->setDirty();
+
+ MyMoneySecurity unknownCurr("DEM", "Deutsche Mark", "DM", 100, 100);
+ try {
+ m->removeCurrency(unknownCurr);
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testCurrency()
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ MyMoneySecurity newCurr;
+ testAddCurrency();
+ m->setDirty();
+ try {
+ newCurr = m->currency("EUR");
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(newCurr.id() == curr.id());
+ CPPUNIT_ASSERT(newCurr.name() == curr.name());
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ try {
+ m->currency("DEM");
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testCurrencyList()
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ CPPUNIT_ASSERT(m->currencyList().count() == 0);
+
+ testAddCurrency();
+ CPPUNIT_ASSERT(m->currencyList().count() == 1);
+
+ MyMoneySecurity unknownCurr("DEM", "Deutsche Mark", "DM", 100, 100);
+ try {
+ m->addCurrency(unknownCurr);
+ m->setDirty();
+ CPPUNIT_ASSERT(m->currencyList().count() == 2);
+ CPPUNIT_ASSERT(m->currencyList().count() == 2);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneyDatabaseMgrTest::testAccountList()
+{
+ testAttachDb();
+
+ if (!m_canOpen) {
+ std::cout << "Database test skipped because no database could be opened." << std::endl;
+ return;
+ }
+
+ QValueList<MyMoneyAccount> accounts;
+ m->accountList(accounts);
+ CPPUNIT_ASSERT(accounts.count() == 0);
+ testAddNewAccount();
+ accounts.clear();
+ m->accountList(accounts);
+ CPPUNIT_ASSERT(accounts.count() == 2);
+
+ MyMoneyAccount a = m->account("A000001");
+ MyMoneyAccount b = m->account("A000002");
+ m->reparentAccount(b, a);
+ accounts.clear();
+ m->accountList(accounts);
+ CPPUNIT_ASSERT(accounts.count() == 2);
+}
+
diff --git a/kmymoney2/mymoney/storage/mymoneydatabasemgrtest.h b/kmymoney2/mymoney/storage/mymoneydatabasemgrtest.h
new file mode 100644
index 0000000..8ab4b64
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneydatabasemgrtest.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ mymoneydatabasemgrtest.h
+ -------------------
+ copyright : (C) 2008 by Fernando Vilas
+ email : fvilas@iname.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYDATABASEMGRTEST_H__
+#define __MYMONEYDATABASEMGRTEST_H__
+
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestSuite.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "../autotest.h"
+
+#define private public
+#define protected public
+#include "../mymoneyobject.h"
+#include "mymoneydatabasemgr.h"
+#undef private
+
+class MyMoneyDatabaseMgrTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyDatabaseMgrTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testCreateDb);
+ CPPUNIT_TEST(testAttachDb);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testSupportFunctions);
+ CPPUNIT_TEST(testIsStandardAccount);
+ CPPUNIT_TEST(testNewAccount);
+ CPPUNIT_TEST(testAddNewAccount);
+ CPPUNIT_TEST(testReparentAccount);
+ CPPUNIT_TEST(testAddInstitution);
+ CPPUNIT_TEST(testInstitution);
+ CPPUNIT_TEST(testAccount2Institution);
+ CPPUNIT_TEST(testModifyAccount);
+ CPPUNIT_TEST(testModifyInstitution);
+ CPPUNIT_TEST(testAddTransactions);
+ CPPUNIT_TEST(testTransactionCount);
+ CPPUNIT_TEST(testBalance);
+ CPPUNIT_TEST(testAddBudget);
+ CPPUNIT_TEST(testCopyBudget);
+ CPPUNIT_TEST(testModifyBudget);
+ CPPUNIT_TEST(testRemoveBudget);
+ CPPUNIT_TEST(testModifyTransaction);
+ CPPUNIT_TEST(testRemoveUnusedAccount);
+ CPPUNIT_TEST(testRemoveUsedAccount);
+ CPPUNIT_TEST(testRemoveInstitution);
+ CPPUNIT_TEST(testRemoveTransaction);
+ CPPUNIT_TEST(testTransactionList);
+ CPPUNIT_TEST(testAddPayee);
+ CPPUNIT_TEST(testSetAccountName);
+ CPPUNIT_TEST(testModifyPayee);
+ CPPUNIT_TEST(testPayeeName);
+ CPPUNIT_TEST(testRemovePayee);
+ CPPUNIT_TEST(testRemoveAccountFromTree);
+ CPPUNIT_TEST(testAssignment);
+ CPPUNIT_TEST(testDuplicate);
+ CPPUNIT_TEST(testAddSchedule);
+ CPPUNIT_TEST(testModifySchedule);
+ CPPUNIT_TEST(testRemoveSchedule);
+ CPPUNIT_TEST(testSchedule);
+ CPPUNIT_TEST(testScheduleList);
+ CPPUNIT_TEST(testAddCurrency);
+ CPPUNIT_TEST(testModifyCurrency);
+ CPPUNIT_TEST(testRemoveCurrency);
+ CPPUNIT_TEST(testCurrency);
+ CPPUNIT_TEST(testCurrencyList);
+ CPPUNIT_TEST(testAccountList);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyDatabaseMgr *m;
+ bool m_dbAttached;
+ bool m_canOpen;
+ KURL m_url;
+public:
+ MyMoneyDatabaseMgrTest();
+
+ void setUp();
+ void tearDown();
+ void testEmptyConstructor();
+ void testCreateDb();
+ void testAttachDb();
+ void testSetFunctions();
+ void testIsStandardAccount();
+ void testNewAccount();
+ void testAccount();
+ void testAddNewAccount();
+ void testAddInstitution();
+ void testInstitution();
+ void testAccount2Institution();
+ void testModifyAccount();
+ void testModifyInstitution();
+ void testReparentAccount();
+ void testAddTransactions();
+ void testTransactionCount();
+ void testAddBudget();
+ void testCopyBudget();
+ void testModifyBudget();
+ void testRemoveBudget();
+ void testBalance();
+ void testModifyTransaction();
+ void testRemoveUnusedAccount();
+ void testRemoveUsedAccount();
+ void testRemoveInstitution();
+ void testRemoveTransaction();
+ void testTransactionList();
+ void testAddPayee();
+ void testSetAccountName();
+ void testModifyPayee();
+ void testPayeeName();
+ void testRemovePayee();
+ void testRemoveAccountFromTree();
+ void testAssignment();
+ void testEquality(const MyMoneyDatabaseMgr* t);
+ void testDuplicate();
+ void testAddSchedule();
+ void testSchedule();
+ void testModifySchedule();
+ void testRemoveSchedule();
+ void testSupportFunctions();
+ void testScheduleList();
+ void testAddCurrency();
+ void testModifyCurrency();
+ void testRemoveCurrency();
+ void testCurrency();
+ void testCurrencyList();
+ void testAccountList();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneymap.h b/kmymoney2/mymoney/storage/mymoneymap.h
new file mode 100644
index 0000000..fa5cda8
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneymap.h
@@ -0,0 +1,328 @@
+#include <stdint.h>
+#include <qmap.h>
+#include <qptrstack.h>
+#include <kmymoney/mymoneyexception.h>
+
+#ifndef MYMONEYMAP_H
+#define MYMONEYMAP_H
+
+#define MY_OWN_DEBUG 0
+
+/**
+ * @author Thomas Baumgart
+ *
+ * This template class adds transaction security to the QMap<> class.
+ * The interface is very simple. Before you perform any changes,
+ * you have to call the startTransaction() method. Then you can use
+ * the insert(), modify() and remove() methods to modify the map.
+ * Changes are recorded and if you are finished, use the
+ * commitTransaction() to finish the transaction. If you want to go
+ * back before you have committed the transaction, use
+ * rollbackTransaction() to set the container to the state it was
+ * in before you called startTransaction().
+ *
+ * The implementation is based on the command pattern, in case
+ * someone is interested.
+ */
+template <class Key, class T>
+class MyMoneyMap : protected QMap<Key, T>
+{
+public:
+ // typedef QMapConstIterator<Key, T> const_iterator;
+
+ MyMoneyMap() : QMap<Key, T>() {}
+ virtual ~MyMoneyMap() {}
+
+ void startTransaction(unsigned long* id = 0)
+ {
+ m_stack.push(new MyMoneyMapStart(this, id));
+ }
+
+ void rollbackTransaction(void)
+ {
+ if(m_stack.count() == 0)
+ throw new MYMONEYEXCEPTION("No transaction started to rollback changes");
+
+ // undo all actions
+ MyMoneyMapAction* action;
+ while(m_stack.count()) {
+ action = m_stack.pop();
+ action->undo();
+ delete action;
+ }
+ }
+
+ bool commitTransaction(void)
+ {
+ if(m_stack.count() == 0)
+ throw new MYMONEYEXCEPTION("No transaction started to commit changes");
+
+ bool rc = m_stack.count() > 1;
+ m_stack.setAutoDelete(true);
+ m_stack.clear();
+ return rc;
+ }
+
+ void insert(const Key& key, const T& obj)
+ {
+ if(m_stack.count() == 0)
+ throw new MYMONEYEXCEPTION("No transaction started to insert new element into container");
+
+ // store object in
+ m_stack.push(new MyMoneyMapInsert(this, key, obj));
+ }
+
+ void modify(const Key& key, const T& obj)
+ {
+ if(m_stack.count() == 0)
+ throw new MYMONEYEXCEPTION("No transaction started to modify element in container");
+
+#if 0
+ // had to take this out, because we use QPair in one instance as key
+ if(key.isEmpty())
+ throw new MYMONEYEXCEPTION("No key to update object");
+#endif
+
+ m_stack.push(new MyMoneyMapModify(this, key, obj));
+ }
+
+ void remove(const Key& key)
+ {
+ if(m_stack.count() == 0)
+ throw new MYMONEYEXCEPTION("No transaction started to remove element from container");
+
+#if 0
+ // had to take this out, because we use QPair in one instance as key
+ if(key.isEmpty())
+ throw new MYMONEYEXCEPTION("No key to remove object");
+#endif
+
+ m_stack.push(new MyMoneyMapRemove(this, key));
+ }
+
+ MyMoneyMap<Key, T>& operator= (const QMap<Key, T>& m)
+ {
+ if(m_stack.count() != 0) {
+ throw new MYMONEYEXCEPTION("Cannot assign whole container during transaction");
+ }
+ QMap<Key, T>::operator=(m);
+ return *this;
+ }
+
+
+ inline QValueList<T> values(void) const
+ {
+ return QMap<Key,T>::values();
+ }
+
+ inline QValueList<Key> keys(void) const
+ {
+ return QMap<Key,T>::keys();
+ }
+
+ const T& operator[] ( const Key& k ) const
+ { QT_CHECK_INVALID_MAP_ELEMENT; return QMap<Key,T>::operator[](k); }
+
+ inline Q_TYPENAME QMap<Key, T>::const_iterator find(const Key& k) const
+ {
+ return QMap<Key,T>::find(k);
+ }
+
+ inline Q_TYPENAME QMap<Key, T>::const_iterator begin(void) const
+ {
+ return QMap<Key,T>::begin();
+ }
+
+ inline Q_TYPENAME QMap<Key, T>::const_iterator end(void) const
+ {
+ return QMap<Key,T>::end();
+ }
+
+ inline bool contains(const Key& k) const
+ {
+ return find(k) != end();
+ }
+
+ inline void map(QMap<Key, T>& that) const
+ {
+ //QMap<Key, T>* ptr = dynamic_cast<QMap<Key, T>* >(this);
+ //that = *ptr;
+ that = *(dynamic_cast<QMap<Key, T>* >(const_cast<MyMoneyMap<Key, T>* >(this)));
+ }
+
+ inline size_t count(void) const
+ {
+ return QMap<Key, T>::count();
+ }
+
+#if MY_OWN_DEBUG
+ void dump(void) const
+ {
+ printf("Container dump\n");
+ printf(" items in container = %d\n", count());
+ printf(" items on stack = %d\n", m_stack.count());
+
+ const_iterator it;
+ for(it = begin(); it != end(); ++it) {
+ printf(" %s \n", it.key().data());
+ }
+ }
+#endif
+
+private:
+ class MyMoneyMapAction
+ {
+ public:
+ MyMoneyMapAction(QMap<Key, T>* container) :
+ m_container(container) {}
+
+ MyMoneyMapAction(QMap<Key, T>* container, const Key& key, const T& obj) :
+ m_container(container),
+ m_obj(obj),
+ m_key(key) {}
+
+ virtual ~MyMoneyMapAction() {}
+ virtual void undo(void) = 0;
+
+ protected:
+ QMap<Key, T>* m_container;
+ T m_obj;
+ Key m_key;
+ };
+
+ class MyMoneyMapStart : public MyMoneyMapAction
+ {
+ public:
+ MyMoneyMapStart(QMap<Key, T>* container, unsigned long* id) :
+ MyMoneyMapAction(container),
+ m_idPtr(id)
+ {
+ if(id != 0)
+ m_id = *id;
+ }
+ virtual ~MyMoneyMapStart() {}
+ void undo(void)
+ {
+ if(m_idPtr != 0)
+ *m_idPtr = m_id;
+ }
+
+ private:
+ unsigned long* m_idPtr;
+ unsigned long m_id;
+ };
+
+ class MyMoneyMapInsert : public MyMoneyMapAction
+ {
+ public:
+ MyMoneyMapInsert(QMap<Key, T>* container, const Key& key, const T& obj) :
+ MyMoneyMapAction(container, key, obj)
+ {
+ (*container)[key] = obj;
+ }
+
+ virtual ~MyMoneyMapInsert() {}
+ void undo(void)
+ {
+ // m_container->remove(m_key) does not work on GCC 4.0.2
+ // using this-> to access those member does the trick
+ this->m_container->remove(this->m_key);
+ }
+ };
+
+ class MyMoneyMapRemove : public MyMoneyMapAction
+ {
+ public:
+ MyMoneyMapRemove(QMap<Key, T>* container, const Key& key) :
+ MyMoneyMapAction(container, key, (*container)[key])
+ {
+ container->remove(key);
+ }
+
+ virtual ~MyMoneyMapRemove() {}
+ void undo(void)
+ {
+ (*(this->m_container))[this->m_key] = this->m_obj;
+ }
+ };
+
+ class MyMoneyMapModify : public MyMoneyMapAction
+ {
+ public:
+ MyMoneyMapModify(QMap<Key, T>* container, const Key& key, const T& obj) :
+ MyMoneyMapAction(container, key, (*container)[key])
+ {
+ (*container)[key] = obj;
+ }
+
+ virtual ~MyMoneyMapModify() {}
+ void undo(void)
+ {
+ (*(this->m_container))[this->m_key] = this->m_obj;
+ }
+ };
+
+protected:
+ QPtrStack<MyMoneyMapAction> m_stack;
+};
+
+#if MY_OWN_DEBUG
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransaction.h>
+main()
+{
+ MyMoneyMap<QString, MyMoneyAccount> container;
+ MyMoneyMap<QString, MyMoneyTransaction> ct;
+
+ MyMoneyAccount acc;
+ acc.setName("Test");
+ // this should not be possible
+ // container["a"] = acc;
+
+ QValueList<MyMoneyAccount> list;
+ list = container.values();
+
+ MyMoneyAccount b;
+ b.setName("Thomas");
+
+ try {
+ container.startTransaction();
+ container.insert("001", acc);
+ container.dump();
+ container.commitTransaction();
+ acc.setName("123");
+ container.startTransaction();
+ container.modify("001", acc);
+ container.dump();
+ container.rollbackTransaction();
+ container.dump();
+
+ container.startTransaction();
+ container.remove(QString("001"));
+ container.dump();
+ container.rollbackTransaction();
+ container.dump();
+
+ b = container["001"];
+ printf("b.name() = %s\n", b.name().data());
+
+ QMap<QString, MyMoneyAccount>::ConstIterator it;
+ it = container.find("001");
+ it = container.begin();
+
+ } catch(MyMoneyException *e) {
+ printf("Caught exception: %s\n", e->what().data());
+ delete e;
+ }
+
+ QMap<QString, MyMoneyAccount> map;
+ map["005"] = b;
+ container = map;
+
+ printf("b.name() = %s\n", container["001"].name().data());
+ printf("b.name() = %s\n", container["005"].name().data());
+}
+
+#endif
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneymaptest.cpp b/kmymoney2/mymoney/storage/mymoneymaptest.cpp
new file mode 100644
index 0000000..5104fad
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneymaptest.cpp
@@ -0,0 +1,38 @@
+/***************************************************************************
+ mymoneymaptest.cpp
+ -------------------
+ copyright : (C) 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneymaptest.h"
+#include <iostream>
+
+MyMoneyMapTest::MyMoneyMapTest()
+{
+}
+
+
+void MyMoneyMapTest::setUp()
+{
+ m = new MyMoneyMap<QString, QString>;
+}
+
+void MyMoneyMapTest::tearDown()
+{
+ delete m;
+}
+
+void MyMoneyMapTest::testArrayOperator()
+{
+}
+
diff --git a/kmymoney2/mymoney/storage/mymoneymaptest.h b/kmymoney2/mymoney/storage/mymoneymaptest.h
new file mode 100644
index 0000000..c089a3f
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneymaptest.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ mymoneymaptest.h
+ -------------------
+ copyright : (C) 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYMAPTEST_H__
+#define __MYMONEYMAPTEST_H__
+
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestSuite.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "../autotest.h"
+
+#define private public
+#include "mymoneyseqaccessmgr.h"
+#undef private
+
+class MyMoneyMapTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneyMapTest);
+ CPPUNIT_TEST(testArrayOperator);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneyMap<QString, QString> *m;
+public:
+ MyMoneyMapTest();
+
+
+ void setUp();
+ void tearDown();
+ void testArrayOperator(void);
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneyseqaccessmgr.cpp b/kmymoney2/mymoney/storage/mymoneyseqaccessmgr.cpp
new file mode 100644
index 0000000..7341ec1
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneyseqaccessmgr.cpp
@@ -0,0 +1,1944 @@
+/***************************************************************************
+ mymoneyseqaccessmgr.cpp
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ 2002 Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <typeinfo>
+#include "mymoneyseqaccessmgr.h"
+#include "../mymoneytransactionfilter.h"
+#include "../mymoneycategory.h"
+
+#define TRY try {
+#define CATCH } catch (MyMoneyException *e) {
+#define PASS } catch (MyMoneyException *e) { throw; }
+
+bool MyMoneyBalanceCacheItem::operator ==(const MyMoneyBalanceCacheItem & right) const
+{
+ return ((balance == right.balance)
+ && (valid == right.valid));
+}
+
+MyMoneySeqAccessMgr::MyMoneySeqAccessMgr()
+{
+ m_nextAccountID = 0;
+ m_nextInstitutionID = 0;
+ m_nextTransactionID = 0;
+ m_nextPayeeID = 0;
+ m_nextScheduleID = 0;
+ m_nextSecurityID = 0;
+ m_nextReportID = 0;
+ m_nextBudgetID = 0;
+ m_user = MyMoneyPayee();
+ m_dirty = false;
+ m_creationDate = QDate::currentDate();
+
+ // setup standard accounts
+ MyMoneyAccount acc_l;
+ acc_l.setAccountType(MyMoneyAccount::Liability);
+ acc_l.setName("Liability");
+ MyMoneyAccount liability(STD_ACC_LIABILITY, acc_l);
+
+ MyMoneyAccount acc_a;
+ acc_a.setAccountType(MyMoneyAccount::Asset);
+ acc_a.setName("Asset");
+ MyMoneyAccount asset(STD_ACC_ASSET, acc_a);
+
+ MyMoneyAccount acc_e;
+ acc_e.setAccountType(MyMoneyAccount::Expense);
+ acc_e.setName("Expense");
+ MyMoneyAccount expense(STD_ACC_EXPENSE, acc_e);
+
+ MyMoneyAccount acc_i;
+ acc_i.setAccountType(MyMoneyAccount::Income);
+ acc_i.setName("Income");
+ MyMoneyAccount income(STD_ACC_INCOME, acc_i);
+
+ MyMoneyAccount acc_q;
+ acc_q.setAccountType(MyMoneyAccount::Equity);
+ acc_q.setName("Equity");
+ MyMoneyAccount equity(STD_ACC_EQUITY, acc_q);
+
+ QMap<QString, MyMoneyAccount> map;
+ map[STD_ACC_ASSET] = asset;
+ map[STD_ACC_LIABILITY] = liability;
+ map[STD_ACC_INCOME] = income;
+ map[STD_ACC_EXPENSE] = expense;
+ map[STD_ACC_EQUITY] = equity;
+
+ // load account list with inital accounts
+ m_accountList = map;
+
+ MyMoneyBalanceCacheItem balance;
+
+ m_balanceCache.clear();
+ m_balanceCache[STD_ACC_LIABILITY] = balance;
+ m_balanceCache[STD_ACC_ASSET] = balance;
+ m_balanceCache[STD_ACC_EXPENSE] = balance;
+ m_balanceCache[STD_ACC_INCOME] = balance;
+ m_balanceCache[STD_ACC_EQUITY] = balance;
+
+ // initialize for file fixes (see kmymoneyview.cpp)
+ m_currentFixVersion = 2;
+ m_fileFixVersion = 0; // default value if no fix-version in file
+ m_transactionListFull = false;
+}
+
+MyMoneySeqAccessMgr::~MyMoneySeqAccessMgr()
+{
+}
+
+MyMoneySeqAccessMgr const * MyMoneySeqAccessMgr::duplicate(void)
+{
+ MyMoneySeqAccessMgr* that = new MyMoneySeqAccessMgr();
+ *that = *this;
+ return that;
+}
+ /**
+ * This method is used to get a SQL reader for subsequent database access
+ */
+KSharedPtr <MyMoneyStorageSql> MyMoneySeqAccessMgr::connectToDatabase
+ (const KURL& /*url*/) {
+ return 0;
+}
+
+bool MyMoneySeqAccessMgr::isStandardAccount(const QString& id) const
+{
+ return id == STD_ACC_LIABILITY
+ || id == STD_ACC_ASSET
+ || id == STD_ACC_EXPENSE
+ || id == STD_ACC_INCOME
+ || id == STD_ACC_EQUITY;
+}
+
+void MyMoneySeqAccessMgr::setAccountName(const QString& id, const QString& name)
+{
+ if(!isStandardAccount(id))
+ throw new MYMONEYEXCEPTION("Only standard accounts can be modified using setAccountName()");
+
+ MyMoneyAccount acc = m_accountList[id];
+ acc.setName(name);
+ m_accountList.modify(acc.id(), acc);
+}
+
+const MyMoneyAccount MyMoneySeqAccessMgr::account(const QString& id) const
+{
+ // locate the account and if present, return it's data
+ if(m_accountList.find(id) != m_accountList.end())
+ return m_accountList[id];
+
+ // throw an exception, if it does not exist
+ QString msg = "Unknown account id '" + id + "'";
+ throw new MYMONEYEXCEPTION(msg);
+}
+
+void MyMoneySeqAccessMgr::accountList(QValueList<MyMoneyAccount>& list) const
+{
+ QMap<QString, MyMoneyAccount>::ConstIterator it;
+ for(it = m_accountList.begin(); it != m_accountList.end(); ++it) {
+ if(!isStandardAccount((*it).id())) {
+ list.append(*it);
+ }
+ }
+}
+
+void MyMoneySeqAccessMgr::addAccount(MyMoneyAccount& account)
+{
+ // create the account.
+ MyMoneyAccount newAccount(nextAccountID(), account);
+ m_accountList.insert(newAccount.id(), newAccount);
+
+ account = newAccount;
+}
+
+void MyMoneySeqAccessMgr::addPayee(MyMoneyPayee& payee)
+{
+ // create the payee
+ MyMoneyPayee newPayee(nextPayeeID(), payee);
+ m_payeeList.insert(newPayee.id(), newPayee);
+ payee = newPayee;
+}
+
+const MyMoneyPayee MyMoneySeqAccessMgr::payee(const QString& id) const
+{
+ QMap<QString, MyMoneyPayee>::ConstIterator it;
+ it = m_payeeList.find(id);
+ if(it == m_payeeList.end())
+ throw new MYMONEYEXCEPTION("Unknown payee '" + id + "'");
+
+ return *it;
+}
+
+const MyMoneyPayee MyMoneySeqAccessMgr::payeeByName(const QString& payee) const
+{
+ if(payee.isEmpty())
+ return MyMoneyPayee::null;
+
+ QMap<QString, MyMoneyPayee>::ConstIterator it_p;
+
+ for(it_p = m_payeeList.begin(); it_p != m_payeeList.end(); ++it_p) {
+ if((*it_p).name() == payee) {
+ return *it_p;
+ }
+ }
+
+ throw new MYMONEYEXCEPTION("Unknown payee '" + payee + "'");
+}
+
+void MyMoneySeqAccessMgr::modifyPayee(const MyMoneyPayee& payee)
+{
+ QMap<QString, MyMoneyPayee>::ConstIterator it;
+
+ it = m_payeeList.find(payee.id());
+ if(it == m_payeeList.end()) {
+ QString msg = "Unknown payee '" + payee.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+ m_payeeList.modify((*it).id(), payee);
+}
+
+void MyMoneySeqAccessMgr::removePayee(const MyMoneyPayee& payee)
+{
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ QMap<QString, MyMoneySchedule>::ConstIterator it_s;
+ QMap<QString, MyMoneyPayee>::ConstIterator it_p;
+
+ it_p = m_payeeList.find(payee.id());
+ if(it_p == m_payeeList.end()) {
+ QString msg = "Unknown payee '" + payee.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ // scan all transactions to check if the payee is still referenced
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+ if((*it_t).hasReferenceTo(payee.id())) {
+ throw new MYMONEYEXCEPTION(QString("Cannot remove payee that is still referenced to a %1").arg("transaction"));
+ }
+ }
+
+ // check referential integrity in schedules
+ for(it_s = m_scheduleList.begin(); it_s != m_scheduleList.end(); ++it_s) {
+ if((*it_s).hasReferenceTo(payee.id())) {
+ throw new MYMONEYEXCEPTION(QString("Cannot remove payee that is still referenced to a %1").arg("schedule"));
+ }
+ }
+
+ // remove any reference to report and/or budget
+ removeReferences(payee.id());
+
+ m_payeeList.remove((*it_p).id());
+}
+
+const QValueList<MyMoneyPayee> MyMoneySeqAccessMgr::payeeList(void) const
+{
+ return m_payeeList.values();
+}
+
+
+void MyMoneySeqAccessMgr::addAccount(MyMoneyAccount& parent, MyMoneyAccount& account)
+{
+ QMap<QString, MyMoneyAccount>::ConstIterator theParent;
+ QMap<QString, MyMoneyAccount>::ConstIterator theChild;
+
+ theParent = m_accountList.find(parent.id());
+ if(theParent == m_accountList.end()) {
+ QString msg = "Unknown parent account '";
+ msg += parent.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ theChild = m_accountList.find(account.id());
+ if(theChild == m_accountList.end()) {
+ QString msg = "Unknown child account '";
+ msg += account.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ MyMoneyAccount acc = *theParent;
+ acc.addAccountId(account.id());
+ m_accountList.modify(acc.id(), acc);
+ parent = acc;
+
+ acc = *theChild;
+ acc.setParentAccountId(parent.id());
+ m_accountList.modify(acc.id(), acc);
+ account = acc;
+
+ MyMoneyBalanceCacheItem balance;
+ m_balanceCache[account.id()] = balance;
+}
+
+void MyMoneySeqAccessMgr::addInstitution(MyMoneyInstitution& institution)
+{
+ MyMoneyInstitution newInstitution(nextInstitutionID(), institution);
+
+ m_institutionList.insert(newInstitution.id(), newInstitution);
+
+ // return new data
+ institution = newInstitution;
+}
+
+unsigned int MyMoneySeqAccessMgr::transactionCount(const QString& account) const
+{
+ unsigned int cnt = 0;
+
+ if(account.length() == 0) {
+ cnt = m_transactionList.count();
+
+ } else {
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ // scan all transactions
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+
+ // scan all splits of this transaction
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ // is it a split in our account?
+ if((*it_s).accountId() == account) {
+ // since a transaction can only have one split referencing
+ // each account, we're done with the splits here!
+ break;
+ }
+ }
+ // if no split contains the account id, continue with the
+ // next transaction
+ if(it_s == (*it_t).splits().end())
+ continue;
+
+ // otherwise count it
+ ++cnt;
+ }
+ }
+ return cnt;
+}
+
+const QMap<QString, unsigned long> MyMoneySeqAccessMgr::transactionCountMap(void) const
+{
+ QMap<QString, unsigned long> map;
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ // scan all transactions
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+ // scan all splits of this transaction
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ map[(*it_s).accountId()]++;
+ }
+ }
+ return map;
+}
+
+unsigned int MyMoneySeqAccessMgr::institutionCount(void) const
+{
+ return m_institutionList.count();
+}
+
+unsigned int MyMoneySeqAccessMgr::accountCount(void) const
+{
+ return m_accountList.count();
+}
+
+QString MyMoneySeqAccessMgr::nextPayeeID(void)
+{
+ QString id;
+ id.setNum(++m_nextPayeeID);
+ id = "P" + id.rightJustify(PAYEE_ID_SIZE, '0');
+ return id;
+}
+
+QString MyMoneySeqAccessMgr::nextInstitutionID(void)
+{
+ QString id;
+ id.setNum(++m_nextInstitutionID);
+ id = "I" + id.rightJustify(INSTITUTION_ID_SIZE, '0');
+ return id;
+}
+
+QString MyMoneySeqAccessMgr::nextAccountID(void)
+{
+ QString id;
+ id.setNum(++m_nextAccountID);
+ id = "A" + id.rightJustify(ACCOUNT_ID_SIZE, '0');
+ return id;
+}
+
+QString MyMoneySeqAccessMgr::nextTransactionID(void)
+{
+ QString id;
+ id.setNum(++m_nextTransactionID);
+ id = "T" + id.rightJustify(TRANSACTION_ID_SIZE, '0');
+ return id;
+}
+
+QString MyMoneySeqAccessMgr::nextScheduleID(void)
+{
+ QString id;
+ id.setNum(++m_nextScheduleID);
+ id = "SCH" + id.rightJustify(SCHEDULE_ID_SIZE, '0');
+ return id;
+}
+
+QString MyMoneySeqAccessMgr::nextSecurityID(void)
+{
+ QString id;
+ id.setNum(++m_nextSecurityID);
+ id = "E" + id.rightJustify(SECURITY_ID_SIZE, '0');
+ return id;
+}
+
+
+void MyMoneySeqAccessMgr::addTransaction(MyMoneyTransaction& transaction, const bool skipAccountUpdate)
+{
+ // perform some checks to see that the transaction stuff is OK. For
+ // now we assume that
+ // * no ids are assigned
+ // * the date valid (must not be empty)
+ // * the referenced accounts in the splits exist
+
+ // first perform all the checks
+ if(!transaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION("transaction already contains an id");
+ if(!transaction.postDate().isValid())
+ throw new MYMONEYEXCEPTION("invalid post date");
+
+ // now check the splits
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following lines will throw an exception if the
+ // account or payee do not exist
+ account((*it_s).accountId());
+ if(!(*it_s).payeeId().isEmpty())
+ payee((*it_s).payeeId());
+ }
+
+ MyMoneyTransaction newTransaction(nextTransactionID(), transaction);
+ QString key = newTransaction.uniqueSortKey();
+
+ m_transactionList.insert(key, newTransaction);
+ m_transactionKeys.insert(newTransaction.id(), key);
+
+ transaction = newTransaction;
+
+ // adjust the balance of all affected accounts
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = m_accountList[(*it_s).accountId()];
+ acc.adjustBalance(*it_s);
+ if(!skipAccountUpdate) {
+ acc.touch();
+ invalidateBalanceCache(acc.id());
+ }
+ m_accountList.modify(acc.id(), acc);
+ }
+}
+
+void MyMoneySeqAccessMgr::touch(void)
+{
+ m_dirty = true;
+ m_lastModificationDate = QDate::currentDate();
+}
+
+bool MyMoneySeqAccessMgr::hasActiveSplits(const QString& id) const
+{
+ QMap<QString, MyMoneyTransaction>::ConstIterator it;
+
+ for(it = m_transactionList.begin(); it != m_transactionList.end(); ++it) {
+ if((*it).accountReferenced(id)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const MyMoneyInstitution MyMoneySeqAccessMgr::institution(const QString& id) const
+{
+ QMap<QString, MyMoneyInstitution>::ConstIterator pos;
+
+ pos = m_institutionList.find(id);
+ if(pos != m_institutionList.end())
+ return *pos;
+ throw new MYMONEYEXCEPTION("unknown institution");
+}
+
+const QValueList<MyMoneyInstitution> MyMoneySeqAccessMgr::institutionList(void) const
+{
+ return m_institutionList.values();
+}
+
+void MyMoneySeqAccessMgr::modifyAccount(const MyMoneyAccount& account, const bool skipCheck)
+{
+ QMap<QString, MyMoneyAccount>::ConstIterator pos;
+
+ // locate the account in the file global pool
+ pos = m_accountList.find(account.id());
+ if(pos != m_accountList.end()) {
+ // check if the new info is based on the old one.
+ // this is the case, when the file and the id
+ // as well as the type are equal.
+ if((((*pos).parentAccountId() == account.parentAccountId())
+ && ((*pos).accountType() == account.accountType()))
+ || (skipCheck == true)) {
+ // make sure that all the referenced objects exist
+ if(!account.institutionId().isEmpty())
+ institution(account.institutionId());
+
+ QValueList<QString>::ConstIterator it_a;
+ for(it_a = account.accountList().begin(); it_a != account.accountList().end(); ++it_a) {
+ this->account(*it_a);
+ }
+
+ // update information in account list
+ m_accountList.modify(account.id(), account);
+
+ // invalidate cached balance
+ invalidateBalanceCache(account.id());
+
+ } else
+ throw new MYMONEYEXCEPTION("Invalid information for update");
+
+ } else
+ throw new MYMONEYEXCEPTION("Unknown account id");
+}
+
+void MyMoneySeqAccessMgr::modifyInstitution(const MyMoneyInstitution& institution)
+{
+ QMap<QString, MyMoneyInstitution>::ConstIterator pos;
+
+ // locate the institution in the file global pool
+ pos = m_institutionList.find(institution.id());
+ if(pos != m_institutionList.end()) {
+ m_institutionList.modify(institution.id(), institution);
+
+ } else
+ throw new MYMONEYEXCEPTION("unknown institution");
+}
+
+void MyMoneySeqAccessMgr::modifyTransaction(const MyMoneyTransaction& transaction)
+{
+ // perform some checks to see that the transaction stuff is OK. For
+ // now we assume that
+ // * ids are assigned
+ // * the pointer to the MyMoneyFile object is not 0
+ // * the date valid (must not be empty)
+ // * the splits must have valid account ids
+
+ // first perform all the checks
+ if(transaction.id().isEmpty()
+// || transaction.file() != this
+ || !transaction.postDate().isValid())
+ throw new MYMONEYEXCEPTION("invalid transaction to be modified");
+
+ // now check the splits
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ // the following lines will throw an exception if the
+ // account or payee do not exist
+ account((*it_s).accountId());
+ if(!(*it_s).payeeId().isEmpty())
+ payee((*it_s).payeeId());
+ }
+
+ // new data seems to be ok. find old version of transaction
+ // in our pool. Throw exception if unknown.
+ if(!m_transactionKeys.contains(transaction.id()))
+ throw new MYMONEYEXCEPTION("invalid transaction id");
+
+ QString oldKey = m_transactionKeys[transaction.id()];
+ if(!m_transactionList.contains(oldKey))
+ throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+
+ it_t = m_transactionList.find(oldKey);
+ if(it_t == m_transactionList.end())
+ throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ // adjust account balances
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ MyMoneyAccount acc = m_accountList[(*it_s).accountId()];
+ acc.adjustBalance(*it_s, true); // reverse the adjust operation (reverse = true)
+ acc.touch();
+ invalidateBalanceCache(acc.id());
+ m_accountList.modify(acc.id(), acc);
+ }
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ MyMoneyAccount acc = m_accountList[(*it_s).accountId()];
+ acc.adjustBalance(*it_s);
+ acc.touch();
+ invalidateBalanceCache(acc.id());
+ m_accountList.modify(acc.id(), acc);
+ }
+
+ // remove old transaction from lists
+ m_transactionList.remove(oldKey);
+
+ // add new transaction to lists
+ QString newKey = transaction.uniqueSortKey();
+ m_transactionList.insert(newKey, transaction);
+ m_transactionKeys.modify(transaction.id(), newKey);
+}
+
+void MyMoneySeqAccessMgr::reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent)
+{
+ reparentAccount(account, parent, true);
+}
+
+void MyMoneySeqAccessMgr::reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent, const bool /* sendNotification */)
+{
+ QMap<QString, MyMoneyAccount>::ConstIterator oldParent;
+ QMap<QString, MyMoneyAccount>::ConstIterator newParent;
+ QMap<QString, MyMoneyAccount>::ConstIterator childAccount;
+
+ // verify that accounts exist. If one does not,
+ // an exception is thrown
+ MyMoneySeqAccessMgr::account(account.id());
+ MyMoneySeqAccessMgr::account(parent.id());
+ if(!account.parentAccountId().isEmpty()) {
+ MyMoneySeqAccessMgr::account(account.parentAccountId());
+ oldParent = m_accountList.find(account.parentAccountId());
+ }
+
+ if(account.accountType() == MyMoneyAccount::Stock && parent.accountType() != MyMoneyAccount::Investment)
+ throw new MYMONEYEXCEPTION("Cannot move a stock acocunt into a non-investment account");
+
+ newParent = m_accountList.find(parent.id());
+ childAccount = m_accountList.find(account.id());
+
+ MyMoneyAccount acc;
+ if(!account.parentAccountId().isEmpty()) {
+ acc = (*oldParent);
+ acc.removeAccountId(account.id());
+ m_accountList.modify(acc.id(), acc);
+ }
+
+ parent = (*newParent);
+ parent.addAccountId(account.id());
+ m_accountList.modify(parent.id(), parent);
+
+ account = (*childAccount);
+ account.setParentAccountId(parent.id());
+ m_accountList.modify(account.id(), account);
+
+#if 0
+ // make sure the type is the same as the new parent. This does not work for stock and investment
+ if(account.accountType() != MyMoneyAccount::Stock && account.accountType() != MyMoneyAccount::Investment)
+ (*childAccount).setAccountType((*newParent).accountType());
+#endif
+}
+
+void MyMoneySeqAccessMgr::removeTransaction(const MyMoneyTransaction& transaction)
+{
+ // first perform all the checks
+ if(transaction.id().isEmpty())
+ throw new MYMONEYEXCEPTION("invalid transaction to be deleted");
+
+ QMap<QString, QString>::ConstIterator it_k;
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+
+ it_k = m_transactionKeys.find(transaction.id());
+ if(it_k == m_transactionKeys.end())
+ throw new MYMONEYEXCEPTION("invalid transaction to be deleted");
+
+ it_t = m_transactionList.find(*it_k);
+ if(it_t == m_transactionList.end())
+ throw new MYMONEYEXCEPTION("invalid transaction key");
+
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ // scan the splits and collect all accounts that need
+ // to be updated after the removal of this transaction
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ MyMoneyAccount acc = m_accountList[(*it_s).accountId()];
+ acc.adjustBalance(*it_s, true); // reverse = true
+ acc.touch();
+ m_accountList.modify(acc.id(), acc);
+ invalidateBalanceCache(acc.id());
+ }
+
+ // FIXME: check if any split is frozen and throw exception
+
+ // remove the transaction from the two lists
+ m_transactionList.remove(*it_k);
+ m_transactionKeys.remove(transaction.id());
+}
+
+void MyMoneySeqAccessMgr::removeAccount(const MyMoneyAccount& account)
+{
+ MyMoneyAccount parent;
+
+ // check that the account and it's parent exist
+ // this will throw an exception if the id is unknown
+ MyMoneySeqAccessMgr::account(account.id());
+ parent = MyMoneySeqAccessMgr::account(account.parentAccountId());
+
+ // check that it's not one of the standard account groups
+ if(isStandardAccount(account.id()))
+ throw new MYMONEYEXCEPTION("Unable to remove the standard account groups");
+
+ if(hasActiveSplits(account.id())) {
+ throw new MYMONEYEXCEPTION("Unable to remove account with active splits");
+ }
+
+ // re-parent all sub-ordinate accounts to the parent of the account
+ // to be deleted. First round check that all accounts exist, second
+ // round do the re-parenting.
+ QStringList::ConstIterator it;
+ for(it = account.accountList().begin(); it != account.accountList().end(); ++it) {
+ MyMoneySeqAccessMgr::account(*it);
+ }
+
+ // if one of the accounts did not exist, an exception had been
+ // thrown and we would not make it until here.
+
+ QMap<QString, MyMoneyAccount>::ConstIterator it_a;
+ QMap<QString, MyMoneyAccount>::ConstIterator it_p;
+
+ // locate the account in the file global pool
+
+ it_a = m_accountList.find(account.id());
+ if(it_a == m_accountList.end())
+ throw new MYMONEYEXCEPTION("Internal error: account not found in list");
+
+ it_p = m_accountList.find(parent.id());
+ if(it_p == m_accountList.end())
+ throw new MYMONEYEXCEPTION("Internal error: parent account not found in list");
+
+ if(!account.institutionId().isEmpty())
+ throw new MYMONEYEXCEPTION("Cannot remove account still attached to an institution");
+
+ removeReferences(account.id());
+
+ // FIXME: check referential integrity for the account to be removed
+
+ // check if the new info is based on the old one.
+ // this is the case, when the file and the id
+ // as well as the type are equal.
+ if((*it_a).id() == account.id()
+ && (*it_a).accountType() == account.accountType()) {
+
+ // second round over sub-ordinate accounts: do re-parenting
+ // but only if the list contains at least one entry
+ // FIXME: move this logic to MyMoneyFile
+ if((*it_a).accountList().count() > 0) {
+ while((*it_a).accountList().count() > 0) {
+ it = (*it_a).accountList().begin();
+ MyMoneyAccount acc(MyMoneySeqAccessMgr::account(*it));
+ reparentAccount(acc, parent, false);
+ }
+ }
+ // remove account from parent's list
+ parent.removeAccountId(account.id());
+ m_accountList.modify(parent.id(), parent);
+
+ // remove account from the global account pool
+ m_accountList.remove(account.id());
+
+ // remove from balance list
+ m_balanceCache.remove(account.id());
+ invalidateBalanceCache(parent.id());
+ }
+}
+
+void MyMoneySeqAccessMgr::removeInstitution(const MyMoneyInstitution& institution)
+{
+ QMap<QString, MyMoneyInstitution>::ConstIterator it_i;
+
+ it_i = m_institutionList.find(institution.id());
+ if(it_i != m_institutionList.end()) {
+ m_institutionList.remove(institution.id());
+
+ } else
+ throw new MYMONEYEXCEPTION("invalid institution");
+}
+
+void MyMoneySeqAccessMgr::transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const
+{
+ list.clear();
+
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+ // This code is used now. It adds the transaction to the list for
+ // each matching split exactly once. This allows to show information
+ // about different splits in the same register view (e.g. search result)
+ //
+ // I have no idea, if this has some impact on the functionality. So far,
+ // I could not see it. (ipwizard 9/5/2003)
+ if(filter.match(*it_t)) {
+ unsigned int cnt = filter.matchingSplits().count();
+ if(cnt > 1) {
+ for(unsigned i=0; i < cnt; ++i)
+ list.append(*it_t);
+ } else {
+ list.append(*it_t);
+ }
+ }
+ }
+}
+
+void MyMoneySeqAccessMgr::transactionList(QValueList< QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const
+{
+ list.clear();
+
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+ if(filter.match(*it_t)) {
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = filter.matchingSplits().begin(); it_s != filter.matchingSplits().end(); ++it_s) {
+ list.append(qMakePair(*it_t, *it_s));
+ }
+ }
+ }
+}
+
+const QValueList<MyMoneyTransaction> MyMoneySeqAccessMgr::transactionList(MyMoneyTransactionFilter& filter) const
+{
+ QValueList<MyMoneyTransaction> list;
+ transactionList(list, filter);
+ return list;
+}
+
+const MyMoneyTransaction MyMoneySeqAccessMgr::transaction(const QString& id) const
+{
+ // get the full key of this transaction, throw exception
+ // if it's invalid (unknown)
+ if(!m_transactionKeys.contains(id)) {
+ QString msg = QString("Invalid transaction id '%1'").arg(id);
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ // check if this key is in the list, throw exception if not
+ QString key = m_transactionKeys[id];
+ if(!m_transactionList.contains(key)) {
+ QString msg = QString("Invalid transaction key '%1'").arg(key);
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ return m_transactionList[key];
+}
+
+const MyMoneyTransaction MyMoneySeqAccessMgr::transaction(const QString& account, const int idx) const
+{
+/* removed with MyMoneyAccount::Transaction
+ QMap<QString, MyMoneyAccount>::ConstIterator acc;
+
+ // find account object in list, throw exception if unknown
+ acc = m_accountList.find(account);
+ if(acc == m_accountList.end())
+ throw new MYMONEYEXCEPTION("unknown account id");
+
+ // get the transaction info from the account
+ MyMoneyAccount::Transaction t = (*acc).transaction(idx);
+
+ // return the transaction, throw exception if not found
+ return transaction(t.transactionID());
+*/
+
+ // new implementation if the above code does not work anymore
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyAccount acc = m_accountList[account];
+ MyMoneyTransactionFilter filter;
+
+ if(acc.accountGroup() == MyMoneyAccount::Income
+ || acc.accountGroup() == MyMoneyAccount::Expense)
+ filter.addCategory(account);
+ else
+ filter.addAccount(account);
+
+ transactionList(list, filter);
+ if(idx < 0 || idx >= static_cast<int> (list.count()))
+ throw new MYMONEYEXCEPTION("Unknown idx for transaction");
+
+ return transaction(list[idx].id());
+}
+
+const MyMoneyMoney MyMoneySeqAccessMgr::balance(const QString& id, const QDate& date) const
+{
+ MyMoneyMoney result(0);
+ MyMoneyAccount acc;
+ // if (date != QDate()) qDebug ("request balance for %s at %s", id.data(), date.toString(Qt::ISODate).latin1());
+ if(!date.isValid() && account(id).accountType() != MyMoneyAccount::Stock) {
+ if(m_accountList.find(id) != m_accountList.end())
+ return m_accountList[id].balance();
+ return MyMoneyMoney(0);
+ }
+ if(m_balanceCache[id].valid == false || date != m_balanceCacheDate) {
+ QMap<QString, MyMoneyMoney> balances;
+ QMap<QString, MyMoneyMoney>::ConstIterator it_b;
+ if (date != m_balanceCacheDate) {
+ m_balanceCache.clear();
+ m_balanceCacheDate = date;
+ }
+
+ QValueList<MyMoneyTransaction> list;
+ QValueList<MyMoneyTransaction>::ConstIterator it_t;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(QDate(), date);
+ filter.setReportAllSplits(false);
+ transactionList(list, filter);
+
+ for(it_t = list.begin(); it_t != list.end(); ++it_t) {
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s){
+ const QString& aid = (*it_s).accountId();
+ if((*it_s).action() == MyMoneySplit::ActionSplitShares) {
+ balances[aid] = balances[aid] * (*it_s).shares();
+ } else {
+ balances[aid] += (*it_s).shares();
+ }
+ }
+ }
+
+ // fill the found balances into the cache
+ for(it_b = balances.begin(); it_b != balances.end(); ++it_b) {
+ MyMoneyBalanceCacheItem balance(*it_b);
+ m_balanceCache[it_b.key()] = balance;
+ }
+
+ // fill all accounts w/o transactions to zero
+ QMap<QString, MyMoneyAccount>::ConstIterator it_a;
+ for(it_a = m_accountList.begin(); it_a != m_accountList.end(); ++it_a) {
+ if(m_balanceCache[(*it_a).id()].valid == false) {
+ MyMoneyBalanceCacheItem balance(MyMoneyMoney(0,1));
+ m_balanceCache[(*it_a).id()] = balance;
+ }
+ }
+ }
+
+ if(m_balanceCache[id].valid == true)
+ result = m_balanceCache[id].balance;
+ else
+ qDebug("Cache mishit should never happen at this point");
+
+ return result;
+}
+
+const MyMoneyMoney MyMoneySeqAccessMgr::totalBalance(const QString& id, const QDate& date) const
+{
+ QStringList accounts;
+ QStringList::ConstIterator it_a;
+
+ MyMoneyMoney result(balance(id, date));
+
+ accounts = account(id).accountList();
+
+ for(it_a = accounts.begin(); it_a != accounts.end(); ++it_a) {
+ result += totalBalance(*it_a, date);
+ }
+
+ return result;
+}
+
+/**
+ * this was intended to move all splits from one account
+ * to another. This somehow is strange to undo because many
+ * changes to different objects are made within one single call.
+ * I kept the source here but commented it out. If we ever need
+ * the functionality, we can turn it back on. BTW: the stuff is untested ;-)
+ */
+/*
+const unsigned int MyMoneyFile::moveSplits(const QString& oldAccount, const QString& newAccount)
+{
+ QMap<QString, MyMoneyTransaction>::Iterator it_t;
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ unsigned int cnt = 0;
+
+ // scan all transactions
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+ // scan all splits of this transaction
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ // is it a split in our account?
+ if((*it_s).account() == oldAccount) {
+ MyMoneySplit s = *it_s;
+ s.setAccount(newAccount);
+ (*it_t).modifySplit(s);
+ ++cnt;
+ }
+ }
+ }
+
+ if(cnt != 0) {
+ // now update all the accounts that were referenced
+ QMap<QString, MyMoneyAccount>::Iterator acc;
+ acc = m_accountList.find(oldAccount);
+ if(acc != m_accountList.end()) {
+ (*acc).touch();
+ refreshAccountTransactionList(acc);
+ }
+ acc = m_accountList.find(newAccount);
+ if(acc != m_accountList.end()) {
+ (*acc).touch();
+ refreshAccountTransactionList(acc);
+ }
+
+ // mark file as changed
+ m_dirty = true;
+ }
+ return cnt;
+}
+*/
+
+void MyMoneySeqAccessMgr::invalidateBalanceCache(const QString& id)
+{
+ if(!id.isEmpty()) {
+ try {
+ m_balanceCache[id].valid = false;
+ if(!isStandardAccount(id)) {
+ invalidateBalanceCache(account(id).parentAccountId());
+ }
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ }
+}
+
+void MyMoneySeqAccessMgr::loadAccounts(const QMap<QString, MyMoneyAccount>& map)
+{
+ m_accountList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneyAccount>::const_iterator it_a;
+ QString lastId("");
+ for(it_a = map.begin(); it_a != map.end(); ++it_a) {
+ if(!isStandardAccount((*it_a).id()) && ((*it_a).id() > lastId))
+ lastId = (*it_a).id();
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextAccountID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::loadTransactions(const QMap<QString, MyMoneyTransaction>& map)
+{
+ m_transactionList = map;
+
+ // now fill the key map and
+ // identify the last used id
+ QString lastId("");
+ QMap<QString, QString> keys;
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ for(it_t = map.begin(); it_t != map.end(); ++it_t) {
+ keys[(*it_t).id()] = it_t.key();
+ if((*it_t).id() > lastId)
+ lastId = (*it_t).id();
+ }
+ m_transactionKeys = keys;
+
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextTransactionID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::loadInstitutions(const QMap<QString, MyMoneyInstitution>& map)
+{
+ m_institutionList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneyInstitution>::const_iterator it_i;
+ QString lastId("");
+ for(it_i = map.begin(); it_i != map.end(); ++it_i) {
+ if((*it_i).id() > lastId)
+ lastId = (*it_i).id();
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextInstitutionID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::loadPayees(const QMap<QString, MyMoneyPayee>& map)
+{
+ m_payeeList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneyPayee>::const_iterator it_p;
+ QString lastId("");
+ for(it_p = map.begin(); it_p != map.end(); ++it_p) {
+ if((*it_p).id().length() <= PAYEE_ID_SIZE+1) {
+ if((*it_p).id() > lastId)
+ lastId = (*it_p).id();
+ } else {
+ }
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextPayeeID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::loadSecurities(const QMap<QString, MyMoneySecurity>& map)
+{
+ m_securitiesList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneySecurity>::const_iterator it_s;
+ QString lastId("");
+ for(it_s = map.begin(); it_s != map.end(); ++it_s) {
+ if((*it_s).id() > lastId)
+ lastId = (*it_s).id();
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextSecurityID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::loadCurrencies(const QMap<QString, MyMoneySecurity>& map)
+{
+ m_currencyList = map;
+}
+
+void MyMoneySeqAccessMgr::loadPrices(const MyMoneyPriceList& list)
+{
+ m_priceList = list;
+}
+
+void MyMoneySeqAccessMgr::loadAccountId(const unsigned long id)
+{
+ m_nextAccountID = id;
+}
+
+void MyMoneySeqAccessMgr::loadTransactionId(const unsigned long id)
+{
+ m_nextTransactionID = id;
+}
+
+void MyMoneySeqAccessMgr::loadPayeeId(const unsigned long id)
+{
+ m_nextPayeeID = id;
+}
+
+void MyMoneySeqAccessMgr::loadInstitutionId(const unsigned long id)
+{
+ m_nextInstitutionID = id;
+}
+
+void MyMoneySeqAccessMgr::loadSecurityId(const unsigned long id)
+{
+ m_nextSecurityID = id;
+}
+
+void MyMoneySeqAccessMgr::loadReportId(const unsigned long id)
+{
+ m_nextReportID = id;
+}
+
+void MyMoneySeqAccessMgr::loadBudgetId(const unsigned long id)
+{
+ m_nextBudgetID = id;
+}
+
+const QString MyMoneySeqAccessMgr::value(const QString& key) const
+{
+ return MyMoneyKeyValueContainer::value(key);
+}
+
+void MyMoneySeqAccessMgr::setValue(const QString& key, const QString& val)
+{
+ MyMoneyKeyValueContainer::setValue(key, val);
+ touch();
+}
+
+void MyMoneySeqAccessMgr::deletePair(const QString& key)
+{
+ MyMoneyKeyValueContainer::deletePair(key);
+ touch();
+}
+
+const QMap<QString, QString> MyMoneySeqAccessMgr::pairs(void) const
+{
+ return MyMoneyKeyValueContainer::pairs();
+}
+
+void MyMoneySeqAccessMgr::setPairs(const QMap<QString, QString>& list)
+{
+ MyMoneyKeyValueContainer::setPairs(list);
+ touch();
+}
+
+void MyMoneySeqAccessMgr::addSchedule(MyMoneySchedule& sched)
+{
+ // first perform all the checks
+ if(!sched.id().isEmpty())
+ throw new MYMONEYEXCEPTION("schedule already contains an id");
+
+ // The following will throw an exception when it fails
+ sched.validate(false);
+
+ MyMoneySchedule newSched(nextScheduleID(), sched);
+ m_scheduleList.insert(newSched.id(), newSched);
+ sched = newSched;
+}
+
+void MyMoneySeqAccessMgr::modifySchedule(const MyMoneySchedule& sched)
+{
+ QMap<QString, MyMoneySchedule>::ConstIterator it;
+
+ it = m_scheduleList.find(sched.id());
+ if(it == m_scheduleList.end()) {
+ QString msg = "Unknown schedule '" + sched.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_scheduleList.modify(sched.id(), sched);
+}
+
+void MyMoneySeqAccessMgr::removeSchedule(const MyMoneySchedule& sched)
+{
+ QMap<QString, MyMoneySchedule>::ConstIterator it;
+
+ it = m_scheduleList.find(sched.id());
+ if(it == m_scheduleList.end()) {
+ QString msg = "Unknown schedule '" + sched.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ // FIXME: check referential integrity for loan accounts
+ m_scheduleList.remove(sched.id());
+}
+
+const MyMoneySchedule MyMoneySeqAccessMgr::schedule(const QString& id) const
+{
+ QMap<QString, MyMoneySchedule>::ConstIterator pos;
+
+ // locate the schedule and if present, return it's data
+ pos = m_scheduleList.find(id);
+ if(pos != m_scheduleList.end())
+ return (*pos);
+
+ // throw an exception, if it does not exist
+ QString msg = "Unknown schedule id '" + id + "'";
+ throw new MYMONEYEXCEPTION(msg);
+}
+
+const QValueList<MyMoneySchedule> MyMoneySeqAccessMgr::scheduleList(
+ const QString& accountId,
+ const MyMoneySchedule::typeE type,
+ const MyMoneySchedule::occurenceE occurence,
+ const MyMoneySchedule::paymentTypeE paymentType,
+ const QDate& startDate,
+ const QDate& endDate,
+ const bool overdue) const
+{
+ QMap<QString, MyMoneySchedule>::ConstIterator pos;
+ QValueList<MyMoneySchedule> list;
+
+ // qDebug("scheduleList()");
+
+ for(pos = m_scheduleList.begin(); pos != m_scheduleList.end(); ++pos) {
+ // qDebug(" '%s'", qPrintable((*pos).id()));
+
+ if(type != MyMoneySchedule::TYPE_ANY) {
+ if(type != (*pos).type()) {
+ continue;
+ }
+ }
+
+ if(occurence != MyMoneySchedule::OCCUR_ANY) {
+ if(occurence != (*pos).occurence()) {
+ continue;
+ }
+ }
+
+ if(paymentType != MyMoneySchedule::STYPE_ANY) {
+ if(paymentType != (*pos).paymentType()) {
+ continue;
+ }
+ }
+
+ if(!accountId.isEmpty()) {
+ MyMoneyTransaction t = (*pos).transaction();
+ QValueList<MyMoneySplit>::ConstIterator it;
+ QValueList<MyMoneySplit> splits;
+ splits = t.splits();
+ for(it = splits.begin(); it != splits.end(); ++it) {
+ if((*it).accountId() == accountId)
+ break;
+ }
+ if(it == splits.end()) {
+ continue;
+ }
+ }
+
+ if(startDate.isValid() && endDate.isValid()) {
+ if((*pos).paymentDates(startDate, endDate).count() == 0) {
+ continue;
+ }
+ }
+
+ if(startDate.isValid() && !endDate.isValid()) {
+ if(!(*pos).nextPayment(startDate.addDays(-1)).isValid()) {
+ continue;
+ }
+ }
+
+ if(!startDate.isValid() && endDate.isValid()) {
+ if((*pos).startDate() > endDate) {
+ continue;
+ }
+ }
+
+ if(overdue) {
+ if (!(*pos).isOverdue())
+ continue;
+ }
+
+ // qDebug("Adding '%s'", (*pos).name().latin1());
+ list << *pos;
+ }
+ return list;
+}
+
+void MyMoneySeqAccessMgr::loadSchedules(const QMap<QString, MyMoneySchedule>& map)
+{
+ m_scheduleList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneySchedule>::const_iterator it_s;
+ QString lastId("");
+ for(it_s = map.begin(); it_s != map.end(); ++it_s) {
+ if((*it_s).id() > lastId)
+ lastId = (*it_s).id();
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextScheduleID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::loadScheduleId(const unsigned long id)
+{
+ m_nextScheduleID = id;
+}
+
+const QValueList<MyMoneySchedule> MyMoneySeqAccessMgr::scheduleListEx(int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate date,
+ const QStringList& accounts) const
+{
+// qDebug("scheduleListEx");
+
+ QMap<QString, MyMoneySchedule>::ConstIterator pos;
+ QValueList<MyMoneySchedule> list;
+
+ if (!date.isValid())
+ return list;
+
+ for(pos = m_scheduleList.begin(); pos != m_scheduleList.end(); ++pos)
+ {
+ if (scheduleTypes && !(scheduleTypes & (*pos).type()))
+ continue;
+
+ if (scheduleOcurrences && !(scheduleOcurrences & (*pos).occurence()))
+ continue;
+
+ if (schedulePaymentTypes && !(schedulePaymentTypes & (*pos).paymentType()))
+ continue;
+
+ if((*pos).paymentDates(date, date).count() == 0)
+ continue;
+
+ if ((*pos).isFinished())
+ continue;
+
+ if ((*pos).hasRecordedPayment(date))
+ continue;
+
+ if (accounts.count() > 0)
+ {
+ if (accounts.contains((*pos).account().id()))
+ continue;
+ }
+
+// qDebug("\tAdding '%s'", (*pos).name().latin1());
+ list << *pos;
+ }
+
+ return list;
+}
+
+void MyMoneySeqAccessMgr::addSecurity(MyMoneySecurity& security)
+{
+ // create the account
+ MyMoneySecurity newSecurity(nextSecurityID(), security);
+
+ m_securitiesList.insert(newSecurity.id(), newSecurity);
+
+ security = newSecurity;
+}
+
+void MyMoneySeqAccessMgr::modifySecurity(const MyMoneySecurity& security)
+{
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = m_securitiesList.find(security.id());
+ if(it == m_securitiesList.end())
+ {
+ QString msg = "Unknown security '";
+ msg += security.id() + "' during modifySecurity()";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_securitiesList.modify(security.id(), security);
+}
+
+void MyMoneySeqAccessMgr::removeSecurity(const MyMoneySecurity& security)
+{
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ // FIXME: check referential integrity
+
+ it = m_securitiesList.find(security.id());
+ if(it == m_securitiesList.end())
+ {
+ QString msg = "Unknown security '";
+ msg += security.id() + "' during removeSecurity()";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_securitiesList.remove(security.id());
+}
+
+const MyMoneySecurity MyMoneySeqAccessMgr::security(const QString& id) const
+{
+ QMap<QString, MyMoneySecurity>::ConstIterator it = m_securitiesList.find(id);
+ if(it != m_securitiesList.end())
+ {
+ return it.data();
+ }
+
+ return MyMoneySecurity();
+}
+
+const QValueList<MyMoneySecurity> MyMoneySeqAccessMgr::securityList(void) const
+{
+ //qDebug("securityList: Security list size is %d, this=%8p", m_equitiesList.size(), (void*)this);
+ return m_securitiesList.values();
+}
+
+void MyMoneySeqAccessMgr::addCurrency(const MyMoneySecurity& currency)
+{
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = m_currencyList.find(currency.id());
+ if(it != m_currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot add currency with existing id %1").arg(currency.id().data()));
+ }
+
+ m_currencyList.insert(currency.id(), currency);
+}
+
+void MyMoneySeqAccessMgr::modifyCurrency(const MyMoneySecurity& currency)
+{
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = m_currencyList.find(currency.id());
+ if(it == m_currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot modify currency with unknown id %1").arg(currency.id().data()));
+ }
+
+ m_currencyList.modify(currency.id(), currency);
+}
+
+void MyMoneySeqAccessMgr::removeCurrency(const MyMoneySecurity& currency)
+{
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ // FIXME: check referential integrity
+
+ it = m_currencyList.find(currency.id());
+ if(it == m_currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot remove currency with unknown id %1").arg(currency.id().data()));
+ }
+
+ m_currencyList.remove(currency.id());
+}
+
+const MyMoneySecurity MyMoneySeqAccessMgr::currency(const QString& id) const
+{
+ if(id.isEmpty()) {
+
+ }
+ QMap<QString, MyMoneySecurity>::ConstIterator it;
+
+ it = m_currencyList.find(id);
+ if(it == m_currencyList.end()) {
+ throw new MYMONEYEXCEPTION(QString("Cannot retrieve currency with unknown id '%1'").arg(id.data()));
+ }
+
+ return *it;
+}
+
+const QValueList<MyMoneySecurity> MyMoneySeqAccessMgr::currencyList(void) const
+{
+ return m_currencyList.values();
+}
+
+const QValueList<MyMoneyReport> MyMoneySeqAccessMgr::reportList(void) const
+{
+ return m_reportList.values();
+}
+
+void MyMoneySeqAccessMgr::addReport( MyMoneyReport& report )
+{
+ if(!report.id().isEmpty())
+ throw new MYMONEYEXCEPTION("report already contains an id");
+
+ MyMoneyReport newReport(nextReportID(), report);
+ m_reportList.insert(newReport.id(), newReport);
+ report = newReport;
+}
+
+void MyMoneySeqAccessMgr::loadReports(const QMap<QString, MyMoneyReport>& map)
+{
+ m_reportList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneyReport>::const_iterator it_r;
+ QString lastId("");
+ for(it_r = map.begin(); it_r != map.end(); ++it_r) {
+ if((*it_r).id() > lastId)
+ lastId = (*it_r).id();
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextReportID = atol(lastId.mid(pos));
+ }
+}
+
+void MyMoneySeqAccessMgr::modifyReport( const MyMoneyReport& report )
+{
+ QMap<QString, MyMoneyReport>::ConstIterator it;
+
+ it = m_reportList.find(report.id());
+ if(it == m_reportList.end()) {
+ QString msg = "Unknown report '" + report.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+ m_reportList.modify(report.id(), report);
+}
+
+QString MyMoneySeqAccessMgr::nextReportID(void)
+{
+ QString id;
+ id.setNum(++m_nextReportID);
+ id = "R" + id.rightJustify(REPORT_ID_SIZE, '0');
+ return id;
+}
+
+unsigned MyMoneySeqAccessMgr::countReports(void) const
+{
+ return m_reportList.count();
+}
+
+const MyMoneyReport MyMoneySeqAccessMgr::report( const QString& _id ) const
+{
+ return m_reportList[_id];
+}
+
+void MyMoneySeqAccessMgr::removeReport( const MyMoneyReport& report )
+{
+ QMap<QString, MyMoneyReport>::ConstIterator it;
+
+ it = m_reportList.find(report.id());
+ if(it == m_reportList.end()) {
+ QString msg = "Unknown report '" + report.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_reportList.remove(report.id());
+}
+
+const QValueList<MyMoneyBudget> MyMoneySeqAccessMgr::budgetList(void) const
+{
+ return m_budgetList.values();
+}
+
+
+void MyMoneySeqAccessMgr::addBudget( MyMoneyBudget& budget )
+{
+ MyMoneyBudget newBudget(nextBudgetID(), budget);
+ m_budgetList.insert(newBudget.id(), newBudget);
+ budget = newBudget;
+}
+
+void MyMoneySeqAccessMgr::loadBudgets(const QMap<QString, MyMoneyBudget>& map)
+{
+ m_budgetList = map;
+
+ // scan the map to identify the last used id
+ QMap<QString, MyMoneyBudget>::const_iterator it_b;
+ QString lastId("");
+ for(it_b = map.begin(); it_b != map.end(); ++it_b) {
+ if((*it_b).id() > lastId)
+ lastId = (*it_b).id();
+ }
+
+ int pos = lastId.find(QRegExp("\\d+"), 0);
+ if(pos != -1) {
+ m_nextBudgetID = atol(lastId.mid(pos));
+ }
+}
+
+const MyMoneyBudget MyMoneySeqAccessMgr::budgetByName(const QString& budget) const
+{
+ QMap<QString, MyMoneyBudget>::ConstIterator it_p;
+
+ for(it_p = m_budgetList.begin(); it_p != m_budgetList.end(); ++it_p) {
+ if((*it_p).name() == budget) {
+ return *it_p;
+ }
+ }
+
+ throw new MYMONEYEXCEPTION("Unknown budget '" + budget + "'");
+}
+
+void MyMoneySeqAccessMgr::modifyBudget( const MyMoneyBudget& budget )
+{
+ QMap<QString, MyMoneyBudget>::ConstIterator it;
+
+ it = m_budgetList.find(budget.id());
+ if(it == m_budgetList.end()) {
+ QString msg = "Unknown budget '" + budget.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+ m_budgetList.modify(budget.id(), budget);
+}
+
+QString MyMoneySeqAccessMgr::nextBudgetID(void)
+{
+ QString id;
+ id.setNum(++m_nextBudgetID);
+ id = "B" + id.rightJustify(BUDGET_ID_SIZE, '0');
+ return id;
+}
+
+unsigned MyMoneySeqAccessMgr::countBudgets(void) const
+{
+ return m_budgetList.count();
+}
+
+MyMoneyBudget MyMoneySeqAccessMgr::budget( const QString& _id ) const
+{
+ return m_budgetList[_id];
+}
+
+void MyMoneySeqAccessMgr::removeBudget( const MyMoneyBudget& budget )
+{
+ QMap<QString, MyMoneyBudget>::ConstIterator it;
+
+ it = m_budgetList.find(budget.id());
+ if(it == m_budgetList.end()) {
+ QString msg = "Unknown budget '" + budget.id() + "'";
+ throw new MYMONEYEXCEPTION(msg);
+ }
+
+ m_budgetList.remove(budget.id());
+}
+
+void MyMoneySeqAccessMgr::addPrice(const MyMoneyPrice& price)
+{
+ MyMoneySecurityPair pricePair(price.from(), price.to());
+ QMap<MyMoneySecurityPair, MyMoneyPriceEntries>::ConstIterator it_m;
+ it_m = m_priceList.find(pricePair);
+
+ MyMoneyPriceEntries entries;
+ if(it_m != m_priceList.end()) {
+ entries = (*it_m);
+ }
+ // entries contains the current entries for this security pair
+ // in case it_m points to m_priceList.end() we need to create a
+ // new entry in the priceList, otherwise we need to modify
+ // an existing one.
+
+ MyMoneyPriceEntries::ConstIterator it;
+ it = entries.find(price.date());
+ if(it != entries.end()) {
+ if((*it).rate(QString()) == price.rate(QString())
+ && (*it).source() == price.source())
+ // in case the information did not change, we don't do anything
+ return;
+ }
+
+ // store new value in local copy
+ entries[price.date()] = price;
+
+ if(it_m != m_priceList.end()) {
+ m_priceList.modify(pricePair, entries);
+ } else {
+ m_priceList.insert(pricePair, entries);
+ }
+}
+
+void MyMoneySeqAccessMgr::removePrice(const MyMoneyPrice& price)
+{
+ MyMoneySecurityPair pricePair(price.from(), price.to());
+ QMap<MyMoneySecurityPair, MyMoneyPriceEntries>::ConstIterator it_m;
+ it_m = m_priceList.find(pricePair);
+
+ MyMoneyPriceEntries entries;
+ if(it_m != m_priceList.end()) {
+ entries = (*it_m);
+ }
+
+ // store new value in local copy
+ entries.remove(price.date());
+
+ if(entries.count() != 0) {
+ m_priceList.modify(pricePair, entries);
+ } else {
+ m_priceList.remove(pricePair);
+ }
+}
+
+const MyMoneyPriceList MyMoneySeqAccessMgr::priceList(void) const
+{
+ MyMoneyPriceList list;
+ m_priceList.map(list);
+ return list;
+}
+
+const MyMoneyPrice MyMoneySeqAccessMgr::price(const QString& fromId, const QString& toId, const QDate& _date, const bool exactDate) const
+{
+ MyMoneyPrice rc;
+ MyMoneyPriceEntries::ConstIterator it;
+ QDate date(_date);
+
+ // If no valid date is passed, we use today's date.
+ if(!date.isValid())
+ date = QDate::currentDate();
+
+ // If the caller selected an exact entry, we can search for
+ // it using the date as the key
+ if(exactDate) {
+ it = m_priceList[MyMoneySecurityPair(fromId, toId)].find(date);
+ if(it != m_priceList[MyMoneySecurityPair(fromId, toId)].end())
+ rc = *it;
+
+ } else {
+ // otherwise, we must scan the map for the previous price entry
+ for(it = m_priceList[MyMoneySecurityPair(fromId, toId)].begin(); it != m_priceList[MyMoneySecurityPair(fromId, toId)].end(); ++it) {
+ if(date < it.key())
+ break;
+
+ if(date >= it.key())
+ rc = *it;
+ }
+ }
+ return rc;
+}
+
+void MyMoneySeqAccessMgr::clearCache(void)
+{
+ m_balanceCache.clear();
+}
+
+void MyMoneySeqAccessMgr::rebuildAccountBalances(void)
+{
+ // reset the balance of all accounts to 0
+ QMap<QString, MyMoneyAccount> map;
+ m_accountList.map(map);
+
+ QMap<QString, MyMoneyAccount>::iterator it_a;
+ for(it_a = map.begin(); it_a != map.end(); ++it_a) {
+ (*it_a).setBalance(MyMoneyMoney(0));
+ }
+
+ // now scan over all transactions and all splits and setup the balances
+ QMap<QString, MyMoneyTransaction>::const_iterator it_t;
+ for(it_t = m_transactionList.begin(); it_t != m_transactionList.end(); ++it_t) {
+ const QValueList<MyMoneySplit>& splits = (*it_t).splits();
+ QValueList<MyMoneySplit>::const_iterator it_s = splits.begin();
+ for(; it_s != splits.end(); ++it_s ) {
+ if(!(*it_s).shares().isZero()) {
+ const QString& id = (*it_s).accountId();
+ // locate the account and if present, update data
+ if(map.find(id) != map.end()) {
+ map[id].adjustBalance(*it_s);
+ }
+ }
+ }
+ }
+
+ m_accountList = map;
+}
+
+bool MyMoneySeqAccessMgr::isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipCheck) const
+{
+ // We delete all references in reports when an object
+ // is deleted, so we don't need to check here. See
+ // MyMoneySeqAccessMgr::removeReferences(). In case
+ // you miss the report checks in the following lines ;)
+
+ bool rc = false;
+ const QString& id = obj.id();
+ QMap<QString, MyMoneyTransaction>::const_iterator it_t;
+ QMap<QString, MyMoneyAccount>::const_iterator it_a;
+ QMap<QString, MyMoneyInstitution>::const_iterator it_i;
+ QMap<QString, MyMoneyPayee>::const_iterator it_p;
+ QMap<QString, MyMoneyBudget>::const_iterator it_b;
+ QMap<QString, MyMoneySchedule>::const_iterator it_sch;
+ QMap<QString, MyMoneySecurity>::const_iterator it_sec;
+ MyMoneyPriceList::const_iterator it_pr;
+
+ // FIXME optimize the list of objects we have to checks
+ // with a bit of knowledge of the internal structure, we
+ // could optimize the number of objects we check for references
+
+ // Scan all engine objects for a reference
+ if(!skipCheck[RefCheckTransaction]) {
+ for(it_t = m_transactionList.begin(); !rc && it_t != m_transactionList.end(); ++it_t) {
+ rc = (*it_t).hasReferenceTo(id);
+ }
+ }
+
+ if(!skipCheck[RefCheckAccount]) {
+ for(it_a = m_accountList.begin(); !rc && it_a != m_accountList.end(); ++it_a) {
+ rc = (*it_a).hasReferenceTo(id);
+ }
+ }
+ if(!skipCheck[RefCheckInstitution]) {
+ for(it_i = m_institutionList.begin(); !rc && it_i != m_institutionList.end(); ++it_i) {
+ rc = (*it_i).hasReferenceTo(id);
+ }
+ }
+ if(!skipCheck[RefCheckPayee]) {
+ for(it_p = m_payeeList.begin(); !rc && it_p != m_payeeList.end(); ++it_p) {
+ rc = (*it_p).hasReferenceTo(id);
+ }
+ }
+
+ if(!skipCheck[RefCheckBudget]) {
+ for(it_b = m_budgetList.begin(); !rc && it_b != m_budgetList.end(); ++it_b) {
+ rc = (*it_b).hasReferenceTo(id);
+ }
+ }
+ if(!skipCheck[RefCheckSchedule]) {
+ for(it_sch = m_scheduleList.begin(); !rc && it_sch != m_scheduleList.end(); ++it_sch) {
+ rc = (*it_sch).hasReferenceTo(id);
+ }
+ }
+ if(!skipCheck[RefCheckSecurity]) {
+ for(it_sec = m_securitiesList.begin(); !rc && it_sec != m_securitiesList.end(); ++it_sec) {
+ rc = (*it_sec).hasReferenceTo(id);
+ }
+ }
+ if(!skipCheck[RefCheckCurrency]) {
+ for(it_sec = m_currencyList.begin(); !rc && it_sec != m_currencyList.end(); ++it_sec) {
+ rc = (*it_sec).hasReferenceTo(id);
+ }
+ }
+ // within the pricelist we don't have to scan each entry. Checking the QPair
+ // members of the MyMoneySecurityPair is enough as they are identical to the
+ // two security ids
+ if(!skipCheck[RefCheckPrice]) {
+ for(it_pr = m_priceList.begin(); !rc && it_pr != m_priceList.end(); ++it_pr) {
+ rc = (it_pr.key().first == id) || (it_pr.key().second == id);
+ }
+ }
+
+ return rc;
+}
+
+void MyMoneySeqAccessMgr::startTransaction(void)
+{
+ m_payeeList.startTransaction(&m_nextPayeeID);
+ m_institutionList.startTransaction(&m_nextInstitutionID);
+ m_accountList.startTransaction(&m_nextPayeeID);
+ m_transactionList.startTransaction(&m_nextTransactionID);
+ m_transactionKeys.startTransaction();
+ m_scheduleList.startTransaction(&m_nextScheduleID);
+ m_securitiesList.startTransaction(&m_nextSecurityID);
+ m_currencyList.startTransaction();
+ m_reportList.startTransaction(&m_nextReportID);
+ m_budgetList.startTransaction(&m_nextBudgetID);
+ m_priceList.startTransaction();
+}
+
+bool MyMoneySeqAccessMgr::commitTransaction(void)
+{
+ bool rc = false;
+ rc |= m_payeeList.commitTransaction();
+ rc |= m_institutionList.commitTransaction();
+ rc |= m_accountList.commitTransaction();
+ rc |= m_transactionList.commitTransaction();
+ rc |= m_transactionKeys.commitTransaction();
+ rc |= m_scheduleList.commitTransaction();
+ rc |= m_securitiesList.commitTransaction();
+ rc |= m_currencyList.commitTransaction();
+ rc |= m_reportList.commitTransaction();
+ rc |= m_budgetList.commitTransaction();
+ rc |= m_priceList.commitTransaction();
+
+ // if there was a change, touch the whole storage object
+ if(rc)
+ touch();
+
+ return rc;
+}
+
+void MyMoneySeqAccessMgr::rollbackTransaction(void)
+{
+ m_payeeList.rollbackTransaction();
+ m_institutionList.rollbackTransaction();
+ m_accountList.rollbackTransaction();
+ m_transactionList.rollbackTransaction();
+ m_transactionKeys.rollbackTransaction();
+ m_scheduleList.rollbackTransaction();
+ m_securitiesList.rollbackTransaction();
+ m_currencyList.rollbackTransaction();
+ m_reportList.rollbackTransaction();
+ m_budgetList.rollbackTransaction();
+ m_priceList.rollbackTransaction();
+}
+
+void MyMoneySeqAccessMgr::removeReferences(const QString& id)
+{
+ QMap<QString, MyMoneyReport>::const_iterator it_r;
+ QMap<QString, MyMoneyBudget>::const_iterator it_b;
+
+ // remove from reports
+ for(it_r = m_reportList.begin(); it_r != m_reportList.end(); ++it_r) {
+ MyMoneyReport r = *it_r;
+ r.removeReference(id);
+ m_reportList.modify(r.id(), r);
+ }
+
+ // remove from budgets
+ for(it_b = m_budgetList.begin(); it_b != m_budgetList.end(); ++it_b) {
+ MyMoneyBudget b = *it_b;
+ b.removeReference(id);
+ m_budgetList.modify(b.id(), b);
+ }
+}
+
+#undef TRY
+#undef CATCH
+#undef PASS
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/storage/mymoneyseqaccessmgr.h b/kmymoney2/mymoney/storage/mymoneyseqaccessmgr.h
new file mode 100644
index 0000000..f200bef
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneyseqaccessmgr.h
@@ -0,0 +1,1232 @@
+/***************************************************************************
+ mymoneyseqaccessmgr.h - description
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSEQACCESSMGR_H
+#define MYMONEYSEQACCESSMGR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "imymoneystorage.h"
+#include "imymoneyserialize.h"
+#include "mymoneymap.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This member represents an item in the balance cache. The balance cache
+ * is used for fast processing of the balance of an account. Several
+ * of these objects are held by the MyMoneySeqAccessMgr() object in a map
+ * with the account Id as key. If such a cache item is present in the map,
+ * the contained balance of it will be used as current balance for this
+ * account. If the balance is changed by any operation, the
+ * MyMoneyBalanceCacheItem for the modified account will be removed from
+ * the map and the next time the balance for this account is requested,
+ * it has to be recalculated. After recalculation, a new MyMoneyBalanceCacheItem
+ * will be created containing the new balance value.
+ *
+ * @see MyMoneySeqAccessMgr::balance() and
+ * MyMoneySeqAccessMgr::invalidateBalanceCache() for a usage example
+ */
+class MyMoneyBalanceCacheItem {
+public:
+ MyMoneyBalanceCacheItem() { valid = false; };
+ MyMoneyBalanceCacheItem(const MyMoneyMoney& val) { balance = val; valid = true; };
+
+ bool operator == (const MyMoneyBalanceCacheItem& right) const;
+ bool valid;
+ MyMoneyMoney balance;
+};
+
+/**
+ * The MyMoneySeqAccessMgr class represents the storage engine for sequential
+ * files. The actual file type and it's internal storage format (e.g. binary
+ * or XML) is not important and handled through the IMyMoneySerialize() interface.
+ *
+ * The MyMoneySeqAccessMgr must be loaded by an application using the
+ * IMyMoneySerialize() interface and can then be accessed through the
+ * IMyMoneyStorage() interface. All data is loaded into memory, modified
+ * and kept there. It is the subject of an outside object to store the
+ * modified data in a persistant storage area using the IMyMoneySerialize()
+ * interface. As indication, if data has been changed, the retrun value
+ * of the method dirty() can be used.
+ */
+class MyMoneySeqAccessMgr : public IMyMoneyStorage, public IMyMoneySerialize,
+ public MyMoneyKeyValueContainer
+{
+public:
+
+ MyMoneySeqAccessMgr();
+ ~MyMoneySeqAccessMgr();
+
+ // general get functions
+ const MyMoneyPayee user(void) const { return m_user; };
+ const QDate creationDate(void) const { return m_creationDate; };
+ const QDate lastModificationDate(void) const { return m_lastModificationDate; };
+ unsigned int currentFixVersion(void) const { return m_currentFixVersion; };
+ unsigned int fileFixVersion(void) const { return m_fileFixVersion; };
+
+
+ // general set functions
+ void setUser(const MyMoneyPayee& user) { m_user = user;
+ touch(); };
+ void setCreationDate(const QDate& val) { m_creationDate = val; touch(); };
+ void setLastModificationDate(const QDate& val) { m_lastModificationDate = val; m_dirty = false; };
+ void setFileFixVersion(const unsigned int v) { m_fileFixVersion = v; };
+ /**
+ * This method is used to get a SQL reader for subsequent database access
+ */
+ KSharedPtr <MyMoneyStorageSql> connectToDatabase (const KURL& url);
+ /**
+ * This method is used when a database file is open, and the data is to
+ * be saved in a different file or format. It will ensure that all data
+ * from the database is available in memory to enable it to be written.
+ */
+ virtual void fillStorage() { };
+
+ /**
+ * This method is used to duplicate the MyMoneySeqAccessMgr object and return
+ * a pointer to the newly created copy. The caller of this method is the
+ * new owner of the object and must destroy it.
+ */
+ MyMoneySeqAccessMgr const * duplicate(void);
+
+ /**
+ * Returns the account addressed by it's id.
+ *
+ * @param id id of the account to locate.
+ * @return reference to MyMoneyAccount object. An exception is thrown
+ * if the id is unknown
+ */
+ const MyMoneyAccount account(const QString& id) const;
+
+ /**
+ * This method is used to check whether a given
+ * account id references one of the standard accounts or not.
+ *
+ * @param id account id
+ * @return true if account-id is one of the standards, false otherwise
+ */
+ bool isStandardAccount(const QString& id) const;
+
+ /**
+ * This method is used to set the name for the specified standard account
+ * within the storage area. An exception will be thrown, if an error
+ * occurs
+ *
+ * @param id QString reference to one of the standard accounts. Possible
+ * values are:
+ *
+ * @li STD_ACC_LIABILITY
+ * @li STD_ACC_ASSET
+ * @li STD_ACC_EXPENSE
+ * @li STD_ACC_INCOME
+ * @li STD_ACC_EQUITY
+ *
+ * @param name QString reference to the name to be set
+ *
+ */
+ void setAccountName(const QString& id, const QString& name);
+
+ /**
+ * This method is used to create a new account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount filled with data
+ */
+ void addAccount(MyMoneyAccount& account);
+
+ /**
+ * This method is used to create a new payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ void addPayee(MyMoneyPayee& payee);
+
+ /**
+ * This method is used to retrieve information about a payee
+ * An exception will be thrown upon error conditions.
+ *
+ * @param id QString reference to id of payee
+ *
+ * @return MyMoneyPayee object of payee
+ */
+ const MyMoneyPayee payee(const QString& id) const;
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a payee/receiver.
+ * An exception will be thrown upon error conditions.
+ *
+ * @param payee QString reference to name of payee
+ *
+ * @return MyMoneyPayee reference to object of payee
+ */
+ const MyMoneyPayee payeeByName(const QString& payee) const;
+
+ /**
+ * This method is used to modify an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ void modifyPayee(const MyMoneyPayee& payee);
+
+ /**
+ * This method is used to remove an existing payee
+ *
+ * An exception will be thrown upon error conditions
+ *
+ * @param payee MyMoneyPayee reference to payee information
+ */
+ void removePayee(const MyMoneyPayee& payee);
+
+ /**
+ * This method returns a list of the payees
+ * inside a MyMoneyStorage object
+ *
+ * @return QValueList<MyMoneyPayee> containing the payee information
+ */
+ const QValueList<MyMoneyPayee> payeeList(void) const;
+
+ /**
+ * This method is used to add one account as sub-ordinate to another
+ * (parent) account. The objects passed as arguments will be modified
+ * accordingly.
+ *
+ * @param parent parent account the account should be added to
+ * @param account the account to be added
+ */
+ void addAccount(MyMoneyAccount& parent, MyMoneyAccount& account);
+
+ /**
+ * Adds an institution to the storage. A
+ * respective institution-ID will be generated within this record.
+ * The ID is stored as QString in the object passed as argument.
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete institution information in a
+ * MyMoneyInstitution object
+ */
+ void addInstitution(MyMoneyInstitution& institution);
+
+ /**
+ * Adds a transaction to the file-global transaction pool. A respective
+ * transaction-ID will be generated within this record. The ID is stored
+ * as QString in the transaction object. The accounts of the referenced splits
+ * will be updated to have a reference to the transaction just added.
+ *
+ * @param transaction reference to the transaction
+ * @param skipAccountUpdate if set, the transaction lists of the accounts
+ * referenced in the splits are not updated. This is used for
+ * bulk loading a lot of transactions but not during normal operation
+ */
+ void addTransaction(MyMoneyTransaction& transaction, const bool skipAccountUpdate = false);
+
+ /**
+ * Modifies an already existing account in the file global account pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account reference to the new account information
+ * @param skipCheck if @p true, skips the built in consistency check for
+ * the object to be updated. Do not set this parameter
+ * to true. This is only used for the MyMoneyFile::consistencyCheck()
+ * procedure to be able to reload accounts. The default
+ * setting of this parameter is @p false.
+ */
+ void modifyAccount(const MyMoneyAccount& account, const bool skipCheck = false);
+
+ /**
+ * Modifies an already existing institution in the file global
+ * institution pool.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param institution The complete new institution information
+ */
+ void modifyInstitution(const MyMoneyInstitution& institution);
+
+ /**
+ * This method is used to update a specific transaction in the
+ * transaction pool of the MyMoneyFile object
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param transaction reference to transaction to be changed
+ */
+ void modifyTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * This method re-parents an existing account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount reference to account to be re-parented
+ * @param parent MyMoneyAccount reference to new parent account
+ */
+ void reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent);
+
+ /**
+ * This method is used to remove a transaction from the transaction
+ * pool (journal).
+ *
+ * @param transaction const reference to transaction to be deleted
+ */
+ void removeTransaction(const MyMoneyTransaction& transaction);
+
+ /**
+ * Deletes an existing account from the file global account pool
+ * This method only allows to remove accounts that are not
+ * referenced by any split. Use moveSplits() to move splits
+ * to another account. An exception is thrown in case of a
+ * problem.
+ *
+ * @param account reference to the account to be deleted.
+ */
+ void removeAccount(const MyMoneyAccount& account);
+
+ /**
+ * Deletes an existing institution from the file global institution pool
+ * Also modifies the accounts that reference this institution as
+ * their institution.
+ *
+ * @param institution institution to be deleted.
+ */
+ void removeInstitution(const MyMoneyInstitution& institution);
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an id. In case of an invalid id, an
+ * exception will be thrown.
+ *
+ * @param id id of transaction as QString.
+ * @return reference to the requested transaction
+ */
+ const MyMoneyTransaction transaction(const QString& id) const;
+
+ /**
+ * This method is used to extract a transaction from the file global
+ * transaction pool through an index into an account.
+ *
+ * @param account id of the account as QString
+ * @param idx number of transaction in this account
+ * @return reference to MyMoneyTransaction object
+ */
+ const MyMoneyTransaction transaction(const QString& account, const int idx) const;
+
+ /**
+ * This method is used to determince, if the account with the
+ * given ID is referenced by any split in m_transactionList.
+ *
+ * @param id id of the account to be checked for
+ * @return true if account is referenced, false otherwise
+ */
+ bool hasActiveSplits(const QString& id) const;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * without it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+ const MyMoneyMoney balance(const QString& id, const QDate& date = QDate()) const;
+
+ /**
+ * This method is used to return the actual balance of an account
+ * including it's sub-ordinate accounts. If a @p date is presented,
+ * the balance at the beginning of this date (not including any
+ * transaction on this date) is returned. Otherwise all recorded
+ * transactions are included in the balance.
+ *
+ * @param id id of the account in question
+ * @param date return balance for specific date
+ * @return balance of the account as MyMoneyMoney object
+ */
+ const MyMoneyMoney totalBalance(const QString& id, const QDate& date = QDate()) const;
+
+ /**
+ * Returns the institution of a given ID
+ *
+ * @param id id of the institution to locate
+ * @return MyMoneyInstitution object filled with data. If the institution
+ * could not be found, an exception will be thrown
+ */
+ const MyMoneyInstitution institution(const QString& id) const;
+
+ /**
+ * This method returns an indicator if the storage object has been
+ * changed after it has last been saved to permanent storage.
+ *
+ * @return true if changed, false if not
+ */
+ bool dirty(void) const { return m_dirty; }
+
+ /**
+ * This method can be used by an external object to force the
+ * storage object to be dirty. This is used e.g. when an upload
+ * to an external destination failed but the previous storage
+ * to a local disk was ok.
+ */
+ void setDirty(void) { m_dirty = true; };
+
+ /**
+ * This method returns a list of the institutions
+ * inside a MyMoneyFile object
+ *
+ * @return QMap containing the institution information
+ */
+ const QValueList<MyMoneyInstitution> institutionList(void) const;
+
+ /**
+ * This method returns a list of accounts inside the storage object.
+ *
+ * @param list reference to QValueList receiving the account objects
+ *
+ * @note The standard accounts will not be returned
+ */
+ void accountList(QValueList<MyMoneyAccount>& list) const;
+
+ /**
+ * This method is used to pull a list of transactions from the file
+ * global transaction pool. It returns all those transactions
+ * that match the filter passed as argument. If the filter is empty,
+ * the whole journal will be returned.
+ * The list returned is sorted according to the transactions posting date.
+ * If more than one transaction exists for the same date, the order among
+ * them is undefined.
+ *
+ * The @p list will be cleared by this method.
+ *
+ * @param list reference to list
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ *
+ * @return set of transactions in form of a QValueList<MyMoneyTransaction>
+ */
+ void transactionList(QValueList<MyMoneyTransaction>& list, MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * This method is used to pull a list of transactions from the file
+ * global transaction pool. It returns all those transactions
+ * that match the filter passed as argument. If the filter is empty,
+ * the whole journal will be returned.
+ * The list returned is sorted according to the transactions posting date.
+ * If more than one transaction exists for the same date, the order among
+ * them is undefined.
+ *
+ * The @p list will be cleared by this method.
+ *
+ * @param list reference to list
+ * @param filter MyMoneyTransactionFilter object with the match criteria
+ *
+ * @return set of transactions in form of a QValueList<QPair<MyMoneyTransaction,MyMoneySplit> >
+ */
+ void transactionList(QValueList< QPair<MyMoneyTransaction, MyMoneySplit> >& list, MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * Compatibility interface for the previous method.
+ */
+ const QValueList<MyMoneyTransaction> transactionList(MyMoneyTransactionFilter& filter) const;
+
+ /**
+ * This method returns whether a given transaction is already in memory, to avoid
+ * reloading it from the database
+ */
+ bool isDuplicateTransaction(const QString& id) const { return m_transactionKeys.contains(id); }
+
+ /**
+ * This method returns the number of transactions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @param account QString reference to account id. If account is empty
+ + all transactions (the journal) will be counted. If account
+ * is not empty it returns the number of transactions
+ * that have splits in this account.
+ *
+ * @return number of transactions in journal/account
+ */
+ unsigned int transactionCount(const QString& account = QString()) const;
+
+ const QMap<QString, unsigned long> transactionCountMap(void) const;
+
+ /**
+ * This method returns the number of institutions currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of institutions known to file
+ */
+ unsigned int institutionCount(void) const;
+
+ /**
+ * This method returns the number of accounts currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of accounts currently known inside a MyMoneyFile object
+ */
+ unsigned int accountCount(void) const;
+
+ /**
+ * This method is used to return the standard liability account
+ * @return MyMoneyAccount liability account(group)
+ */
+ const MyMoneyAccount liability(void) const { return account(STD_ACC_LIABILITY); };
+
+ /**
+ * This method is used to return the standard asset account
+ * @return MyMoneyAccount asset account(group)
+ */
+ const MyMoneyAccount asset(void) const { return account(STD_ACC_ASSET); };
+
+ /**
+ * This method is used to return the standard expense account
+ * @return MyMoneyAccount expense account(group)
+ */
+ const MyMoneyAccount expense(void) const { return account(STD_ACC_EXPENSE); };
+
+ /**
+ * This method is used to return the standard income account
+ * @return MyMoneyAccount income account(group)
+ */
+ const MyMoneyAccount income(void) const { return account(STD_ACC_INCOME); };
+
+ /**
+ * This method is used to return the standard equity account
+ * @return MyMoneyAccount equity account(group)
+ */
+ const MyMoneyAccount equity(void) const { return account(STD_ACC_EQUITY); };
+
+ virtual void loadAccounts(const QMap<QString, MyMoneyAccount>& acc);
+ virtual void loadTransactions(const QMap<QString, MyMoneyTransaction>& map);
+ virtual void loadInstitutions(const QMap<QString, MyMoneyInstitution>& map);
+ virtual void loadPayees(const QMap<QString, MyMoneyPayee>& map);
+ virtual void loadSchedules(const QMap<QString, MyMoneySchedule>& map);
+ virtual void loadSecurities(const QMap<QString, MyMoneySecurity>& map);
+ virtual void loadCurrencies(const QMap<QString, MyMoneySecurity>& map);
+ virtual void loadPrices(const MyMoneyPriceList& list);
+
+ virtual void loadAccountId(const unsigned long id);
+ virtual void loadTransactionId(const unsigned long id);
+ virtual void loadPayeeId(const unsigned long id);
+ virtual void loadInstitutionId(const unsigned long id);
+ virtual void loadScheduleId(const unsigned long id);
+ virtual void loadSecurityId(const unsigned long id);
+ virtual void loadReportId(const unsigned long id);
+ virtual void loadBudgetId(const unsigned long id);
+
+ virtual unsigned long accountId(void) const { return m_nextAccountID; };
+ virtual unsigned long transactionId(void) const { return m_nextTransactionID; };
+ virtual unsigned long payeeId(void) const { return m_nextPayeeID; };
+ virtual unsigned long institutionId(void) const { return m_nextInstitutionID; };
+ virtual unsigned long scheduleId(void) const { return m_nextScheduleID; };
+ virtual unsigned long securityId(void) const { return m_nextSecurityID; };
+ virtual unsigned long reportId(void) const { return m_nextReportID; };
+ virtual unsigned long budgetId(void) const { return m_nextBudgetID; };
+
+
+ /**
+ * This method is used to extract a value from
+ * KeyValueContainer. For details see MyMoneyKeyValueContainer::value().
+ *
+ * @param key const reference to QString containing the key
+ * @return QString containing the value
+ */
+ const QString value(const QString& key) const;
+
+ /**
+ * This method is used to set a value in the
+ * KeyValueContainer. For details see MyMoneyKeyValueContainer::setValue().
+ *
+ * @param key const reference to QString containing the key
+ * @param val const reference to QString containing the value
+ */
+ void setValue(const QString& key, const QString& val);
+
+ /**
+ * This method is used to delete a key-value-pair from the
+ * KeyValueContainer identified by the parameter
+ * @p key. For details see MyMoneyKeyValueContainer::deletePair().
+ *
+ * @param key const reference to QString containing the key
+ */
+ void deletePair(const QString& key);
+
+ // documented in IMyMoneySerialize base class
+ const QMap<QString, QString> pairs(void) const;
+
+ // documented in IMyMoneySerialize base class
+ void setPairs(const QMap<QString, QString>& list);
+
+ /**
+ * This method is used to add a scheduled transaction to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched reference to the MyMoneySchedule object
+ */
+ void addSchedule(MyMoneySchedule& sched);
+
+ /**
+ * This method is used to modify an existing MyMoneySchedule
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ void modifySchedule(const MyMoneySchedule& sched);
+
+ /**
+ * This method is used to remove an existing MyMoneySchedule object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param sched const reference to the MyMoneySchedule object to be updated
+ */
+ void removeSchedule(const MyMoneySchedule& sched);
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ const MyMoneySchedule schedule(const QString& id) const;
+
+ /**
+ * This method is used to create a new security object. The ID will be created
+ * automatically. The object passed with the parameter @p security is modified
+ * to contain the assigned id.
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param security MyMoneySecurity filled with data
+ */
+ virtual void addSecurity(MyMoneySecurity& security);
+
+ /**
+ * This method is used to modify an existing MyMoneySchedule
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be updated
+ */
+ void modifySecurity(const MyMoneySecurity& security);
+
+ /**
+ * This method is used to remove an existing MyMoneySecurity object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param security reference to the MyMoneySecurity object to be removed
+ */
+ void removeSecurity(const MyMoneySecurity& security);
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ const MyMoneySecurity security(const QString& id) const;
+
+
+ /**
+ * This method returns a list of security objects that the engine has
+ * knowledge of.
+ */
+ const QValueList<MyMoneySecurity> securityList(void) const;
+
+ /**
+ * This method is used to add a new currency object to the engine.
+ * The ID of the object is the trading symbol, so there is no need for an additional
+ * ID since the symbol is guaranteed to be unique.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneyCurrency object
+ */
+ void addCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to modify an existing MyMoneyCurrency
+ * object.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneyCurrency object
+ */
+ void modifyCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to remove an existing MyMoneyCurrency object
+ * from the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param currency reference to the MyMoneyCurrency object
+ */
+ void removeCurrency(const MyMoneySecurity& currency);
+
+ /**
+ * This method is used to retrieve a single MyMoneySchedule object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneySchedule object
+ * @return MyMoneySchedule object
+ */
+ const MyMoneySecurity currency(const QString& id) const;
+
+ /**
+ * This method is used to retrieve the list of all currencies
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyCurrency objects.
+ */
+ const QValueList<MyMoneySecurity> currencyList(void) const;
+
+ /**
+ * This method is used to extract a list of scheduled transactions
+ * according to the filter criteria passed as arguments.
+ *
+ * @param accountId only search for scheduled transactions that reference
+ * accound @p accountId. If accountId is the empty string,
+ * this filter is off. Default is @p QString().
+ * @param type only schedules of type @p type are searched for.
+ * See MyMoneySchedule::typeE for details.
+ * Default is MyMoneySchedule::TYPE_ANY
+ * @param occurence only schedules of occurence type @p occurence are searched for.
+ * See MyMoneySchedule::occurenceE for details.
+ * Default is MyMoneySchedule::OCCUR_ANY
+ * @param paymentType only schedules of payment method @p paymentType
+ * are searched for.
+ * See MyMoneySchedule::paymentTypeE for details.
+ * Default is MyMoneySchedule::STYPE_ANY
+ * @param startDate only schedules with payment dates after @p startDate
+ * are searched for. Default is all dates (QDate()).
+ * @param endDate only schedules with payment dates ending prior to @p endDate
+ * are searched for. Default is all dates (QDate()).
+ * @param overdue if true, only those schedules that are overdue are
+ * searched for. Default is false (all schedules will be returned).
+ *
+ * @return const QValueList<MyMoneySchedule> list of schedule objects.
+ */
+ const QValueList<MyMoneySchedule> scheduleList(const QString& accountId = QString(),
+ const MyMoneySchedule::typeE type = MyMoneySchedule::TYPE_ANY,
+ const MyMoneySchedule::occurenceE occurence = MyMoneySchedule::OCCUR_ANY,
+ const MyMoneySchedule::paymentTypeE paymentType = MyMoneySchedule::STYPE_ANY,
+ const QDate& startDate = QDate(),
+ const QDate& endDate = QDate(),
+ const bool overdue = false) const;
+
+ const QValueList<MyMoneySchedule> scheduleListEx( int scheduleTypes,
+ int scheduleOcurrences,
+ int schedulePaymentTypes,
+ QDate startDate,
+ const QStringList& accounts=QStringList()) const;
+
+ /**
+ * This method is used to retrieve the list of all reports
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyReport objects.
+ */
+ const QValueList<MyMoneyReport> reportList( void ) const;
+
+ /**
+ * This method is used to add a new report to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report reference to the MyMoneyReport object
+ */
+ void addReport( MyMoneyReport& report );
+
+ /**
+ * This method is used to load a set of reports into the engine. This is
+ * used when loading from storage, and an ID is already known.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param reports reference to the map of MyMoneyReport objects
+ */
+ void loadReports( const QMap<QString, MyMoneyReport>& reports );
+
+ /**
+ * This method is used to modify an existing MyMoneyReport
+ * object. Therefor, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ void modifyReport( const MyMoneyReport& report );
+
+ /**
+ * This method returns the number of reports currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of reports known to file
+ */
+ unsigned countReports(void) const;
+
+ /**
+ * This method is used to retrieve a single MyMoneyReport object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyReport object
+ * @return MyMoneyReport object
+ */
+ const MyMoneyReport report( const QString& id ) const;
+
+ /**
+ * This method is used to remove an existing MyMoneyReport object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param report const reference to the MyMoneyReport object to be updated
+ */
+ void removeReport(const MyMoneyReport& report);
+
+ /**
+ * This method is used to retrieve the list of all budgets
+ * known to the engine.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @return QValueList of all MyMoneyBudget objects.
+ */
+ const QValueList<MyMoneyBudget> budgetList( void ) const;
+
+ /**
+ * This method is used to add a new budget to the engine.
+ * It must be sure, that the id of the object is not filled. When the
+ * method returns to the caller, the id will be filled with the
+ * newly created object id value.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget reference to the MyMoneyBudget object
+ */
+ void addBudget( MyMoneyBudget& budget );
+
+ /**
+ * This method is used to load a set of budgets into the engine. This is
+ * used when loading from storage, and an ID is already known.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budgets reference to the map of MyMoneyBudget object
+ */
+ void loadBudgets(const QMap<QString, MyMoneyBudget>& budgets);
+
+ /**
+ * This method is used to retrieve the id to a corresponding
+ * name of a budget
+ * An exception will be thrown upon error conditions.
+ *
+ * @param budget QString reference to name of budget
+ *
+ * @return MyMoneyBudget reference to object of budget
+ */
+ const MyMoneyBudget budgetByName(const QString& budget) const;
+
+ /**
+ * This method is used to modify an existing MyMoneyBudget
+ * object. Therefore, the id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ void modifyBudget( const MyMoneyBudget& budget );
+
+ /**
+ * This method returns the number of budgets currently known to file
+ * in the range 0..MAXUINT
+ *
+ * @return number of budgets known to file
+ */
+ unsigned countBudgets(void) const;
+
+ /**
+ * This method is used to retrieve a single MyMoneyBudget object.
+ * The id of the object must be supplied in the parameter @p id.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param id QString containing the id of the MyMoneyBudget object
+ * @return MyMoneyBudget object
+ */
+ MyMoneyBudget budget( const QString& id ) const;
+
+ /**
+ * This method is used to remove an existing MyMoneyBudget object
+ * from the engine. The id attribute of the object must be set.
+ *
+ * An exception will be thrown upon erronous situations.
+ *
+ * @param budget const reference to the MyMoneyBudget object to be updated
+ */
+ void removeBudget(const MyMoneyBudget& budget);
+
+
+ /**
+ * This method adds/replaces a price to/from the price list
+ */
+ void addPrice(const MyMoneyPrice& price);
+
+ /**
+ * This method removes a price from the price list
+ */
+ void removePrice(const MyMoneyPrice& price);
+
+ /**
+ * This method retrieves a price from the price list.
+ * If @p date is inValid, QDate::currentDate() is assumed.
+ */
+ const MyMoneyPrice price(const QString& fromId, const QString& toId, const QDate& date, const bool exactDate) const;
+
+ /**
+ * This method returns a list of all price entries.
+ */
+ const MyMoneyPriceList priceList(void) const;
+
+ /**
+ * Clear all internal caches (used internally for performance measurements)
+ */
+ void clearCache(void);
+
+ /**
+ * This method checks, if the given @p object is referenced
+ * by another engine object.
+ *
+ * @param obj const reference to object to be checked
+ * @param skipCheck QBitArray with ReferenceCheckBits set for which
+ * the check should be skipped
+ *
+ * @retval false @p object is not referenced
+ * @retval true @p institution is referenced
+ */
+ bool isReferenced(const MyMoneyObject& obj, const MyMoneyFileBitArray& skipCheck = MyMoneyFileBitArray()) const;
+
+ /**
+ * This method recalculates the balances of all accounts
+ * based on the transactions stored in the engine.
+ */
+ void rebuildAccountBalances(void);
+
+ virtual void startTransaction(void);
+ virtual bool commitTransaction(void);
+ virtual void rollbackTransaction(void);
+
+protected:
+ void removeReferences(const QString& id);
+
+private:
+
+ static const int INSTITUTION_ID_SIZE = 6;
+ static const int ACCOUNT_ID_SIZE = 6;
+ static const int TRANSACTION_ID_SIZE = 18;
+ static const int PAYEE_ID_SIZE = 6;
+ static const int SCHEDULE_ID_SIZE = 6;
+ static const int SECURITY_ID_SIZE = 6;
+ static const int REPORT_ID_SIZE = 6;
+ static const int BUDGET_ID_SIZE = 6;
+
+ /**
+ * This method is used to set the dirty flag and update the
+ * date of the last modification.
+ */
+ void touch(void);
+
+ /**
+ * This method is used to invalidate the cached balance for
+ * the selected account and all it's parents.
+ *
+ * @param id id of the account in question
+ */
+ void invalidateBalanceCache(const QString& id);
+
+ /**
+ * This member variable keeps the User information.
+ * @see setUser()
+ */
+ MyMoneyPayee m_user;
+
+ /**
+ * The member variable m_nextInstitutionID keeps the number that will be
+ * assigned to the next institution created. It is maintained by
+ * nextInstitutionID().
+ */
+ unsigned long m_nextInstitutionID;
+
+ /**
+ * The member variable m_nextAccountID keeps the number that will be
+ * assigned to the next institution created. It is maintained by
+ * nextAccountID().
+ */
+ unsigned long m_nextAccountID;
+
+ /**
+ * The member variable m_nextTransactionID keeps the number that will be
+ * assigned to the next transaction created. It is maintained by
+ * nextTransactionID().
+ */
+ unsigned long m_nextTransactionID;
+
+ /**
+ * The member variable m_nextPayeeID keeps the number that will be
+ * assigned to the next payee created. It is maintained by
+ * nextPayeeID()
+ */
+ unsigned long m_nextPayeeID;
+
+ /**
+ * The member variable m_nextScheduleID keeps the number that will be
+ * assigned to the next schedule created. It is maintained by
+ * nextScheduleID()
+ */
+ unsigned long m_nextScheduleID;
+
+ /**
+ * The member variable m_nextSecurityID keeps the number that will be
+ * assigned to the next security object created. It is maintained by
+ * nextSecurityID()
+ */
+ unsigned long m_nextSecurityID;
+
+ unsigned long m_nextReportID;
+
+ /**
+ * The member variable m_nextBudgetID keeps the number that will be
+ * assigned to the next budget object created. It is maintained by
+ * nextBudgetID()
+ */
+ unsigned long m_nextBudgetID;
+
+ /**
+ * The member variable m_institutionList is the container for the
+ * institutions known within this file.
+ */
+ MyMoneyMap<QString, MyMoneyInstitution> m_institutionList;
+
+ /**
+ * The member variable m_accountList is the container for the accounts
+ * known within this file.
+ */
+ MyMoneyMap<QString, MyMoneyAccount> m_accountList;
+
+ /**
+ * The member variable m_balanceCache is the container for the
+ * accounts actual balance
+ */
+ mutable QMap<QString, MyMoneyBalanceCacheItem> m_balanceCache;
+
+ /**
+ * This member keeps the date for which the m_balanceCache member
+ * is valid. In case the whole cache is invalid it is set to
+ * QDate().
+ */
+ mutable QDate m_balanceCacheDate;
+
+ /**
+ * The member variable m_transactionList is the container for all
+ * transactions within this file.
+ * @see m_transactionKeys
+ */
+ MyMoneyMap<QString, MyMoneyTransaction> m_transactionList;
+
+ /**
+ * The member variable m_transactionKeys is used to convert
+ * transaction id's into the corresponding key used in m_transactionList.
+ * @see m_transactionList;
+ */
+ MyMoneyMap<QString, QString> m_transactionKeys;
+
+ /**
+ * A list containing all the payees that have been used
+ */
+ MyMoneyMap<QString, MyMoneyPayee> m_payeeList;
+
+ /**
+ * A list containing all the scheduled transactions
+ */
+ MyMoneyMap<QString, MyMoneySchedule> m_scheduleList;
+
+ /**
+ * A list containing all the security information objects. Each object
+ * can represent a stock, bond, or mutual fund. It contains a price
+ * history that a user can add entries to. The price history will be used
+ * to determine the cost basis for sales, as well as the source of
+ * information for reports in a security account.
+ */
+ MyMoneyMap<QString, MyMoneySecurity> m_securitiesList;
+
+ /**
+ * A list containing all the currency information objects.
+ */
+ MyMoneyMap<QString, MyMoneySecurity> m_currencyList;
+
+ MyMoneyMap<QString, MyMoneyReport> m_reportList;
+
+ /**
+ * A list containing all the budget information objects.
+ */
+ MyMoneyMap<QString, MyMoneyBudget> m_budgetList;
+
+ MyMoneyMap<MyMoneySecurityPair, MyMoneyPriceEntries> m_priceList;
+
+ /**
+ * This member signals if the file has been modified or not
+ */
+ bool m_dirty;
+
+ /**
+ * This member variable keeps the creation date of this MyMoneySeqAccessMgr
+ * object. It is set during the constructor and can only be modified using
+ * the stream read operator.
+ */
+ QDate m_creationDate;
+
+ /**
+ * This member variable keeps the date of the last modification of
+ * the MyMoneySeqAccessMgr object.
+ */
+ QDate m_lastModificationDate;
+
+ /**
+ * This member variable contains the current fix level of application
+ * data files. (see kmymoneyview.cpp)
+ */
+ unsigned int m_currentFixVersion;
+ /**
+ * This member variable contains the current fix level of the
+ * presently open data file. (see kmymoneyview.cpp)
+ */
+ unsigned int m_fileFixVersion;
+ /**
+ * This method is used to get the next valid ID for a institution
+ * @return id for a institution
+ */
+ QString nextInstitutionID(void);
+
+ /**
+ * This method is used to get the next valid ID for an account
+ * @return id for an account
+ */
+ QString nextAccountID(void);
+
+ /**
+ * This method is used to get the next valid ID for a transaction
+ * @return id for a transaction
+ */
+ QString nextTransactionID(void);
+
+ /**
+ * This method is used to get the next valid ID for a payee
+ * @return id for a payee
+ */
+ QString nextPayeeID(void);
+
+ /**
+ * This method is used to get the next valid ID for a scheduled transaction
+ * @return id for a scheduled transaction
+ */
+ QString nextScheduleID(void);
+
+ /**
+ * This method is used to get the next valid ID for an security object.
+ * @return id for an security object
+ */
+ QString nextSecurityID(void);
+
+ QString nextReportID(void);
+
+ /**
+ * This method is used to get the next valid ID for a budget object.
+ * @return id for an budget object
+ */
+ QString nextBudgetID(void);
+
+
+ /**
+ * This method re-parents an existing account
+ *
+ * An exception will be thrown upon error conditions.
+ *
+ * @param account MyMoneyAccount reference to account to be re-parented
+ * @param parent MyMoneyAccount reference to new parent account
+ * @param sendNotification if true, notifications with the ids
+ * of all modified objects are send
+ */
+ void reparentAccount(MyMoneyAccount &account, MyMoneyAccount& parent, const bool sendNotification);
+ /**
+ * This method will close a database and log the use roff
+ */
+ void close(void) {}
+
+ /**
+ * This member variable is set when all transactions have been read from the database.
+ * This is would be probably the case when doing, for e.g., a full report,
+ * or after some types of transaction search which cannot be easily implemented in SQL
+ */
+ bool m_transactionListFull;
+};
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.cpp b/kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.cpp
new file mode 100644
index 0000000..09bf791
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.cpp
@@ -0,0 +1,1705 @@
+/***************************************************************************
+ mymoneyseqaccessmgrtest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyseqaccessmgrtest.h"
+#include <iostream>
+
+MyMoneySeqAccessMgrTest::MyMoneySeqAccessMgrTest()
+{
+}
+
+
+void MyMoneySeqAccessMgrTest::setUp()
+{
+ m = new MyMoneySeqAccessMgr;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ file->attachStorage(m);
+ m->startTransaction();
+}
+
+void MyMoneySeqAccessMgrTest::tearDown()
+{
+ m->commitTransaction();
+ MyMoneyFile* file = MyMoneyFile::instance();
+ file->detachStorage(m);
+ delete m;
+}
+
+void MyMoneySeqAccessMgrTest::testEmptyConstructor()
+{
+ MyMoneyPayee user = m->user();
+
+ CPPUNIT_ASSERT(user.name().isEmpty());
+ CPPUNIT_ASSERT(user.address().isEmpty());
+ CPPUNIT_ASSERT(user.city().isEmpty());
+ CPPUNIT_ASSERT(user.state().isEmpty());
+ CPPUNIT_ASSERT(user.postcode().isEmpty());
+ CPPUNIT_ASSERT(user.telephone().isEmpty());
+ CPPUNIT_ASSERT(user.email().isEmpty());
+ CPPUNIT_ASSERT(m->m_nextInstitutionID == 0);
+ CPPUNIT_ASSERT(m->m_nextAccountID == 0);
+ CPPUNIT_ASSERT(m->m_nextTransactionID == 0);
+ CPPUNIT_ASSERT(m->m_nextPayeeID == 0);
+ CPPUNIT_ASSERT(m->m_nextScheduleID == 0);
+ CPPUNIT_ASSERT(m->m_nextReportID == 0);
+ CPPUNIT_ASSERT(m->m_institutionList.count() == 0);
+ CPPUNIT_ASSERT(m->m_accountList.count() == 5);
+ CPPUNIT_ASSERT(m->m_transactionList.count() == 0);
+ CPPUNIT_ASSERT(m->m_transactionKeys.count() == 0);
+ CPPUNIT_ASSERT(m->m_payeeList.count() == 0);
+ CPPUNIT_ASSERT(m->m_scheduleList.count() == 0);
+
+ CPPUNIT_ASSERT(m->m_dirty == false);
+ CPPUNIT_ASSERT(m->m_creationDate == QDate::currentDate());
+
+ CPPUNIT_ASSERT(m->liability().name() == "Liability");
+ CPPUNIT_ASSERT(m->asset().name() == "Asset");
+ CPPUNIT_ASSERT(m->expense().name() == "Expense");
+ CPPUNIT_ASSERT(m->income().name() == "Income");
+ CPPUNIT_ASSERT(m->equity().name() == "Equity");
+}
+
+void MyMoneySeqAccessMgrTest::testSetFunctions() {
+ MyMoneyPayee user = m->user();
+
+ m->m_dirty = false;
+ user.setName("Name");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ user.setAddress("Street");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ user.setCity("Town");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ user.setState("County");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ user.setPostcode("Postcode");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ user.setTelephone("Telephone");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ user.setEmail("Email");
+ m->setUser(user);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ m->m_dirty = false;
+ m->setValue("key", "value");
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+
+ user = m->user();
+ CPPUNIT_ASSERT(user.name() == "Name");
+ CPPUNIT_ASSERT(user.address() == "Street");
+ CPPUNIT_ASSERT(user.city() == "Town");
+ CPPUNIT_ASSERT(user.state() == "County");
+ CPPUNIT_ASSERT(user.postcode() == "Postcode");
+ CPPUNIT_ASSERT(user.telephone() == "Telephone");
+ CPPUNIT_ASSERT(user.email() == "Email");
+ CPPUNIT_ASSERT(m->value("key") == "value");
+
+ m->m_dirty = false;
+ m->deletePair("key");
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+}
+
+void MyMoneySeqAccessMgrTest::testSupportFunctions()
+{
+ CPPUNIT_ASSERT(m->nextInstitutionID() == "I000001");
+ CPPUNIT_ASSERT(m->m_nextInstitutionID == 1);
+ CPPUNIT_ASSERT(m->nextAccountID() == "A000001");
+ CPPUNIT_ASSERT(m->m_nextAccountID == 1);
+ CPPUNIT_ASSERT(m->nextTransactionID() == "T000000000000000001");
+ CPPUNIT_ASSERT(m->m_nextTransactionID == 1);
+ CPPUNIT_ASSERT(m->nextPayeeID() == "P000001");
+ CPPUNIT_ASSERT(m->m_nextPayeeID == 1);
+ CPPUNIT_ASSERT(m->nextScheduleID() == "SCH000001");
+ CPPUNIT_ASSERT(m->m_nextScheduleID == 1);
+ CPPUNIT_ASSERT(m->nextReportID() == "R000001");
+ CPPUNIT_ASSERT(m->m_nextReportID == 1);
+}
+
+void MyMoneySeqAccessMgrTest::testIsStandardAccount()
+{
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_LIABILITY) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_ASSET) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_EXPENSE) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount(STD_ACC_INCOME) == true);
+ CPPUNIT_ASSERT(m->isStandardAccount("A0002") == false);
+}
+
+void MyMoneySeqAccessMgrTest::testNewAccount() {
+ MyMoneyAccount a;
+
+ a.setName("AccountName");
+ a.setNumber("AccountNumber");
+
+ m->addAccount(a);
+ m->commitTransaction();
+ m->startTransaction();
+
+ CPPUNIT_ASSERT(m->m_nextAccountID == 1);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->m_accountList.count() == 6);
+ CPPUNIT_ASSERT(m->m_accountList["A000001"].name() == "AccountName");
+}
+
+void MyMoneySeqAccessMgrTest::testAccount() {
+ testNewAccount();
+ m->m_dirty = false;
+
+ MyMoneyAccount a;
+
+ // make sure that an invalid ID causes an exception
+ try {
+ a = m->account("Unknown ID");
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == false);
+
+ // now make sure, that a real ID works
+ try {
+ a = m->account("A000001");
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(a.name() == "AccountName");
+ CPPUNIT_ASSERT(a.id() == "A000001");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testAddNewAccount() {
+ testNewAccount();
+
+ MyMoneyAccount a,b;
+ b.setName("Account2");
+ b.setNumber("Acc2");
+ m->addAccount(b);
+ m->commitTransaction();
+ m->startTransaction();
+
+ m->m_dirty = false;
+
+ CPPUNIT_ASSERT(m->m_nextAccountID == 2);
+ CPPUNIT_ASSERT(m->m_accountList.count() == 7);
+
+ // try to add account to undefined account
+ try {
+ MyMoneyAccount c("UnknownID", b);
+ m->addAccount(c, a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ m->commitTransaction();
+ m->startTransaction();
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+ // now try to add account 1 as sub-account to account 2
+ a = m->account("A000001");
+ try {
+ CPPUNIT_ASSERT(m->m_accountList[STD_ACC_ASSET].accountList().count() == 0);
+ m->addAccount(b, a);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->m_accountList["A000002"].accountList()[0] == "A000001");
+ CPPUNIT_ASSERT(m->m_accountList["A000002"].accountList().count() == 1);
+ CPPUNIT_ASSERT(m->m_accountList[STD_ACC_ASSET].accountList().count() == 0);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testAddInstitution() {
+ MyMoneyInstitution i;
+
+ i.setName("Inst Name");
+
+ m->addInstitution(i);
+ CPPUNIT_ASSERT(m->m_institutionList.count() == 1);
+ CPPUNIT_ASSERT(m->m_nextInstitutionID == 1);
+ CPPUNIT_ASSERT(m->m_institutionList["I000001"].name() == "Inst Name");
+}
+
+void MyMoneySeqAccessMgrTest::testInstitution() {
+ testAddInstitution();
+ MyMoneyInstitution i;
+
+ m->m_dirty = false;
+
+ // try to find unknown institution
+ try {
+ i = m->institution("Unknown ID");
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+
+ // now try to find real institution
+ try {
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.name() == "Inst Name");
+ CPPUNIT_ASSERT(m->dirty() == false);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testAccount2Institution() {
+ testAddInstitution();
+ testAddNewAccount();
+
+ MyMoneyInstitution i;
+ MyMoneyAccount a, b;
+
+ try {
+ i = m->institution("I000001");
+ a = m->account("A000001");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->m_dirty = false;
+
+ // try to add to a false institution
+ MyMoneyInstitution fake("Unknown ID", i);
+ a.setInstitutionId(fake.id());
+ try {
+ m->modifyAccount(a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ m->commitTransaction();
+ m->startTransaction();
+
+ CPPUNIT_ASSERT(m->dirty() == false);
+ // now try to do it with a real institution
+ try {
+ CPPUNIT_ASSERT(i.accountList().count() == 0);
+ a.setInstitutionId(i.id());
+ m->modifyAccount(a);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(a.institutionId() == i.id());
+ b = m->account("A000001");
+ CPPUNIT_ASSERT(b.institutionId() == i.id());
+ CPPUNIT_ASSERT(i.accountList().count() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testModifyAccount() {
+ testAccount2Institution();
+
+ // test the OK case
+ MyMoneyAccount a = m->account("A000001");
+ a.setName("New account name");
+ m->m_dirty = false;
+ try {
+ m->modifyAccount(a);
+ m->commitTransaction();
+ m->startTransaction();
+ MyMoneyAccount b = m->account("A000001");
+ CPPUNIT_ASSERT(b.parentAccountId() == a.parentAccountId());
+ CPPUNIT_ASSERT(b.name() == "New account name");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // modify institution to unknown id
+ MyMoneyAccount c("Unknown ID", a);
+ m->m_dirty = false;
+ try {
+ m->modifyAccount(c);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // use different account type
+ MyMoneyAccount d;
+ d.setAccountType(MyMoneyAccount::CreditCard);
+ MyMoneyAccount f("A000001", d);
+ try {
+ m->modifyAccount(f);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // use different parent
+ a.setParentAccountId("A000002");
+ try {
+ m->modifyAccount(c);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testModifyInstitution() {
+ testAddInstitution();
+ MyMoneyInstitution i = m->institution("I000001");
+
+ m->m_dirty = false;
+ i.setName("New inst name");
+ try {
+ m->modifyInstitution(i);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.name() == "New inst name");
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // try to modify an institution that does not exist
+ MyMoneyInstitution f("Unknown ID", i);
+ try {
+ m->modifyInstitution(f);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testReparentAccount() {
+ // this one adds some accounts to the database
+ MyMoneyAccount ex1;
+ ex1.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount ex2;
+ ex2.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount ex3;
+ ex3.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount ex4;
+ ex4.setAccountType(MyMoneyAccount::Expense);
+ MyMoneyAccount in;
+ in.setAccountType(MyMoneyAccount::Income);
+ MyMoneyAccount ch;
+ ch.setAccountType(MyMoneyAccount::Checkings);
+
+ ex1.setName("Sales Tax");
+ ex2.setName("Sales Tax 16%");
+ ex3.setName("Sales Tax 7%");
+ ex4.setName("Grosseries");
+
+ in.setName("Salary");
+ ch.setName("My checkings account");
+
+ try {
+ m->addAccount(ex1);
+ m->addAccount(ex2);
+ m->addAccount(ex3);
+ m->addAccount(ex4);
+ m->addAccount(in);
+ m->addAccount(ch);
+
+ CPPUNIT_ASSERT(ex1.id() == "A000001");
+ CPPUNIT_ASSERT(ex2.id() == "A000002");
+ CPPUNIT_ASSERT(ex3.id() == "A000003");
+ CPPUNIT_ASSERT(ex4.id() == "A000004");
+ CPPUNIT_ASSERT(in.id() == "A000005");
+ CPPUNIT_ASSERT(ch.id() == "A000006");
+
+ MyMoneyAccount parent = m->expense();
+
+ m->addAccount(parent, ex1);
+ m->addAccount(ex1, ex2);
+ m->addAccount(parent, ex3);
+ m->addAccount(parent, ex4);
+
+ parent = m->income();
+ m->addAccount(parent, in);
+
+ parent = m->asset();
+ m->addAccount(parent, ch);
+
+ CPPUNIT_ASSERT(m->expense().accountCount() == 3);
+ CPPUNIT_ASSERT(m->account(ex1.id()).accountCount() == 1);
+ CPPUNIT_ASSERT(ex3.parentAccountId() == STD_ACC_EXPENSE);
+
+ m->reparentAccount(ex3, ex1);
+ CPPUNIT_ASSERT(m->expense().accountCount() == 2);
+ CPPUNIT_ASSERT(m->account(ex1.id()).accountCount() == 2);
+ CPPUNIT_ASSERT(ex3.parentAccountId() == ex1.id());
+ } catch (MyMoneyException *e) {
+ std::cout << std::endl << e->what() << std::endl;
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testAddTransactions() {
+ testReparentAccount();
+
+ MyMoneyAccount ch;
+ MyMoneyTransaction t1, t2;
+ MyMoneySplit s;
+
+ try {
+ // I made some money, great
+ s.setAccountId("A000006"); // Checkings
+ s.setShares(100000);
+ s.setValue(100000);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t1.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000005"); // Salary
+ s.setShares(-100000);
+ s.setValue(-100000);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t1.addSplit(s);
+
+ t1.setPostDate(QDate(2002,5,10));
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ m->m_dirty = false;
+ try {
+ m->addTransaction(t1);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(t1.id() == "T000000000000000001");
+ CPPUNIT_ASSERT(t1.splitCount() == 2);
+ CPPUNIT_ASSERT(m->transactionCount() == 1);
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ try {
+ // I spent some money, not so great
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000004"); // Grosseries
+ s.setShares(10000);
+ s.setValue(10000);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000002"); // 16% sales tax
+ s.setShares(1200);
+ s.setValue(1200);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000003"); // 7% sales tax
+ s.setShares(400);
+ s.setValue(400);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ s.setId(QString()); // enable re-usage of split variable
+ s.setAccountId("A000006"); // Checkings account
+ s.setShares(-11600);
+ s.setValue(-11600);
+ CPPUNIT_ASSERT(s.id().isEmpty());
+ t2.addSplit(s);
+
+ t2.setPostDate(QDate(2002,5,9));
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+ m->m_dirty = false;
+ try {
+ m->addTransaction(t2);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(t2.id() == "T000000000000000002");
+ CPPUNIT_ASSERT(t2.splitCount() == 4);
+ CPPUNIT_ASSERT(m->transactionCount() == 2);
+
+ QMap<QString, QString>::ConstIterator it_k;
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ it_k = m->m_transactionKeys.begin();
+ it_t = m->m_transactionList.begin();
+
+ CPPUNIT_ASSERT((*it_k) == "2002-05-10-T000000000000000001");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000002");
+ ++it_k;
+ ++it_t;
+ CPPUNIT_ASSERT((*it_k) == "2002-05-09-T000000000000000002");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000001");
+ ++it_k;
+ ++it_t;
+ CPPUNIT_ASSERT(it_k == m->m_transactionKeys.end());
+ CPPUNIT_ASSERT(it_t == m->m_transactionList.end());
+
+ ch = m->account("A000006");
+
+ // check that the account's transaction list is updated
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyTransactionFilter filter("A000006");
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.size() == 2);
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ it = list.begin();
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000002");
+ ++it;
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000001");
+ ++it;
+ CPPUNIT_ASSERT(it == list.end());
+
+/* removed with MyMoneyAccount::Transaction
+ CPPUNIT_ASSERT(ch.transactionCount() == 2);
+
+ QValueList<MyMoneyAccount::Transaction>::ConstIterator it_l;
+ it_l = ch.transactionList().begin();
+ CPPUNIT_ASSERT((*it_l).transactionID() == "T000000000000000002");
+ CPPUNIT_ASSERT((*it_l).balance() == -11600);
+ ++it_l;
+
+ CPPUNIT_ASSERT((*it_l).transactionID() == "T000000000000000001");
+ CPPUNIT_ASSERT((*it_l).balance() == -11600+100000);
+
+ ++it_l;
+ CPPUNIT_ASSERT(it_l == ch.transactionList().end());
+*/
+
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testTransactionCount() {
+ testAddTransactions();
+ CPPUNIT_ASSERT(m->transactionCount("A000001") == 0);
+ CPPUNIT_ASSERT(m->transactionCount("A000002") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000003") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000004") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000005") == 1);
+ CPPUNIT_ASSERT(m->transactionCount("A000006") == 2);
+}
+
+void MyMoneySeqAccessMgrTest::testBalance() {
+ testAddTransactions();
+
+ CPPUNIT_ASSERT(m->balance("A000001").isZero());
+ CPPUNIT_ASSERT(m->balance("A000002") == MyMoneyMoney(1200));
+ CPPUNIT_ASSERT(m->balance("A000003") == MyMoneyMoney(400));
+ CPPUNIT_ASSERT(m->totalBalance("A000001") == MyMoneyMoney(1600));
+ CPPUNIT_ASSERT(m->balance("A000006", QDate(2002,5,9)) == MyMoneyMoney(-11600));
+ CPPUNIT_ASSERT(m->balance("A000005", QDate(2002,5,10)) == MyMoneyMoney(-100000));
+ CPPUNIT_ASSERT(m->balance("A000006", QDate(2002,5,10)) == MyMoneyMoney(88400));
+}
+
+void MyMoneySeqAccessMgrTest::testModifyTransaction() {
+ testAddTransactions();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000002");
+ MyMoneySplit s;
+ MyMoneyAccount ch;
+
+ // just modify simple stuff (splits)
+ CPPUNIT_ASSERT(t.splitCount() == 4);
+
+ s = t.splits()[0];
+ s.setShares(11000);
+ s.setValue(11000);
+ t.modifySplit(s);
+
+ CPPUNIT_ASSERT(t.splitCount() == 4);
+ s = t.splits()[3];
+ s.setShares(-12600);
+ s.setValue(-12600);
+ t.modifySplit(s);
+
+ try {
+ CPPUNIT_ASSERT(m->balance("A000004") == MyMoneyMoney(10000));
+ CPPUNIT_ASSERT(m->balance("A000006") == MyMoneyMoney(100000-11600));
+ CPPUNIT_ASSERT(m->totalBalance("A000001") == MyMoneyMoney(1600));
+ m->modifyTransaction(t);
+ CPPUNIT_ASSERT(m->balance("A000004") == MyMoneyMoney(11000));
+ CPPUNIT_ASSERT(m->balance("A000006") == MyMoneyMoney(100000-12600));
+ CPPUNIT_ASSERT(m->totalBalance("A000001") == MyMoneyMoney(1600));
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // now modify the date
+ t.setPostDate(QDate(2002,5,11));
+ try {
+ m->modifyTransaction(t);
+ CPPUNIT_ASSERT(m->balance("A000004") == MyMoneyMoney(11000));
+ CPPUNIT_ASSERT(m->balance("A000006") == MyMoneyMoney(100000-12600));
+ CPPUNIT_ASSERT(m->totalBalance("A000001") == MyMoneyMoney(1600));
+
+ QMap<QString, QString>::ConstIterator it_k;
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ it_k = m->m_transactionKeys.begin();
+ it_t = m->m_transactionList.begin();
+ CPPUNIT_ASSERT((*it_k) == "2002-05-10-T000000000000000001");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000001");
+ ++it_k;
+ ++it_t;
+ CPPUNIT_ASSERT((*it_k) == "2002-05-11-T000000000000000002");
+ CPPUNIT_ASSERT((*it_t).id() == "T000000000000000002");
+ ++it_k;
+ ++it_t;
+ CPPUNIT_ASSERT(it_k == m->m_transactionKeys.end());
+ CPPUNIT_ASSERT(it_t == m->m_transactionList.end());
+
+ ch = m->account("A000006");
+
+ // check that the account's transaction list is updated
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyTransactionFilter filter("A000006");
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.size() == 2);
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ it = list.begin();
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000001");
+ ++it;
+ CPPUNIT_ASSERT((*it).id() == "T000000000000000002");
+ ++it;
+ CPPUNIT_ASSERT(it == list.end());
+
+/* removed with MyMoneyAccount::Transaction
+ // CPPUNIT_ASSERT(ch.transactionCount() == 2);
+
+ QValueList<MyMoneyAccount::Transaction>::ConstIterator it_l;
+ it_l = ch.transactionList().begin();
+ CPPUNIT_ASSERT((*it_l).transactionID() == "T000000000000000001");
+ CPPUNIT_ASSERT((*it_l).balance() == 100000);
+ ++it_l;
+
+ CPPUNIT_ASSERT((*it_l).transactionID() == "T000000000000000002");
+ CPPUNIT_ASSERT((*it_l).balance() == -12600+100000);
+
+ ++it_l;
+ CPPUNIT_ASSERT(it_l == ch.transactionList().end());
+*/
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+
+void MyMoneySeqAccessMgrTest::testRemoveUnusedAccount() {
+ testAccount2Institution();
+
+ MyMoneyAccount a = m->account("A000001");
+ MyMoneyInstitution i = m->institution("I000001");
+
+ m->m_dirty = false;
+ // make sure, we cannot remove the standard account groups
+ try {
+ m->removeAccount(m->liability());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->removeAccount(m->asset());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->removeAccount(m->expense());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ try {
+ m->removeAccount(m->income());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // try to remove the account still attached to the institution
+ try {
+ m->removeAccount(a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ // now really remove an account
+
+ try {
+ CPPUNIT_ASSERT(i.accountCount() == 0);
+ CPPUNIT_ASSERT(m->accountCount() == 7);
+
+ a.setInstitutionId(QString());
+ m->modifyAccount(a);
+ m->removeAccount(a);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->accountCount() == 6);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ i = m->institution("I000001");
+ CPPUNIT_ASSERT(i.accountCount() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testRemoveUsedAccount() {
+ testAddTransactions();
+
+ MyMoneyAccount a = m->account("A000006");
+
+ try {
+ m->removeAccount(a);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testRemoveInstitution() {
+ testModifyInstitution();
+ testReparentAccount();
+
+ MyMoneyInstitution i;
+ MyMoneyAccount a;
+
+ // assign the checkings account to the institution
+ try {
+ i = m->institution("I000001");
+ a = m->account("A000006");
+ a.setInstitutionId(i.id());
+ m->modifyAccount(a);
+ CPPUNIT_ASSERT(i.accountCount() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->m_dirty = false;
+ // now remove the institution and see if the account survived ;-)
+ try {
+ m->removeInstitution(i);
+ a.setInstitutionId(QString());
+ m->modifyAccount(a);
+ m->commitTransaction();
+ m->startTransaction();
+ a = m->account("A000006");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(a.institutionId().isEmpty());
+ CPPUNIT_ASSERT(m->institutionCount() == 0);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testRemoveTransaction() {
+ testAddTransactions();
+
+ MyMoneyTransaction t = m->transaction("T000000000000000002");
+
+ m->m_dirty = false;
+ try {
+ m->removeTransaction(t);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->transactionCount() == 1);
+/* removed with MyMoneyAccount::Transaction
+ CPPUNIT_ASSERT(m->account("A000006").transactionCount() == 1);
+*/
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testTransactionList() {
+ testAddTransactions();
+
+ QValueList<MyMoneyTransaction> list;
+ MyMoneyTransactionFilter filter("A000006");
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT((*(list.at(0))).id() == "T000000000000000002");
+ CPPUNIT_ASSERT((*(list.at(1))).id() == "T000000000000000001");
+
+ filter.clear();
+ filter.addAccount(QString("A000003"));
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT((*(list.at(0))).id() == "T000000000000000002");
+
+ filter.clear();
+ list = m->transactionList(filter);
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT((*(list.at(0))).id() == "T000000000000000002");
+ CPPUNIT_ASSERT((*(list.at(1))).id() == "T000000000000000001");
+}
+
+void MyMoneySeqAccessMgrTest::testAddPayee() {
+ MyMoneyPayee p;
+
+ p.setName("THB");
+ m->m_dirty = false;
+ try {
+ CPPUNIT_ASSERT(m->m_nextPayeeID == 0);
+ m->addPayee(p);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == true);
+ CPPUNIT_ASSERT(m->m_nextPayeeID == 1);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+}
+
+void MyMoneySeqAccessMgrTest::testSetAccountName() {
+ try {
+ m->setAccountName(STD_ACC_LIABILITY, "Verbindlichkeiten");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ m->setAccountName(STD_ACC_ASSET, "Verm�gen");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ m->setAccountName(STD_ACC_EXPENSE, "Ausgaben");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ m->setAccountName(STD_ACC_INCOME, "Einnahmen");
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ CPPUNIT_ASSERT(m->liability().name() == "Verbindlichkeiten");
+ CPPUNIT_ASSERT(m->asset().name() == "Verm�gen");
+ CPPUNIT_ASSERT(m->expense().name() == "Ausgaben");
+ CPPUNIT_ASSERT(m->income().name() == "Einnahmen");
+
+ try {
+ m->setAccountName("A000001", "New account name");
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testModifyPayee() {
+ MyMoneyPayee p;
+
+ testAddPayee();
+
+ p = m->payee("P000001");
+ p.setName("New name");
+ m->m_dirty = false;
+ try {
+ m->modifyPayee(p);
+ m->commitTransaction();
+ m->startTransaction();
+ p = m->payee("P000001");
+ CPPUNIT_ASSERT(p.name() == "New name");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testRemovePayee() {
+ testAddPayee();
+ m->m_dirty = false;
+
+ // check that we can remove an unreferenced payee
+ MyMoneyPayee p = m->payee("P000001");
+ try {
+ CPPUNIT_ASSERT(m->m_payeeList.count() == 1);
+ m->removePayee(p);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->m_payeeList.count() == 0);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ // add transaction
+ testAddTransactions();
+
+ MyMoneyTransaction tr = m->transaction("T000000000000000001");
+ MyMoneySplit sp;
+ sp = tr.splits()[0];
+ sp.setPayeeId("P000001");
+ tr.modifySplit(sp);
+
+ // check that we cannot add a transaction referencing
+ // an unknown payee
+ try {
+ m->modifyTransaction(tr);
+ CPPUNIT_FAIL("Expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+
+ m->m_nextPayeeID = 0; // reset here, so that the
+ // testAddPayee will not fail
+ testAddPayee();
+
+ // check that it works when the payee exists
+ try {
+ m->modifyTransaction(tr);
+ } catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->m_dirty = false;
+
+ // now check, that we cannot remove the payee
+ try {
+ m->removePayee(p);
+ CPPUNIT_FAIL("Expected exception");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ CPPUNIT_ASSERT(m->m_payeeList.count() == 1);
+}
+
+
+void MyMoneySeqAccessMgrTest::testRemoveAccountFromTree() {
+ MyMoneyAccount a, b, c;
+ a.setName("Acc A");
+ b.setName("Acc B");
+ c.setName("Acc C");
+
+ // build a tree A -> B -> C, remove B and see if A -> C
+ // remains in the storag manager
+
+ try {
+ m->addAccount(a);
+ m->addAccount(b);
+ m->addAccount(c);
+ m->reparentAccount(b, a);
+ m->reparentAccount(c, b);
+
+ CPPUNIT_ASSERT(a.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->account(a.accountList()[0]).name() == "Acc B");
+
+ CPPUNIT_ASSERT(b.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->account(b.accountList()[0]).name() == "Acc C");
+
+ CPPUNIT_ASSERT(c.accountList().count() == 0);
+
+ m->removeAccount(b);
+
+ // reload account info from titutionIDtorage
+ a = m->account(a.id());
+ c = m->account(c.id());
+
+ try {
+ b = m->account(b.id());
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ CPPUNIT_ASSERT(a.accountList().count() == 1);
+ CPPUNIT_ASSERT(m->account(a.accountList()[0]).name() == "Acc C");
+
+ CPPUNIT_ASSERT(c.accountList().count() == 0);
+
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testPayeeName() {
+ testAddPayee();
+
+ MyMoneyPayee p;
+ QString name("THB");
+
+ // OK case
+ try {
+ p = m->payeeByName(name);
+ CPPUNIT_ASSERT(p.name() == "THB");
+ CPPUNIT_ASSERT(p.id() == "P000001");
+ } catch (MyMoneyException *e) {
+ unexpectedException(e);
+ }
+
+ // Not OK case
+ name = "Thb";
+ try {
+ p = m->payeeByName(name);
+ CPPUNIT_FAIL("Exception expected");
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testAssignment() {
+ testAddTransactions();
+
+ MyMoneyPayee user;
+ user.setName("Thomas");
+ m->setUser(user);
+
+ MyMoneySeqAccessMgr test = *m;
+ testEquality(&test);
+}
+
+void MyMoneySeqAccessMgrTest::testEquality(const MyMoneySeqAccessMgr *t)
+{
+ CPPUNIT_ASSERT(m->user().name() == t->user().name());
+ CPPUNIT_ASSERT(m->user().address() == t->user().address());
+ CPPUNIT_ASSERT(m->user().city() == t->user().city());
+ CPPUNIT_ASSERT(m->user().state() == t->user().state());
+ CPPUNIT_ASSERT(m->user().postcode() == t->user().postcode());
+ CPPUNIT_ASSERT(m->user().telephone() == t->user().telephone());
+ CPPUNIT_ASSERT(m->user().email() == t->user().email());
+ CPPUNIT_ASSERT(m->m_nextInstitutionID == t->m_nextInstitutionID);
+ CPPUNIT_ASSERT(m->m_nextAccountID == t->m_nextAccountID);
+ CPPUNIT_ASSERT(m->m_nextTransactionID == t->m_nextTransactionID);
+ CPPUNIT_ASSERT(m->m_nextPayeeID == t->m_nextPayeeID);
+ CPPUNIT_ASSERT(m->m_nextScheduleID == t->m_nextScheduleID);
+ CPPUNIT_ASSERT(m->m_dirty == t->m_dirty);
+ CPPUNIT_ASSERT(m->m_creationDate == t->m_creationDate);
+ CPPUNIT_ASSERT(m->m_lastModificationDate == t->m_lastModificationDate);
+
+ /*
+ * make sure, that the keys and values are the same
+ * on the left and the right side
+ */
+ CPPUNIT_ASSERT(m->m_payeeList.keys() == t->m_payeeList.keys());
+ CPPUNIT_ASSERT(m->m_payeeList.values() == t->m_payeeList.values());
+ CPPUNIT_ASSERT(m->m_transactionKeys.keys() == t->m_transactionKeys.keys());
+ CPPUNIT_ASSERT(m->m_transactionKeys.values() == t->m_transactionKeys.values());
+ CPPUNIT_ASSERT(m->m_institutionList.keys() == t->m_institutionList.keys());
+ CPPUNIT_ASSERT(m->m_institutionList.values() == t->m_institutionList.values());
+ CPPUNIT_ASSERT(m->m_accountList.keys() == t->m_accountList.keys());
+ CPPUNIT_ASSERT(m->m_accountList.values() == t->m_accountList.values());
+ CPPUNIT_ASSERT(m->m_transactionList.keys() == t->m_transactionList.keys());
+ CPPUNIT_ASSERT(m->m_transactionList.values() == t->m_transactionList.values());
+ CPPUNIT_ASSERT(m->m_balanceCache.keys() == t->m_balanceCache.keys());
+ CPPUNIT_ASSERT(m->m_balanceCache.values() == t->m_balanceCache.values());
+
+// CPPUNIT_ASSERT(m->m_scheduleList.keys() == t->m_scheduleList.keys());
+// CPPUNIT_ASSERT(m->m_scheduleList.values() == t->m_scheduleList.values());
+}
+
+void MyMoneySeqAccessMgrTest::testDuplicate() {
+ const MyMoneySeqAccessMgr* t;
+
+ testModifyTransaction();
+
+ t = m->duplicate();
+ testEquality(t);
+ delete t;
+}
+
+void MyMoneySeqAccessMgrTest::testAddSchedule() {
+ /* Note addSchedule() now calls validate as it should
+ * so we need an account id. Later this will
+ * be checked to make sure its a valid account id. The
+ * tests currently fail because no splits are defined
+ * for the schedules transaction.
+ */
+
+
+ try {
+ CPPUNIT_ASSERT(m->m_scheduleList.count() == 0);
+ MyMoneyTransaction t1;
+ MyMoneySplit s1, s2;
+ s1.setAccountId("A000001");
+ t1.addSplit(s1);
+ s2.setAccountId("A000002");
+ t1.addSplit(s2);
+ MyMoneySchedule schedule("Sched-Name",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_DAILY, 1,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ QDate(),
+ QDate(),
+ true,
+ false);
+ t1.setPostDate(QDate(2003,7,10));
+ schedule.setTransaction(t1);
+
+ m->addSchedule(schedule);
+
+ CPPUNIT_ASSERT(m->m_scheduleList.count() == 1);
+ CPPUNIT_ASSERT(schedule.id() == "SCH000001");
+ CPPUNIT_ASSERT(m->m_scheduleList["SCH000001"].id() == "SCH000001");
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ try {
+ MyMoneySchedule schedule("Sched-Name",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_DAILY, 1,
+ MyMoneySchedule::STYPE_MANUALDEPOSIT,
+ QDate(),
+ QDate(),
+ true,
+ false);
+ m->addSchedule(schedule);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testSchedule() {
+ testAddSchedule();
+ MyMoneySchedule sched;
+
+ sched = m->schedule("SCH000001");
+ CPPUNIT_ASSERT(sched.name() == "Sched-Name");
+ CPPUNIT_ASSERT(sched.id() == "SCH000001");
+
+ try {
+ m->schedule("SCH000002");
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testModifySchedule() {
+ testAddSchedule();
+ MyMoneySchedule sched;
+
+ sched = m->schedule("SCH000001");
+ sched.setId("SCH000002");
+ try {
+ m->modifySchedule(sched);
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ sched = m->schedule("SCH000001");
+ sched.setName("New Sched-Name");
+ try {
+ m->modifySchedule(sched);
+ CPPUNIT_ASSERT(m->m_scheduleList.count() == 1);
+ CPPUNIT_ASSERT(m->m_scheduleList["SCH000001"].name() == "New Sched-Name");
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+}
+
+void MyMoneySeqAccessMgrTest::testRemoveSchedule() {
+ testAddSchedule();
+ m->commitTransaction();
+ m->startTransaction();
+ MyMoneySchedule sched;
+
+ sched = m->schedule("SCH000001");
+ sched.setId("SCH000002");
+ try {
+ m->removeSchedule(sched);
+ m->commitTransaction();
+ CPPUNIT_FAIL("Exception expected");
+ } catch(MyMoneyException *e) {
+ m->rollbackTransaction();
+ delete e;
+ }
+ m->startTransaction();
+
+ sched = m->schedule("SCH000001");
+ try {
+ m->removeSchedule(sched);
+ m->commitTransaction();
+ CPPUNIT_ASSERT(m->m_scheduleList.count() == 0);
+
+ } catch(MyMoneyException *e) {
+ m->rollbackTransaction();
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ m->startTransaction();
+}
+
+void MyMoneySeqAccessMgrTest::testScheduleList() {
+ QDate testDate = QDate::currentDate();
+ QDate notOverdue = testDate.addDays(2);
+ QDate overdue = testDate.addDays(-2);
+
+
+ MyMoneyTransaction t1;
+ MyMoneySplit s1, s2;
+ s1.setAccountId("A000001");
+ t1.addSplit(s1);
+ s2.setAccountId("A000002");
+ t1.addSplit(s2);
+ MyMoneySchedule schedule1("Schedule 1",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_ONCE, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate(),
+ QDate(),
+ false,
+ false);
+ t1.setPostDate(notOverdue);
+ schedule1.setTransaction(t1);
+ schedule1.setLastPayment(notOverdue);
+
+ MyMoneyTransaction t2;
+ MyMoneySplit s3, s4;
+ s3.setAccountId("A000001");
+ t2.addSplit(s3);
+ s4.setAccountId("A000003");
+ t2.addSplit(s4);
+ MyMoneySchedule schedule2("Schedule 2",
+ MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_DAILY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEPOSIT,
+ QDate(),
+ QDate(),
+ false,
+ false);
+ t2.setPostDate(notOverdue.addDays(1));
+ schedule2.setTransaction(t2);
+ schedule2.setLastPayment(notOverdue.addDays(1));
+
+ MyMoneyTransaction t3;
+ MyMoneySplit s5, s6;
+ s5.setAccountId("A000005");
+ t3.addSplit(s5);
+ s6.setAccountId("A000006");
+ t3.addSplit(s6);
+ MyMoneySchedule schedule3("Schedule 3",
+ MyMoneySchedule::TYPE_TRANSFER,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_OTHER,
+ QDate(),
+ QDate(),
+ false,
+ false);
+ t3.setPostDate(notOverdue.addDays(2));
+ schedule3.setTransaction(t3);
+ schedule3.setLastPayment(notOverdue.addDays(2));
+
+ MyMoneyTransaction t4;
+ MyMoneySplit s7, s8;
+ s7.setAccountId("A000005");
+ t4.addSplit(s7);
+ s8.setAccountId("A000006");
+ t4.addSplit(s8);
+ MyMoneySchedule schedule4("Schedule 4",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_WRITECHEQUE,
+ QDate(),
+ notOverdue.addDays(31),
+ false,
+ false);
+ t4.setPostDate(overdue.addDays(-7));
+ schedule4.setTransaction(t4);
+
+ try {
+ m->addSchedule(schedule1);
+ m->addSchedule(schedule2);
+ m->addSchedule(schedule3);
+ m->addSchedule(schedule4);
+ } catch(MyMoneyException *e) {
+ qDebug("Error: %s", e->what().latin1());
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ QValueList<MyMoneySchedule> list;
+
+ // no filter
+ list = m->scheduleList();
+ CPPUNIT_ASSERT(list.count() == 4);
+
+ // filter by type
+ list = m->scheduleList("", MyMoneySchedule::TYPE_BILL);
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 1");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 4");
+
+ // filter by occurence
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_DAILY);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 2");
+
+ // filter by payment type
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_DIRECTDEPOSIT);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 2");
+
+ // filter by account
+ list = m->scheduleList("A01");
+ CPPUNIT_ASSERT(list.count() == 0);
+ list = m->scheduleList("A000001");
+ CPPUNIT_ASSERT(list.count() == 2);
+ list = m->scheduleList("A000002");
+ CPPUNIT_ASSERT(list.count() == 1);
+
+ // filter by start date
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ notOverdue.addDays(31));
+ CPPUNIT_ASSERT(list.count() == 3);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 2");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 3");
+ CPPUNIT_ASSERT(list[2].name() == "Schedule 4");
+
+ // filter by end date
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate(),
+ notOverdue.addDays(1));
+ CPPUNIT_ASSERT(list.count() == 3);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 1");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 2");
+ CPPUNIT_ASSERT(list[2].name() == "Schedule 4");
+
+ // filter by start and end date
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ notOverdue.addDays(-1),
+ notOverdue.addDays(1));
+ CPPUNIT_ASSERT(list.count() == 2);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 1");
+ CPPUNIT_ASSERT(list[1].name() == "Schedule 2");
+
+ // filter by overdue status
+ list = m->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate(),
+ QDate(),
+ true);
+ CPPUNIT_ASSERT(list.count() == 1);
+ CPPUNIT_ASSERT(list[0].name() == "Schedule 4");
+}
+
+void MyMoneySeqAccessMgrTest::testAddCurrency()
+{
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ CPPUNIT_ASSERT(m->m_currencyList.count() == 0);
+ m->m_dirty = false;
+ try {
+ m->addCurrency(curr);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->m_currencyList.count() == 1);
+ CPPUNIT_ASSERT(m->m_currencyList["EUR"].name() == "Euro");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->m_dirty = false;
+ try {
+ m->addCurrency(curr);
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testModifyCurrency()
+{
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ testAddCurrency();
+ m->m_dirty = false;
+ curr.setName("EURO");
+ try {
+ m->modifyCurrency(curr);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->m_currencyList.count() == 1);
+ CPPUNIT_ASSERT(m->m_currencyList["EUR"].name() == "EURO");
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->m_dirty = false;
+
+ MyMoneySecurity unknownCurr("DEM", "Deutsche Mark", "DM", 100, 100);
+ try {
+ m->modifyCurrency(unknownCurr);
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testRemoveCurrency()
+{
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ testAddCurrency();
+ m->m_dirty = false;
+ try {
+ m->removeCurrency(curr);
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->m_currencyList.count() == 0);
+ CPPUNIT_ASSERT(m->dirty() == true);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ m->m_dirty = false;
+
+ MyMoneySecurity unknownCurr("DEM", "Deutsche Mark", "DM", 100, 100);
+ try {
+ m->removeCurrency(unknownCurr);
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testCurrency()
+{
+ MyMoneySecurity curr("EUR", "Euro", "?", 100, 100);
+ MyMoneySecurity newCurr;
+ testAddCurrency();
+ m->m_dirty = false;
+ try {
+ newCurr = m->currency("EUR");
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ CPPUNIT_ASSERT(newCurr.id() == curr.id());
+ CPPUNIT_ASSERT(newCurr.name() == curr.name());
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ try {
+ m->currency("DEM");
+ CPPUNIT_FAIL("Expected exception missing");
+ } catch(MyMoneyException *e) {
+ m->commitTransaction();
+ m->startTransaction();
+ CPPUNIT_ASSERT(m->dirty() == false);
+ delete e;
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testCurrencyList()
+{
+ CPPUNIT_ASSERT(m->currencyList().count() == 0);
+
+ testAddCurrency();
+ CPPUNIT_ASSERT(m->currencyList().count() == 1);
+
+ MyMoneySecurity unknownCurr("DEM", "Deutsche Mark", "DM", 100, 100);
+ try {
+ m->addCurrency(unknownCurr);
+ m->m_dirty = false;
+ CPPUNIT_ASSERT(m->m_currencyList.count() == 2);
+ CPPUNIT_ASSERT(m->currencyList().count() == 2);
+ CPPUNIT_ASSERT(m->dirty() == false);
+ } catch(MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+}
+
+void MyMoneySeqAccessMgrTest::testAccountList()
+{
+ QValueList<MyMoneyAccount> accounts;
+ m->accountList(accounts);
+ CPPUNIT_ASSERT(accounts.count() == 0);
+ testAddNewAccount();
+ accounts.clear();
+ m->accountList(accounts);
+ CPPUNIT_ASSERT(accounts.count() == 2);
+
+ MyMoneyAccount a = m->account("A000001");
+ MyMoneyAccount b = m->account("A000002");
+ m->reparentAccount(b, a);
+ accounts.clear();
+ m->accountList(accounts);
+ CPPUNIT_ASSERT(accounts.count() == 2);
+}
+
+void MyMoneySeqAccessMgrTest::testLoaderFunctions()
+{
+ // we don't need the transaction started by setup() here
+ m->rollbackTransaction();
+
+ // account loader
+ QMap<QString, MyMoneyAccount> amap;
+ MyMoneyAccount acc("A0000176", MyMoneyAccount());
+ amap[acc.id()] = acc;
+ m->loadAccounts(amap);
+ CPPUNIT_ASSERT(m->m_accountList.values() == amap.values());
+ CPPUNIT_ASSERT(m->m_accountList.keys() == amap.keys());
+ CPPUNIT_ASSERT(m->m_nextAccountID == 176);
+
+ // transaction loader
+ QMap<QString, MyMoneyTransaction> tmap;
+ MyMoneyTransaction t("T000000108", MyMoneyTransaction());
+ tmap[t.id()] = t;
+ m->loadTransactions(tmap);
+ CPPUNIT_ASSERT(m->m_transactionList.values() == tmap.values());
+ CPPUNIT_ASSERT(m->m_transactionList.keys() == tmap.keys());
+ CPPUNIT_ASSERT(m->m_nextTransactionID == 108);
+
+ // institution loader
+ QMap<QString, MyMoneyInstitution> imap;
+ MyMoneyInstitution inst("I000028", MyMoneyInstitution());
+ imap[inst.id()] = inst;
+ m->loadInstitutions(imap);
+ CPPUNIT_ASSERT(m->m_institutionList.values() == imap.values());
+ CPPUNIT_ASSERT(m->m_institutionList.keys() == imap.keys());
+ CPPUNIT_ASSERT(m->m_nextInstitutionID == 28);
+
+ // payee loader
+ QMap<QString, MyMoneyPayee> pmap;
+ MyMoneyPayee p("P1234", MyMoneyPayee());
+ pmap[p.id()] = p;
+ m->loadPayees(pmap);
+ CPPUNIT_ASSERT(m->m_payeeList.values() == pmap.values());
+ CPPUNIT_ASSERT(m->m_payeeList.keys() == pmap.keys());
+ CPPUNIT_ASSERT(m->m_nextPayeeID == 1234);
+
+ // security loader
+ QMap<QString, MyMoneySecurity> smap;
+ MyMoneySecurity s("S54321", MyMoneySecurity());
+ smap[s.id()] = s;
+ m->loadSecurities(smap);
+ CPPUNIT_ASSERT(m->m_securitiesList.values() == smap.values());
+ CPPUNIT_ASSERT(m->m_securitiesList.keys() == smap.keys());
+ CPPUNIT_ASSERT(m->m_nextSecurityID == 54321);
+
+ // schedule loader
+ QMap<QString, MyMoneySchedule> schmap;
+ MyMoneySchedule sch("SCH6789", MyMoneySchedule());
+ schmap[sch.id()] = sch;
+ m->loadSchedules(schmap);
+ CPPUNIT_ASSERT(m->m_scheduleList.values() == schmap.values());
+ CPPUNIT_ASSERT(m->m_scheduleList.keys() == schmap.keys());
+ CPPUNIT_ASSERT(m->m_nextScheduleID == 6789);
+
+ // report loader
+ QMap<QString, MyMoneyReport> rmap;
+ MyMoneyReport r("R1298", MyMoneyReport());
+ rmap[r.id()] = r;
+ m->loadReports(rmap);
+ CPPUNIT_ASSERT(m->m_reportList.values() == rmap.values());
+ CPPUNIT_ASSERT(m->m_reportList.keys() == rmap.keys());
+ CPPUNIT_ASSERT(m->m_nextReportID == 1298);
+
+ // budget loader
+ QMap<QString, MyMoneyBudget> bmap;
+ MyMoneyBudget b("B89765", MyMoneyBudget());
+ bmap[b.id()] = b;
+ m->loadBudgets(bmap);
+ CPPUNIT_ASSERT(m->m_budgetList.values() == bmap.values());
+ CPPUNIT_ASSERT(m->m_budgetList.keys() == bmap.keys());
+ CPPUNIT_ASSERT(m->m_nextBudgetID == 89765);
+
+ // restart a transaction so that teardown() is happy
+ m->startTransaction();
+}
+
diff --git a/kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.h b/kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.h
new file mode 100644
index 0000000..b9fa763
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneyseqaccessmgrtest.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+ mymoneyseqaccessmgrtest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MYMONEYSEQACCESSMGRTEST_H__
+#define __MYMONEYSEQACCESSMGRTEST_H__
+
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestCase.h>
+#include <cppunit/TestSuite.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "../autotest.h"
+
+#define private public
+#define protected public
+#include "../mymoneyobject.h"
+#include "mymoneyseqaccessmgr.h"
+#undef private
+
+class MyMoneySeqAccessMgrTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(MyMoneySeqAccessMgrTest);
+ CPPUNIT_TEST(testEmptyConstructor);
+ CPPUNIT_TEST(testSetFunctions);
+ CPPUNIT_TEST(testSupportFunctions);
+ CPPUNIT_TEST(testIsStandardAccount);
+ CPPUNIT_TEST(testNewAccount);
+ CPPUNIT_TEST(testAddNewAccount);
+ CPPUNIT_TEST(testReparentAccount);
+ CPPUNIT_TEST(testAddInstitution);
+ CPPUNIT_TEST(testInstitution);
+ CPPUNIT_TEST(testAccount2Institution);
+ CPPUNIT_TEST(testModifyAccount);
+ CPPUNIT_TEST(testModifyInstitution);
+ CPPUNIT_TEST(testAddTransactions);
+ CPPUNIT_TEST(testTransactionCount);
+ CPPUNIT_TEST(testBalance);
+ CPPUNIT_TEST(testModifyTransaction);
+ CPPUNIT_TEST(testRemoveUnusedAccount);
+ CPPUNIT_TEST(testRemoveUsedAccount);
+ CPPUNIT_TEST(testRemoveInstitution);
+ CPPUNIT_TEST(testRemoveTransaction);
+ CPPUNIT_TEST(testTransactionList);
+ CPPUNIT_TEST(testAddPayee);
+ CPPUNIT_TEST(testSetAccountName);
+ CPPUNIT_TEST(testModifyPayee);
+ CPPUNIT_TEST(testPayeeName);
+ CPPUNIT_TEST(testRemovePayee);
+ CPPUNIT_TEST(testRemoveAccountFromTree);
+ CPPUNIT_TEST(testAssignment);
+ CPPUNIT_TEST(testDuplicate);
+ CPPUNIT_TEST(testAddSchedule);
+ CPPUNIT_TEST(testModifySchedule);
+ CPPUNIT_TEST(testRemoveSchedule);
+ CPPUNIT_TEST(testSchedule);
+ CPPUNIT_TEST(testScheduleList);
+ CPPUNIT_TEST(testAddCurrency);
+ CPPUNIT_TEST(testModifyCurrency);
+ CPPUNIT_TEST(testRemoveCurrency);
+ CPPUNIT_TEST(testCurrency);
+ CPPUNIT_TEST(testCurrencyList);
+ CPPUNIT_TEST(testAccountList);
+ CPPUNIT_TEST(testLoaderFunctions);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ MyMoneySeqAccessMgr *m;
+public:
+ MyMoneySeqAccessMgrTest();
+
+
+ void setUp();
+ void tearDown();
+ void testEmptyConstructor();
+ void testSetFunctions();
+ void testIsStandardAccount();
+ void testNewAccount();
+ void testAccount();
+ void testAddNewAccount();
+ void testAddInstitution();
+ void testInstitution();
+ void testAccount2Institution();
+ void testModifyAccount();
+ void testModifyInstitution();
+ void testReparentAccount();
+ void testAddTransactions();
+ void testTransactionCount();
+ void testBalance();
+ void testModifyTransaction();
+ void testRemoveUnusedAccount();
+ void testRemoveUsedAccount();
+ void testRemoveInstitution();
+ void testRemoveTransaction();
+ void testTransactionList();
+ void testAddPayee();
+ void testSetAccountName();
+ void testModifyPayee();
+ void testPayeeName();
+ void testRemovePayee();
+ void testRemoveAccountFromTree();
+ void testAssignment();
+ void testEquality(const MyMoneySeqAccessMgr* t);
+ void testDuplicate();
+ void testAddSchedule();
+ void testSchedule();
+ void testModifySchedule();
+ void testRemoveSchedule();
+ void testSupportFunctions();
+ void testScheduleList();
+ void testAddCurrency();
+ void testModifyCurrency();
+ void testRemoveCurrency();
+ void testCurrency();
+ void testCurrencyList();
+ void testAccountList();
+ void testLoaderFunctions();
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneystorageanon.cpp b/kmymoney2/mymoney/storage/mymoneystorageanon.cpp
new file mode 100644
index 0000000..31f051e
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystorageanon.cpp
@@ -0,0 +1,294 @@
+/***************************************************************************
+ mymoneystorageanon.cpp
+ -------------------
+ begin : Thu Oct 24 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "config.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfile.h>
+#include <qdom.h>
+#include <qmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneystorageanon.h"
+#include "../mymoneyreport.h"
+#include "../mymoneyinstitution.h"
+
+QStringList MyMoneyStorageANON::zKvpNoModify = QStringList::split(",","kmm-baseCurrency,PreferredAccount,Tax,fixed-interest,interest-calculation,payee,schedule,term,kmm-online-source,kmm-brokerage-account,lastStatementDate,kmm-sort-reconcile,kmm-sort-std,kmm-iconpos,mm-closed,payee,schedule,term,lastImportedTransactionDate,VatAccount,VatRate,kmm-matched-tx,Imported");
+QStringList MyMoneyStorageANON::zKvpXNumber = QStringList::split(",","final-payment,loan-amount,periodic-payment,lastStatementBalance");
+
+
+MyMoneyStorageANON::MyMoneyStorageANON() :
+ MyMoneyStorageXML()
+{
+ // Choose a quasi-random 0.0-100.0 factor which will be applied to all splits this time
+ // around.
+
+ int msec;
+ do {
+ msec = QTime::currentTime().msec();
+ } while(msec == 0);
+ m_factor = MyMoneyMoney(msec, 10).reduce();
+}
+
+MyMoneyStorageANON::~MyMoneyStorageANON()
+{
+}
+
+void MyMoneyStorageANON::readFile(QIODevice* , IMyMoneySerialize* )
+{
+ throw new MYMONEYEXCEPTION("Cannot read a file through MyMoneyStorageANON!!");
+}
+
+void MyMoneyStorageANON::writeUserInformation(QDomElement& userInfo)
+{
+ MyMoneyPayee user = m_storage->user();
+
+ userInfo.setAttribute(QString("name"), hideString(user.name()));
+ userInfo.setAttribute(QString("email"), hideString(user.email()));
+
+ QDomElement address = m_doc->createElement("ADDRESS");
+ address.setAttribute(QString("street"), hideString(user.address()));
+ address.setAttribute(QString("city"), hideString(user.city()));
+ address.setAttribute(QString("county"), hideString(user.state()));
+ address.setAttribute(QString("zipcode"), hideString(user.postcode()));
+ address.setAttribute(QString("telephone"), hideString(user.telephone()));
+
+ userInfo.appendChild(address);
+}
+
+void MyMoneyStorageANON::writeInstitution(QDomElement& institution, const MyMoneyInstitution& _i)
+{
+ MyMoneyInstitution i(_i);
+
+ // mangle fields
+ i.setName(i.id());
+ i.setManager(hideString(i.manager()));
+ i.setSortcode(hideString(i.sortcode()));
+
+ i.setStreet(hideString(i.street()));
+ i.setCity(hideString(i.city()));
+ i.setPostcode(hideString(i.postcode()));
+ i.setTelephone(hideString(i.telephone()));
+
+ MyMoneyStorageXML::writeInstitution(institution, i);
+}
+
+
+void MyMoneyStorageANON::writePayee(QDomElement& payee, const MyMoneyPayee& _p)
+{
+ MyMoneyPayee p(_p);
+
+ p.setName(p.id());
+ p.setReference(hideString(p.reference()));
+
+ p.setAddress(hideString(p.address()));
+ p.setCity(hideString(p.city()));
+ p.setPostcode(hideString(p.postcode()));
+ p.setState(hideString(p.state()));
+ p.setTelephone(hideString(p.telephone()));
+ p.setNotes(hideString(p.notes()));
+ bool ignoreCase;
+ QStringList keys;
+ MyMoneyPayee::payeeMatchType matchType = p.matchData(ignoreCase, keys);
+ QRegExp exp("[A-Za-z]");
+ p.setMatchData(matchType, ignoreCase, QStringList::split(";", keys.join(";").replace(exp, "x")));
+
+ MyMoneyStorageXML::writePayee(payee, p);
+}
+
+void MyMoneyStorageANON::writeAccount(QDomElement& account, const MyMoneyAccount& _p)
+{
+ MyMoneyAccount p(_p);
+
+ p.setNumber(hideString(p.number()));
+ p.setName(p.id());
+ p.setDescription(hideString(p.description()));
+ fakeKeyValuePair(p);
+
+ // Remove the online banking settings entirely.
+ p.setOnlineBankingSettings(MyMoneyKeyValueContainer());
+
+ MyMoneyStorageXML::writeAccount(account, p);
+}
+
+void MyMoneyStorageANON::fakeTransaction(MyMoneyTransaction& tx)
+{
+ MyMoneyTransaction tn = tx;
+
+ // hide transaction data
+ tn.setMemo(tx.id());
+ tn.setBankID(hideString(tx.bankID()));
+
+ // hide split data
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = tx.splits().begin(); it_s != tx.splits().end(); ++it_s) {
+ MyMoneySplit s = (*it_s);
+ s.setMemo(QString("%1/%2").arg(tn.id()).arg(s.id()));
+
+ if(s.value() != MyMoneyMoney::autoCalc) {
+ s.setValue((s.value() * m_factor));
+ s.setShares((s.shares() * m_factor));
+ }
+ s.setNumber(hideString(s.number()));
+
+ // obfuscate a possibly matched transaction as well
+ if(s.isMatched()) {
+ MyMoneyTransaction t = s.matchedTransaction();
+ fakeTransaction(t);
+ s.removeMatch();
+ s.addMatch(t);
+ }
+ tn.modifySplit(s);
+ }
+ tx = tn;
+ fakeKeyValuePair(tx);
+}
+
+void MyMoneyStorageANON::fakeKeyValuePair(MyMoneyKeyValueContainer& kvp)
+{
+ QMap<QString, QString> pairs;
+ QMap<QString, QString>::const_iterator it;
+
+ for(it = kvp.pairs().begin(); it != kvp.pairs().end(); ++it)
+ {
+ if ( zKvpXNumber.contains( it.key() ) || it.key().left(3)=="ir-" )
+ pairs[it.key()] = hideNumber(MyMoneyMoney(it.data())).toString();
+ else if ( zKvpNoModify.contains( it.key() ) )
+ pairs[it.key()] = it.data();
+ else
+ pairs[it.key()] = hideString(it.data());
+ }
+ kvp.setPairs(pairs);
+}
+
+void MyMoneyStorageANON::writeTransaction(QDomElement& transactions, const MyMoneyTransaction& tx)
+{
+ MyMoneyTransaction tn = tx;
+
+ fakeTransaction(tn);
+
+ MyMoneyStorageXML::writeTransaction(transactions, tn);
+}
+
+void MyMoneyStorageANON::writeSchedule(QDomElement& scheduledTx, const MyMoneySchedule& sx)
+{
+ MyMoneySchedule sn = sx;
+ MyMoneyTransaction tn = sn.transaction();
+
+ fakeTransaction(tn);
+
+ sn.setName(sx.id());
+ sn.setTransaction(tn, true);
+
+ MyMoneyStorageXML::writeSchedule(scheduledTx, sn);
+}
+
+void MyMoneyStorageANON::writeSecurity(QDomElement& securityElement, const MyMoneySecurity& security)
+{
+ MyMoneySecurity s = security;
+ s.setName(security.id());
+ fakeKeyValuePair(s);
+
+ MyMoneyStorageXML::writeSecurity(securityElement, s);
+}
+
+QString MyMoneyStorageANON::hideString(const QString& _in) const
+{
+ return QString(_in).fill('x');
+}
+
+MyMoneyMoney MyMoneyStorageANON::hideNumber(const MyMoneyMoney& _in) const
+{
+ MyMoneyMoney result;
+ static MyMoneyMoney counter = MyMoneyMoney(100,100);
+
+ // preserve sign
+ if ( _in.isNegative() )
+ result = MyMoneyMoney(-1);
+ else
+ result = MyMoneyMoney(1);
+
+ result = result * counter;
+ counter += MyMoneyMoney("10/100");
+
+ // preserve > 1000
+ if ( _in >= MyMoneyMoney(1000) )
+ result = result * MyMoneyMoney(1000);
+ if ( _in <= MyMoneyMoney(-1000) )
+ result = result * MyMoneyMoney(1000);
+
+ return result.convert();
+}
+
+void MyMoneyStorageANON::fakeBudget(MyMoneyBudget& bx)
+{
+ MyMoneyBudget bn;
+
+ bn.setName(bx.name());
+ bn.setBudgetStart(bx.budgetStart());
+ bn = MyMoneyBudget(bx.id(), bn);
+
+ QValueList<MyMoneyBudget::AccountGroup> list = bx.getaccounts();
+ QValueList<MyMoneyBudget::AccountGroup>::iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ // only add the account if there is a budget entered
+ if(!(*it).balance().isZero()) {
+ MyMoneyBudget::AccountGroup account;
+ account.setId((*it).id());
+ account.setBudgetLevel((*it).budgetLevel());
+ account.setBudgetSubaccounts((*it).budgetSubaccounts());
+ QMap<QDate, MyMoneyBudget::PeriodGroup> plist = (*it).getPeriods();
+ QMap<QDate, MyMoneyBudget::PeriodGroup>::const_iterator it_p;
+ for(it_p = plist.begin(); it_p != plist.end(); ++it_p) {
+ MyMoneyBudget::PeriodGroup pGroup;
+ pGroup.setAmount((*it_p).amount() * m_factor );
+ pGroup.setStartDate( (*it_p).startDate());
+ account.addPeriod(pGroup.startDate(), pGroup);
+ }
+ bn.setAccount(account, account.id());
+ }
+ }
+
+ bx = bn;
+}
+
+void MyMoneyStorageANON::writeBudget(QDomElement& budgets, const MyMoneyBudget& b)
+{
+ MyMoneyBudget bn = b;
+
+ fakeBudget(bn);
+
+ MyMoneyStorageXML::writeBudget(budgets, bn);
+}
+
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/mymoney/storage/mymoneystorageanon.h b/kmymoney2/mymoney/storage/mymoneystorageanon.h
new file mode 100644
index 0000000..4b7ab95
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystorageanon.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+ mymoneystorageanon.h
+ -------------------
+ begin : Thu Oct 24 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jone <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSTORAGEANON_H
+#define MYMONEYSTORAGEANON_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// #include <qdom.h>
+// #include <qdatastream.h>
+// class QIODevice;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+// #include "imymoneyserialize.h"
+// #include "imymoneystorageformat.h"
+#include "mymoneystoragexml.h"
+
+/**
+ * @author Kevin Tambascio (ktambascio@users.sourceforge.net)
+ */
+
+#define VERSION_0_60_XML 0x10000010 // Version 0.5 file version info
+#define VERSION_0_61_XML 0x10000011 // use 8 bytes for MyMoneyMoney objects
+
+/**
+ * This class provides storage of an anonymized version of the current
+ * file. Any object with an ID (account, transaction, etc) is renamed
+ * with that ID. Any other string value the user typed in is replaced with
+ * x's equal in length to the original string. Any numeric value is
+ * replaced with an arbitrary number which matches the sign of the original.
+ *
+ * The purpose of this class is to give users a way to send a developer
+ * their file without comprimising their financial data. If a user
+ * encounters an error, they should try saving the anonymous version of the
+ * file and see if the error is still there. If so, they should notify the
+ * list of the problem, and then when requested, send the anonymous file
+ * privately to the developer who takes the problem. I still don't think
+ * it's wise to post the file to the public list...maybe I'm just paranoid.
+ *
+ * @author Ace Jones <ace.j@hotpop.com>
+ */
+
+class MyMoneyStorageANON : public MyMoneyStorageXML
+{
+public:
+ MyMoneyStorageANON();
+ virtual ~MyMoneyStorageANON();
+
+protected:
+ void writeUserInformation(QDomElement& userInfo);
+
+ void writeInstitution(QDomElement& institutions, const MyMoneyInstitution& i);
+
+ void writePayee(QDomElement& payees, const MyMoneyPayee& p);
+
+ void writeAccount(QDomElement& accounts, const MyMoneyAccount& p);
+
+ void writeTransaction(QDomElement& transactions, const MyMoneyTransaction& tx);
+
+ void writeSchedule(QDomElement& scheduledTx, const MyMoneySchedule& tx);
+
+ void writeBudget(QDomElement& budgets, const MyMoneyBudget& b);
+
+ void readFile(QIODevice* s, IMyMoneySerialize* storage);
+
+ void writeSecurity(QDomElement& securityElement, const MyMoneySecurity& security);
+
+ QDomElement findChildElement(const QString& name, const QDomElement& root);
+
+private:
+ /**
+ * The list of key-value pairs to not modify
+ */
+ static QStringList zKvpNoModify;
+
+ /**
+ * The list of key-value pairs which are numbers to be hidden
+ */
+ static QStringList zKvpXNumber;
+
+ QString hideString(const QString&) const;
+ MyMoneyMoney hideNumber(const MyMoneyMoney&) const;
+ void fakeTransaction(MyMoneyTransaction& tn);
+ void fakeBudget(MyMoneyBudget& bn);
+ void fakeKeyValuePair(MyMoneyKeyValueContainer& _kvp);
+
+ MyMoneyMoney m_factor;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneystoragebin.h b/kmymoney2/mymoney/storage/mymoneystoragebin.h
new file mode 100644
index 0000000..6ef7e20
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragebin.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ imymoneystoragebin.h - description
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSTORAGEBIN_H
+#define MYMONEYSTORAGEBIN_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ *@author Thomas Baumgart
+ */
+
+ #define VERSION_0_3_3 0x00000006 // MAGIC1 for version 0.33 files
+ #define VERSION_0_4_0 0x00000007 // MAGIC1 for version 0.4 files
+
+ #define MAGIC_0_50 0x4B4D794D // "KMyM" MAGIC1 for version 0.5 files
+ #define MAGIC_0_51 0x6F6E6579 // "oney" second part of MAGIC
+
+ #define VERSION_0_50 0x00000010 // Version 0.5 file version info
+ #define VERSION_0_51 0x00000011 // use 8 bytes for MyMoneyMoney objects
+
+ // add new definitions above and make sure to adapt MAX_FILE_VERSION below
+ #define MIN_FILE_VERSION VERSION_0_50
+ #define MAX_FILE_VERSION VERSION_0_51
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneystoragedump.cpp b/kmymoney2/mymoney/storage/mymoneystoragedump.cpp
new file mode 100644
index 0000000..e0d0083
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragedump.cpp
@@ -0,0 +1,446 @@
+/***************************************************************************
+ mymoneystoragedump.cpp - description
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneystoragedump.h"
+#include "imymoneystorage.h"
+#include "../mymoneyaccount.h"
+#include "../mymoneysecurity.h"
+#include "../mymoneyprice.h"
+
+MyMoneyStorageDump::MyMoneyStorageDump()
+{
+}
+
+MyMoneyStorageDump::~MyMoneyStorageDump()
+{
+}
+
+void MyMoneyStorageDump::readStream(QDataStream& /* s */, IMyMoneySerialize* /* storage */)
+{
+ qDebug("Reading not supported by MyMoneyStorageDump!!");
+}
+
+void MyMoneyStorageDump::writeStream(QDataStream& _s, IMyMoneySerialize* _storage)
+{
+ QTextStream s(_s.device());
+ IMyMoneyStorage* storage = dynamic_cast<IMyMoneyStorage *> (_storage);
+ MyMoneyPayee user = storage->user();
+
+ s << "File-Info\n";
+ s << "---------\n";
+ s << "user name = " << user.name() << "\n";
+ s << "user street = " << user.address() << "\n";
+ s << "user city = " << user.city() << "\n";
+ s << "user city = " << user.state() << "\n";
+ s << "user zip = " << user.postcode() << "\n";
+ s << "user telephone = " << user.telephone() << "\n";
+ s << "user e-mail = " << user.email() << "\n";
+ s << "creation date = " << storage->creationDate().toString(Qt::ISODate) << "\n";
+ s << "last modification date = " << storage->lastModificationDate().toString(Qt::ISODate) << "\n";
+ s << "base currency = " << storage->value("kmm-baseCurrency") << "\n";
+ s << "\n";
+
+ s << "Internal-Info\n";
+ s << "-------------\n";
+ QValueList<MyMoneyAccount> list_a;
+ storage->accountList(list_a);
+ s << "accounts = " << list_a.count() <<", next id = " << _storage->accountId() << "\n";
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> list_t;
+ storage->transactionList(list_t, filter);
+ QValueList<MyMoneyTransaction>::ConstIterator it_t;
+ s << "transactions = " << list_t.count() << ", next id = " << _storage->transactionId() << "\n";
+ QMap<int,int> xferCount;
+ for(it_t = list_t.begin(); it_t != list_t.end(); ++it_t) {
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ int accountCount = 0;
+ for(it_s = (*it_t).splits().begin(); it_s != (*it_t).splits().end(); ++it_s) {
+ MyMoneyAccount acc = storage->account((*it_s).accountId());
+ if(acc.accountGroup() != MyMoneyAccount::Expense
+ && acc.accountGroup() != MyMoneyAccount::Income)
+ accountCount++;
+ }
+ if(accountCount > 1)
+ xferCount[accountCount] = xferCount[accountCount] + 1;
+ }
+ QMap<int,int>::ConstIterator it_cnt;
+ for(it_cnt = xferCount.begin(); it_cnt != xferCount.end(); ++it_cnt) {
+ s << " " << *it_cnt << " of them references " << it_cnt.key() << " accounts\n";
+ }
+
+ s << "payees = " << _storage->payeeList().count() << ", next id = " << _storage->payeeId() << "\n";
+ s << "institutions = " << _storage->institutionList().count() << ", next id = " << _storage->institutionId() << "\n";
+ s << "schedules = " << _storage->scheduleList().count() << ", next id = " << _storage->scheduleId() << "\n";
+ s << "\n";
+
+ s << "Institutions\n";
+ s << "------------\n";
+
+ QValueList<MyMoneyInstitution> list_i = storage->institutionList();
+ QValueList<MyMoneyInstitution>::ConstIterator it_i;
+ for(it_i = list_i.begin(); it_i != list_i.end(); ++it_i) {
+ s << " ID = " << (*it_i).id() << "\n";
+ s << " Name = " << (*it_i).name() << "\n";
+ s << "\n";
+ }
+ s << "\n";
+
+ s << "Payees" << "\n";
+ s << "------" << "\n";
+
+ QValueList<MyMoneyPayee> list_p = storage->payeeList();
+ QValueList<MyMoneyPayee>::ConstIterator it_p;
+ for(it_p = list_p.begin(); it_p != list_p.end(); ++it_p) {
+ s << " ID = " << (*it_p).id() << "\n";
+ s << " Name = " << (*it_p).name() << "\n";
+ s << " Address = " << (*it_p).address() << "\n";
+ s << " City = " << (*it_p).city() << "\n";
+ s << " State = " << (*it_p).state() << "\n";
+ s << " Zip = " << (*it_p).postcode() << "\n";
+ s << " E-Mail = " << (*it_p).email() << "\n";
+ s << " Telephone = " << (*it_p).telephone() << "\n";
+ s << " Reference = " << (*it_p).reference() << "\n";
+ s << "\n";
+ }
+ s << "\n";
+
+
+ s << "Accounts" << "\n";
+ s << "--------" << "\n";
+
+ list_a.push_front(storage->equity());
+ list_a.push_front(storage->expense());
+ list_a.push_front(storage->income());
+ list_a.push_front(storage->liability());
+ list_a.push_front(storage->asset());
+ QValueList<MyMoneyAccount>::ConstIterator it_a;
+ for(it_a = list_a.begin(); it_a != list_a.end(); ++it_a) {
+ s << " ID = " << (*it_a).id() << "\n";
+ s << " Name = " << (*it_a).name() << "\n";
+ s << " Number = " << (*it_a).number() << "\n";
+ s << " Description = " << (*it_a).description() << "\n";
+ s << " Type = " << (*it_a).accountType() << "\n";
+ if((*it_a).currencyId().isEmpty()) {
+ s << " Currency = unknown\n";
+ } else {
+ if((*it_a).isInvest()) {
+ s << " Equity = " << storage->security((*it_a).currencyId()).name() << "\n";
+ } else {
+ s << " Currency = " << storage->currency((*it_a).currencyId()).name() << "\n";
+ }
+ }
+ s << " Parent = " << (*it_a).parentAccountId();
+ if(!(*it_a).parentAccountId().isEmpty()) {
+ MyMoneyAccount parent = storage->account((*it_a).parentAccountId());
+ s << " (" << parent.name() << ")";
+ } else {
+ s << "n/a";
+ }
+ s << "\n";
+
+ s << " Institution = " << (*it_a).institutionId();
+ if(!(*it_a).institutionId().isEmpty()) {
+ MyMoneyInstitution inst = storage->institution((*it_a).institutionId());
+ s << " (" << inst.name() << ")";
+ } else {
+ s << "n/a";
+ }
+ s << "\n";
+
+ s << " Opening data = " << (*it_a).openingDate().toString(Qt::ISODate) << "\n";
+ s << " Last modified = " << (*it_a).lastModified().toString(Qt::ISODate) << "\n";
+ s << " Last reconciled = " << (*it_a).lastReconciliationDate().toString(Qt::ISODate) << "\n";
+ s << " Balance = " << (*it_a).balance().formatMoney("", 2) << "\n";
+
+ dumpKVP(" KVP: ", s, *it_a);
+ dumpKVP(" OnlineBankingSettings: ", s, (*it_a).onlineBankingSettings());
+
+ QStringList list_s = (*it_a).accountList();
+ QStringList::ConstIterator it_s;
+ if(list_s.count() > 0) {
+ s << " Children =" << "\n";
+ }
+ for(it_s = list_s.begin(); it_s != list_s.end(); ++it_s) {
+ MyMoneyAccount child = storage->account(*it_s);
+ s << " " << *it_s << " (" << child.name() << ")\n";
+ }
+ s << "\n";
+ }
+ s << "\n";
+
+#if 0
+ s << "Currencies" << "\n";
+ s << "----------" << "\n";
+
+ QValueList<MyMoneyCurrency> list_c = storage->currencyList();
+ QValueList<MyMoneyCurrency>::ConstIterator it_c;
+ for(it_c = list_c.begin(); it_c != list_c.end(); ++it_c) {
+ s << " Name = " << (*it_c).name() << "\n";
+ s << " ID = " << (*it_c).id() << "\n";
+ s << " Symbol = " << (*it_c).tradingSymbol() << "\n";
+ s << " Parts/Unit = " << (*it_c).partsPerUnit() << "\n";
+ s << " smallest cash fraction = " << (*it_c).smallestCashFraction() << "\n";
+ s << " smallest account fraction = " << (*it_c).smallestAccountFraction() << "\n";
+ dumpPriceHistory(s, (*it_c).priceHistory());
+ s << "\n";
+ }
+ s << "\n";
+#endif
+
+ s << "Securities" << "\n";
+ s << "----------" << "\n";
+
+ QValueList<MyMoneySecurity> list_e = storage->securityList();
+ QValueList<MyMoneySecurity>::ConstIterator it_e;
+ for(it_e = list_e.begin(); it_e != list_e.end(); ++it_e) {
+ s << " Name = " << (*it_e).name() << "\n";
+ s << " ID = " << (*it_e).id() << "\n";
+ s << " Market = " << (*it_e).tradingMarket() << "\n";
+ s << " Symbol = " << (*it_e).tradingSymbol() << "\n";
+ s << " Currency = " << (*it_e).tradingCurrency() << " (";
+ if((*it_e).tradingCurrency().isEmpty()) {
+ s << "unknown";
+ } else {
+ MyMoneySecurity tradingCurrency = storage->currency((*it_e).tradingCurrency());
+ if(!tradingCurrency.isCurrency()) {
+ s << "invalid currency: ";
+ }
+ s << tradingCurrency.name();
+ }
+ s << ")\n";
+
+ s << " Type = " << MyMoneySecurity::securityTypeToString((*it_e).securityType()) << "\n";
+ s << " smallest account fraction = " << (*it_e).smallestAccountFraction() << "\n";
+
+ s << " KVP: " << "\n";
+ QMap<QString, QString>kvp = (*it_e).pairs();
+ QMap<QString, QString>::Iterator it;
+ for(it = kvp.begin(); it != kvp.end(); ++it) {
+ s << " '" << it.key() << "' = '" << it.data() << "'\n";
+ }
+ s << "\n";
+ }
+ s << "\n";
+
+ s << "Prices" << "\n";
+ s << "--------" << "\n";
+
+ MyMoneyPriceList list_pr = _storage->priceList();
+ MyMoneyPriceList::ConstIterator it_pr;
+ for(it_pr = list_pr.begin(); it_pr != list_pr.end(); ++it_pr) {
+ s << " From = " << it_pr.key().first << "\n";
+ s << " To = " << it_pr.key().second << "\n";
+ MyMoneyPriceEntries::ConstIterator it_pre;
+ for(it_pre = (*it_pr).begin(); it_pre != (*it_pr).end(); ++it_pre) {
+ s << " Date = " << (*it_pre).date().toString() << "\n";
+ s << " Price = " << (*it_pre).rate(QString()).formatMoney("", 8) << "\n";
+ s << " Source = " << (*it_pre).source() << "\n";
+ s << " From = " << (*it_pre).from() << "\n";
+ s << " To = " << (*it_pre).to() << "\n";
+ }
+ s << "\n";
+ }
+ s << "\n";
+
+ s << "Transactions" << "\n";
+ s << "------------" << "\n";
+
+ for(it_t = list_t.begin(); it_t != list_t.end(); ++it_t) {
+ dumpTransaction(s, storage, *it_t);
+ }
+ s << "\n";
+
+
+ s << "Schedules" << "\n";
+ s << "---------" << "\n";
+
+ QValueList<MyMoneySchedule> list_s = storage->scheduleList();
+ QValueList<MyMoneySchedule>::ConstIterator it_s;
+ for(it_s = list_s.begin(); it_s != list_s.end(); ++it_s) {
+ s << " ID = " << (*it_s).id() << "\n";
+ s << " Name = " << (*it_s).name() << "\n";
+ s << " Startdate = " << (*it_s).startDate().toString(Qt::ISODate) << "\n";
+ if((*it_s).willEnd())
+ s << " Enddate = " << (*it_s).endDate().toString(Qt::ISODate) << "\n";
+ else
+ s << " Enddate = not specified\n";
+ s << " Occurence = " << (*it_s).occurenceToString() << "\n";
+ s << " OccurenceMultiplier = " << (*it_s).occurenceMultiplier() << "\n";
+ s << " Type = " << MyMoneySchedule::scheduleTypeToString((*it_s).type()) << "\n";
+ s << " Paymenttype = " << MyMoneySchedule::paymentMethodToString((*it_s).paymentType()) << "\n";
+ s << " Fixed = " << (*it_s).isFixed() << "\n";
+ s << " AutoEnter = " << (*it_s).autoEnter() << "\n";
+
+ if((*it_s).lastPayment().isValid())
+ s << " Last payment = " << (*it_s).lastPayment().toString(Qt::ISODate) << "\n";
+ else
+ s << " Last payment = not defined" << "\n";
+ if((*it_s).isFinished())
+ s << " Next payment = payment finished" << "\n";
+ else {
+ s << " Next payment = " << (*it_s).nextDueDate().toString(Qt::ISODate) << "\n";
+ if((*it_s).isOverdue())
+ s << " = overdue!" << "\n";
+ }
+
+ QValueList<QDate> list_d;
+ QValueList<QDate>::ConstIterator it_d;
+
+ list_d = (*it_s).recordedPayments();
+ if(list_d.count() > 0) {
+ s << " Recorded payments" << "\n";
+ for(it_d = list_d.begin(); it_d != list_d.end(); ++it_d) {
+ s << " " << (*it_d).toString(Qt::ISODate) << "\n";
+ }
+ }
+ s << " TRANSACTION\n";
+ dumpTransaction(s, storage, (*it_s).transaction());
+ }
+ s << "\n";
+
+ s << "Reports" << "\n";
+ s << "-------" << "\n";
+
+ QValueList<MyMoneyReport> list_r = storage->reportList();
+ QValueList<MyMoneyReport>::ConstIterator it_r;
+ for(it_r = list_r.begin(); it_r != list_r.end(); ++it_r) {
+ s << " ID = " << (*it_r).id() << "\n";
+ s << " Name = " << (*it_r).name() << "\n";
+ }
+}
+
+void MyMoneyStorageDump::dumpKVP(const QString& headline, QTextStream& s, const MyMoneyKeyValueContainer &kvp, int indent)
+{
+ QString ind;
+ ind.fill(' ', indent);
+ s << ind << headline << "\n";
+ QMap<QString, QString>::const_iterator it;
+ for(it = kvp.pairs().begin(); it != kvp.pairs().end(); ++it) {
+ s << ind << " '" << it.key() << "' = '" << it.data() << "'\n";
+ }
+}
+
+void MyMoneyStorageDump::dumpTransaction(QTextStream& s, IMyMoneyStorage* storage, const MyMoneyTransaction& it_t)
+{
+ s << " ID = " << it_t.id() << "\n";
+ s << " Postdate = " << it_t.postDate().toString(Qt::ISODate) << "\n";
+ s << " EntryDate = " << it_t.entryDate().toString(Qt::ISODate) << "\n";
+ s << " Commodity = [" << it_t.commodity() << "]\n";
+ s << " Memo = " << it_t.memo() << "\n";
+ s << " BankID = " << it_t.bankID() << "\n";
+ dumpKVP("KVP:", s, it_t, 2);
+
+ s << " Splits\n";
+ s << " ------\n";
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = it_t.splits().begin(); it_s != it_t.splits().end(); ++it_s) {
+ s << " ID = " << (*it_s).id() << "\n";
+ s << " Transaction = " << (*it_s).transactionId() << "\n";
+ s << " Payee = " << (*it_s).payeeId();
+ if(!(*it_s).payeeId().isEmpty()) {
+ MyMoneyPayee p = storage->payee((*it_s).payeeId());
+ s << " (" << p.name() << ")" << "\n";
+ } else
+ s << " ()\n";
+ s << " Account = " << (*it_s).accountId();
+ MyMoneyAccount acc;
+ try {
+ acc = storage->account((*it_s).accountId());
+ s << " (" << acc.name() << ") [" << acc.currencyId() << "]\n";
+ } catch (MyMoneyException *e) {
+ s << " (---) [---]\n";
+ delete e;
+ }
+ s << " Memo = " << (*it_s).memo() << "\n";
+ if((*it_s).value() == MyMoneyMoney::autoCalc)
+ s << " Value = will be calculated" << "\n";
+ else
+ s << " Value = " << (*it_s).value().formatMoney("", 2)
+ << " (" << (*it_s).value().toString() << ")\n";
+ s << " Shares = " << (*it_s).shares().formatMoney("", 2)
+ << " (" << (*it_s).shares().toString() << ")\n";
+ s << " Action = '" << (*it_s).action() << "'\n";
+ s << " Nr = '" << (*it_s).number() << "'\n";
+ s << " ReconcileFlag = '" << reconcileToString((*it_s).reconcileFlag()) << "'\n";
+ if((*it_s).reconcileFlag() != MyMoneySplit::NotReconciled) {
+ s << " ReconcileDate = " << (*it_s).reconcileDate().toString(Qt::ISODate) << "\n";
+ }
+ s << " BankID = " << (*it_s).bankID() << "\n";
+ dumpKVP("KVP:", s, (*it_s), 4);
+ s << "\n";
+ }
+ s << "\n";
+}
+
+#define i18n QString
+
+const QString MyMoneyStorageDump::reconcileToString(MyMoneySplit::reconcileFlagE flag) const
+{
+ QString rc;
+
+ switch(flag) {
+ case MyMoneySplit::NotReconciled:
+ rc = i18n("not reconciled");
+ break;
+ case MyMoneySplit::Cleared:
+ rc = i18n("cleared");
+ break;
+ case MyMoneySplit::Reconciled:
+ rc = i18n("reconciled");
+ break;
+ case MyMoneySplit::Frozen:
+ rc = i18n("frozen");
+ break;
+ default:
+ rc = i18n("unknown");
+ break;
+ }
+ return rc;
+}
+
+#if 0
+void MyMoneyStorageDump::dumpPriceHistory(QTextStream& s, const equity_price_history history)
+{
+ if(history.count() != 0) {
+ s << " Price History:\n";
+
+ equity_price_history::const_iterator it_price = history.begin();
+ while ( it_price != history.end() )
+ {
+ s << " " << it_price.key().toString() << ": " << it_price.data().toDouble() << "\n";
+ it_price++;
+ }
+ }
+}
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneystoragedump.h b/kmymoney2/mymoney/storage/mymoneystoragedump.h
new file mode 100644
index 0000000..e399cde
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragedump.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ mymoneystoragedump.h - description
+ -------------------
+ begin : Sun May 5 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSTORAGEDUMP_H
+#define MYMONEYSTORAGEDUMP_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatastream.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "imymoneyserialize.h"
+#include "../mymoneysecurity.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class MyMoneyStorageDump
+{
+public:
+ MyMoneyStorageDump();
+ ~MyMoneyStorageDump();
+
+ void readStream(QDataStream& s, IMyMoneySerialize* storage);
+ void writeStream(QDataStream& s, IMyMoneySerialize* storage);
+
+private:
+ void dumpTransaction(QTextStream& s, IMyMoneyStorage* storage, const MyMoneyTransaction& it_t);
+ void dumpKVP(const QString& headline, QTextStream& s, const MyMoneyKeyValueContainer &kvp, int indent = 0);
+ const QString reconcileToString(MyMoneySplit::reconcileFlagE flag) const;
+};
+
+#endif
diff --git a/kmymoney2/mymoney/storage/mymoneystoragesql.cpp b/kmymoney2/mymoney/storage/mymoneystoragesql.cpp
new file mode 100644
index 0000000..97b4c55
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragesql.cpp
@@ -0,0 +1,4511 @@
+/***************************************************************************
+ mymoneystoragesql.cpp
+ ---------------------
+ begin : 11 November 2005
+ copyright : (C) 2005 by Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ : Fernando Vilas <fvilas@iname.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <algorithm>
+#include <numeric>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <qiodevice.h>
+#include <qsqldriver.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneystoragesql.h"
+#include "imymoneyserialize.h"
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#define TRY try {
+#define CATCH } catch (MyMoneyException *e) {
+#define PASS } catch (MyMoneyException *e) { throw; }
+#define ECATCH }
+#define DBG(a) // qDebug(a)
+//#define TRACE(a) qDebug(a)
+#define TRACE(a) ::timetrace(a)
+
+//***************** THE CURRENT VERSION OF THE DATABASE LAYOUT ****************
+unsigned int MyMoneyDbDef::m_currentVersion = 6;
+
+// subclass QSqlQuery for performance tracing
+
+MyMoneySqlQuery::MyMoneySqlQuery (MyMoneyStorageSql* db)
+ : QSqlQuery (static_cast<QSqlDatabase*>(db)) {
+ m_db = db;
+}
+
+bool MyMoneySqlQuery::exec () {
+ TRACE(QString("start sql - %1").arg(lastQuery()));
+ bool rc = QSqlQuery::exec();
+ QString msg("end sql\n%1\n***Query returned %2, row count %3");
+ TRACE (msg.arg(QSqlQuery::executedQuery()).arg(rc).arg(numRowsAffected()));
+ //DBG (QString("%1\n***Query returned %2, row count %3").arg(QSqlQuery::executedQuery()).arg(rc).arg(size()));
+ return (rc);
+}
+
+bool MyMoneySqlQuery::prepare ( const QString & query ) {
+ if (m_db->isSqlite3()) {
+ QString newQuery = query;
+ return (QSqlQuery::prepare (newQuery.replace("FOR UPDATE", "")));
+ }
+ return (QSqlQuery::prepare (query));
+}
+
+//*****************************************************************************
+MyMoneyDbDrivers::MyMoneyDbDrivers () {
+ m_driverMap["QDB2"] = QString("IBM DB2");
+ m_driverMap["QIBASE"] = QString("Borland Interbase");
+ m_driverMap["QMYSQL3"] = QString("MySQL");
+ m_driverMap["QOCI8"] = QString("Oracle Call Interface, version 8 and 9");
+ m_driverMap["QODBC3"] = QString("Open Database Connectivity");
+ m_driverMap["QPSQL7"] = QString("PostgreSQL v6.x and v7.x");
+ m_driverMap["QTDS7"] = QString("Sybase Adaptive Server and Microsoft SQL Server");
+#if QT_VERSION < 0x040000
+ m_driverMap["QSQLITE3"] = QString("SQLite Version 3");
+#else
+ m_driverMap["QSQLITE"] = QString("SQLite Version 3");
+#endif
+}
+
+databaseTypeE MyMoneyDbDrivers::driverToType (const QString& driver) const {
+ if (driver == "QDB2") return(Db2);
+ else if (driver == "QIBASE") return(Interbase);
+ else if (driver == "QMYSQL3") return(Mysql);
+ else if (driver == "QOCI8") return(Oracle8);
+ else if (driver == "QODBC3") return(ODBC3);
+ else if (driver == "QPSQL7") return(Postgresql);
+ else if (driver == "QTDS7") return(Sybase);
+#if QT_VERSION < 0x040000
+ else if (driver == "QSQLITE3") return(Sqlite3);
+#else
+ else if (driver == "QSQLITE") return(Sqlite3);
+#endif
+ else throw new MYMONEYEXCEPTION (QString("Unknown database driver type").arg(driver));
+}
+
+bool MyMoneyDbDrivers::isTested (databaseTypeE dbType) const {
+ switch (dbType) {
+ case Mysql:
+ case Sqlite3:
+ case Postgresql:
+ return (true);
+ default:
+ return(false);
+ }
+ return(false);
+}
+
+//************************ Constructor/Destructor *****************************
+MyMoneyStorageSql::MyMoneyStorageSql (IMyMoneySerialize *storage, const KURL& url)
+ : QSqlDatabase (url.queryItem("driver"), QString("kmmdatabase")) {
+ DBG("*** Entering MyMoneyStorageSql::MyMoneyStorageSql");
+ m_dbVersion = 0;
+ m_progressCallback = 0;
+ m_displayStatus = false;
+ m_storage = storage;
+ m_storagePtr = dynamic_cast<IMyMoneyStorage*>(storage);
+ m_newDatabase = false;
+ m_readingPrices = false;
+ m_loadAll = false;
+ m_override = false;
+ m_preferred.setReportAllSplits(false);
+}
+
+int MyMoneyStorageSql::open(const KURL& url, int openMode, bool clear) {
+ DBG("*** Entering MyMoneyStorageSql::open");
+try {
+ int rc = 0;
+ QString driverName = url.queryItem("driver");
+ m_dbType = m_drivers.driverToType(driverName);
+ //get the input options
+ QStringList options = QStringList::split(',', url.queryItem("options"));
+ m_loadAll = options.contains("loadAll")/*|| m_mode == 0*/;
+ m_override = options.contains("override");
+
+ // create the database connection
+ QString dbName = url.path().right(url.path().length() - 1); // remove separator slash
+ setDatabaseName(dbName);
+ setHostName(url.host());
+ setUserName(url.user());
+ setPassword(url.pass());
+ switch (openMode) {
+ case IO_ReadOnly: // OpenDatabase menu entry (or open last file)
+ case IO_ReadWrite: // Save menu entry with database open
+ if (!QSqlDatabase::open()) {
+ buildError(MyMoneySqlQuery(), __func__, "opening database");
+ rc = 1;
+ } else {
+ rc = createTables(); // check all tables are present, create if not (we may add tables at some time)
+ }
+ break;
+ case IO_WriteOnly: // SaveAs Database - if exists, must be empty, if not will create
+ // Try to open the database.
+ // If that fails, try to create the database, then try to open it again.
+ m_newDatabase = true;
+ if (!QSqlDatabase::open()) {
+ if (createDatabase(url) != 0) {
+ rc = 1;
+ } else {
+ if (!QSqlDatabase::open()) {
+ buildError(MyMoneySqlQuery(), __func__, "opening new database");
+ rc = 1;
+ } else {
+ rc = createTables();
+ }
+ }
+ } else {
+ rc = createTables();
+ if (rc == 0) {
+ if (clear) {
+ clean();
+ } else {
+ rc = isEmpty();
+ }
+ }
+ }
+ break;
+ default:
+ qFatal("%s", QString("%1 - unknown open mode %2").arg(__func__).arg(openMode).data());
+ }
+ if (rc != 0) return (rc);
+ // bypass logon check if we are creating a database
+ if (openMode == IO_WriteOnly) return(0);
+ // check if the database is locked, if not lock it
+ readFileInfo();
+ if (!m_logonUser.isEmpty() && (!m_override)) {
+ m_error = QString
+ (i18n("Database apparently in use\nOpened by %1 on %2 at %3.\nOpen anyway?"))
+ .arg(m_logonUser)
+ .arg(m_logonAt.date().toString(Qt::ISODate))
+ .arg(m_logonAt.time().toString("hh.mm.ss"));
+ qDebug("%s", m_error.data());
+ close(false);
+ rc = -1;
+ } else {
+ m_logonUser = url.user() + "@" + url.host();
+ m_logonAt = QDateTime::currentDateTime();
+ writeFileInfo();
+ }
+ return(rc);
+} catch (QString& s) {
+ qDebug("%s",s.data());
+ return (1);
+}
+}
+
+void MyMoneyStorageSql::close(bool logoff) {
+ DBG("*** Entering MyMoneyStorageSql::close");
+ if (QSqlDatabase::open()) {
+ if (logoff) {
+ startCommitUnit(__func__);
+ m_logonUser = QString();
+ writeFileInfo();
+ endCommitUnit(__func__);
+ }
+ QSqlDatabase::close();
+ QSqlDatabase::removeDatabase(this);
+ }
+}
+
+int MyMoneyStorageSql::createDatabase (const KURL& url) {
+ DBG("*** Entering MyMoneyStorageSql::createDatabase");
+ if (m_dbType == Sqlite3) return(0); // not needed for sqlite
+ if (!m_dbType == Mysql) {
+ m_error =
+ QString(i18n("Cannot currently create database for driver %1; please create manually")).arg(driverName());
+ return (1);
+ }
+ // create the database (only works for mysql at present)
+ QString dbName = url.path().right(url.path().length() - 1); // remove separator slash
+ QSqlDatabase *maindb = QSqlDatabase::addDatabase(driverName());
+ maindb->setDatabaseName ("mysql");
+ maindb->setHostName (url.host());
+ maindb->setUserName (url.user());
+ maindb->setPassword (url.pass());
+ maindb->open();
+ QSqlQuery qm(maindb);
+ QString qs = QString("CREATE DATABASE %1;").arg(dbName);
+ qm.prepare (qs);
+ if (!qm.exec()) {
+ buildError (qm, __func__, QString(i18n("Error in create database %1; do you have create permissions?")).arg(dbName));
+ return (1);
+ }
+ QSqlDatabase::removeDatabase (maindb);
+ return (0);
+}
+
+
+int MyMoneyStorageSql::upgradeDb() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeDb");
+ //signalProgress(0, 1, QObject::tr("Upgrading database..."));
+ MyMoneySqlQuery q(this);
+ q.prepare ("SELECT version FROM kmmFileInfo;");
+ if (!q.exec() || !q.next()) {
+ if (!m_newDatabase) {
+ buildError (q, __func__, "Error retrieving file info(version)");
+ return(1);
+ } else {
+ m_dbVersion = m_db.currentVersion();
+ m_storage->setFileFixVersion(m_storage->currentFixVersion());
+ QSqlQuery q(this);
+ q.prepare("UPDATE kmmFileInfo SET version = :version, \
+ fixLevel = :fixLevel;");
+ q.bindValue(":version", m_dbVersion);
+ q.bindValue(":fixLevel", m_storage->currentFixVersion());
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating file info(version)");
+ return(1);
+ }
+ return (0);
+ }
+ }
+ // prior to dbv6, 'version' format was 'dbversion.fixLevel+1'
+ // as of dbv6, these are separate fields
+ QString version = q.value(0).toString();
+ if (version.contains('.')) {
+ m_dbVersion = q.value(0).toString().section('.', 0, 0).toUInt();
+ m_storage->setFileFixVersion(q.value(0).toString().section('.', 1, 1).toUInt() - 1);
+ } else {
+ m_dbVersion = version.toUInt();
+ q.prepare ("SELECT fixLevel FROM kmmFileInfo;");
+ if (!q.exec() || !q.next()) {
+ buildError (q, __func__, "Error retrieving file info (fixLevel)");
+ return(1);
+ }
+ m_storage->setFileFixVersion(q.value(0).toUInt());
+ }
+ int rc = 0;
+ while ((m_dbVersion < m_db.currentVersion()) && (rc == 0)) {
+ switch (m_dbVersion) {
+ case 0:
+ if ((rc = upgradeToV1()) != 0) return (1);
+ ++m_dbVersion;
+ break;
+ case 1:
+ if ((rc = upgradeToV2()) != 0) return (1);
+ ++m_dbVersion;
+ break;
+ case 2:
+ if ((rc = upgradeToV3()) != 0) return (1);
+ ++m_dbVersion;
+ break;
+ case 3:
+ if ((rc = upgradeToV4()) != 0) return (1);
+ ++m_dbVersion;
+ break;
+ case 4:
+ if ((rc = upgradeToV5()) != 0) return (1);
+ ++m_dbVersion;
+ break;
+ case 5:
+ if ((rc = upgradeToV6()) != 0) return (1);
+ ++m_dbVersion;
+ break;
+ case 6:
+ break;
+ default:
+ qFatal("Unknown version number in database - %d", m_dbVersion);
+ }
+ }
+ // write updated version to DB
+ //setVersion(QString("%1.%2").arg(m_dbVersion).arg(m_minorVersion));
+ q.prepare (QString("UPDATE kmmFileInfo SET version = :version;"));
+ q.bindValue(":version", m_dbVersion);
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating db version");
+ return (1);
+ }
+ //signalProgress(-1,-1);
+ return (0);
+}
+// SF bug 2779291
+// check whether a column appears in a table already; if not, add it
+bool MyMoneyStorageSql::addColumn
+ (const QString& table, const QString& col,
+ const QString& after)
+{
+ MyMoneyDbTable t = m_db.m_tables[table];
+ MyMoneyDbTable::field_iterator ft;
+ const MyMoneyDbColumn* c;
+ for (ft = t.begin(); ft != t.end(); ++ft) {
+ c = (*ft);
+ if (c->name() == col)
+ break;
+ }
+ if (ft == t.end()) qFatal("addColumn - get it right");
+ return (addColumn(t, *c, after));
+}
+
+bool MyMoneyStorageSql::addColumn
+ (const MyMoneyDbTable& t, const MyMoneyDbColumn& c,
+ const QString& after){
+ if ((m_dbType == Sqlite3) && (!after.isEmpty()))
+ qFatal("sqlite doesn't support 'AFTER'; use sqliteAlterTable");
+ if (record(t.name()).contains(c.name()))
+ return (true);
+ QSqlQuery q(this);
+ QString afterString = ";";
+ if (!after.isEmpty())
+ afterString = QString("AFTER %1;").arg(after);
+ q.prepare("ALTER TABLE " + t.name() + " ADD COLUMN " +
+ c.generateDDL(m_dbType) + afterString);
+ if (!q.exec()) {
+ buildError (q, __func__,
+ QString("Error adding column %1 to table %2").arg(c.name()).arg(t.name()));
+ return (false);
+ }
+ return (true);
+}
+
+// analogous to above
+bool MyMoneyStorageSql::dropColumn
+ (const QString& table, const QString& col)
+{
+ return (dropColumn(m_db.m_tables[table], col));
+}
+
+bool MyMoneyStorageSql::dropColumn
+ (const MyMoneyDbTable& t, const QString& col){
+ if (m_dbType == Sqlite3)
+ qFatal("sqlite doesn't support 'DROP COLUMN'; use sqliteAlterTable");
+ if (!record(t.name()).contains(col))
+ return (true);
+ QSqlQuery q(this);
+ q.prepare("ALTER TABLE " + t.name() + " DROP COLUMN "
+ + col + ";");
+ if (!q.exec()) {
+ buildError (q, __func__,
+ QString("Error dropping column %1 from table %2").arg(col).arg(t.name()));
+ return (false);
+ }
+ return (true);
+}
+
+int MyMoneyStorageSql::upgradeToV1() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeToV1");
+ if ((m_dbType == Sqlite) || (m_dbType == Sqlite3)) qFatal("SQLite upgrade NYI");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ // change kmmSplits pkey to (transactionId, splitId)
+ q.prepare ("ALTER TABLE kmmSplits ADD PRIMARY KEY (transactionId, splitId);");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating kmmSplits pkey");
+ return (1);
+ }
+ // change kmmSplits alter checkNumber varchar(32)
+ q.prepare (m_db.m_tables["kmmSplits"].modifyColumnString(m_dbType, "checkNumber",
+ MyMoneyDbColumn("checkNumber", "varchar(32)")));
+ if (!q.exec()) {
+ buildError (q, __func__, "Error expanding kmmSplits.checkNumber");
+ return (1);
+ }
+ // change kmmSplits add postDate datetime
+ if (!addColumn(m_db.m_tables["kmmSplits"],
+ MyMoneyDbDatetimeColumn("postDate")))
+ return (1);
+ // initialize it to same value as transaction (do it the long way round)
+ q.prepare ("SELECT id, postDate FROM kmmTransactions WHERE txType = 'N';");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error priming kmmSplits.postDate");
+ return (1);
+ }
+ QMap<QString, QDateTime> tids;
+ while (q.next()) tids[q.value(0).toString()] = q.value(1).toDateTime();
+ QMap<QString, QDateTime>::ConstIterator it;
+ for (it = tids.begin(); it != tids.end(); ++it) {
+ q.prepare ("UPDATE kmmSplits SET postDate=:postDate WHERE transactionId = :id;");
+ q.bindValue(":postDate", it.data().toString(Qt::ISODate));
+ q.bindValue(":id", it.key());
+ if (!q.exec()) {
+ buildError (q, __func__, "priming kmmSplits.postDate");
+ return(1);
+ }
+ }
+ // add index to kmmKeyValuePairs to (kvpType,kvpId)
+ QStringList list;
+ list << "kvpType" << "kvpId";
+ q.prepare (MyMoneyDbIndex("kmmKeyValuePairs", "kmmKVPtype_id", list, false).generateDDL(m_dbType) + ";");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error adding kmmKeyValuePairs index");
+ return (1);
+ }
+ // add index to kmmSplits to (accountId, txType)
+ list.clear();
+ list << "accountId" << "txType";
+ q.prepare (MyMoneyDbIndex("kmmSplits", "kmmSplitsaccount_type", list, false).generateDDL(m_dbType) + ";");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error adding kmmSplits index");
+ return (1);
+ }
+ // change kmmSchedulePaymentHistory pkey to (schedId, payDate)
+ q.prepare ("ALTER TABLE kmmSchedulePaymentHistory ADD PRIMARY KEY (schedId, payDate);");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating kmmSchedulePaymentHistory pkey");
+ return (1);
+ }
+ // change kmmPrices pkey to (fromId, toId, priceDate)
+ q.prepare ("ALTER TABLE kmmPrices ADD PRIMARY KEY (fromId, toId, priceDate);");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating kmmPrices pkey");
+ return (1);
+ }
+ // change kmmReportConfig pkey to (name)
+ // There wasn't one previously, so no need to drop it.
+ q.prepare ("ALTER TABLE kmmReportConfig ADD PRIMARY KEY (name);");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating kmmReportConfig pkey");
+ return (1);
+ }
+ // change kmmFileInfo add budgets unsigned bigint after kvps
+ if (!addColumn(m_db.m_tables["kmmFileInfo"],
+ MyMoneyDbIntColumn("budgets", MyMoneyDbIntColumn::BIG, false)))
+ return (1);
+ // change kmmFileInfo add hiBudgetId unsigned bigint after hiReportId
+ if (!addColumn(m_db.m_tables["kmmFileInfo"],
+ MyMoneyDbIntColumn("hiBudgetId", MyMoneyDbIntColumn::BIG, false)))
+ return (1);
+ // change kmmFileInfo add logonUser
+ if (!addColumn(m_db.m_tables["kmmFileInfo"],
+ MyMoneyDbColumn("logonUser", "varchar(255)", false)))
+ return (1);
+ // change kmmFileInfo add logonAt datetime
+ if (!addColumn(m_db.m_tables["kmmFileInfo"],
+ MyMoneyDbDatetimeColumn("logonAt", false)))
+ return (1);
+ // change kmmAccounts add transactionCount unsigned bigint as last field
+ if (!addColumn(m_db.m_tables["kmmAccounts"],
+ MyMoneyDbIntColumn("transactionCount", MyMoneyDbIntColumn::BIG, false)))
+ return (1);
+ // calculate the transaction counts. the application logic defines an account's tx count
+ // in such a way as to count multiple splits in a tx which reference the same account as one.
+ // this is the only way I can think of to do this which will work in sqlite too.
+ // inefficient, but it only gets done once...
+ // get a list of all accounts so we'll get a zero value for those without txs
+ q.prepare ("SELECT id FROM kmmAccounts");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error retrieving accounts for transaction counting");
+ return(1);
+ }
+ while (q.next()) {
+ m_transactionCountMap[q.value(0).toCString()] = 0;
+ }
+ q.prepare ("SELECT accountId, transactionId FROM kmmSplits WHERE txType = 'N' ORDER BY 1, 2");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error retrieving splits for transaction counting");
+ return(1);
+ }
+ QString lastAcc, lastTx;
+ while (q.next()) {
+ QString thisAcc = q.value(0).toCString();
+ QString thisTx = q.value(1).toCString();
+ if ((thisAcc != lastAcc) || (thisTx != lastTx)) ++m_transactionCountMap[thisAcc];
+ lastAcc = thisAcc;
+ lastTx = thisTx;
+ }
+ QMap<QString, unsigned long>::ConstIterator itm;
+ q.prepare("UPDATE kmmAccounts SET transactionCount = :txCount WHERE id = :id;");
+ for (itm = m_transactionCountMap.begin(); itm != m_transactionCountMap.end(); ++itm) {
+ q.bindValue (":txCount", QString::number(itm.data()));
+ q.bindValue (":id", itm.key());
+ if (!q.exec()) {
+ buildError(q, __func__, "Error updating transaction count");
+ return (1);
+ }
+ }
+ m_transactionCountMap.clear();
+ // there were considerable problems with record counts in V0, so rebuild them
+ readFileInfo();
+ m_institutions = getRecCount("kmmInstitutions");
+ m_accounts = getRecCount("kmmAccounts");
+ m_payees = getRecCount("kmmPayees");
+ m_transactions = getRecCount("kmmTransactions WHERE txType = 'N'");
+ m_splits = getRecCount("kmmSplits");
+ m_securities = getRecCount("kmmSecurities");
+ m_prices = getRecCount("kmmPrices");
+ m_currencies = getRecCount("kmmCurrencies");
+ m_schedules = getRecCount("kmmSchedules");
+ m_reports = getRecCount("kmmReportConfig");
+ m_kvps = getRecCount("kmmKeyValuePairs");
+ m_budgets = getRecCount("kmmBudgetConfig");
+ writeFileInfo();
+ /* if sqlite {
+ q.prepare("VACUUM;");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error vacuuming database");
+ return(1);
+ }
+ }*/
+ endCommitUnit(__func__);
+ return (0);
+}
+
+int MyMoneyStorageSql::upgradeToV2() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeToV2");
+ //SQLite3 now supports ALTER TABLE...ADD COLUMN, so only die if version < 3
+ //if (m_dbType == Sqlite3) qFatal("SQLite upgrade NYI");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ // change kmmSplits add price fields
+ if (!addColumn(m_db.m_tables["kmmSplits"],
+ MyMoneyDbTextColumn("price")))
+ return (1);
+ if (!addColumn(m_db.m_tables["kmmSplits"],
+ MyMoneyDbTextColumn("priceFormatted")))
+ return (1);
+ endCommitUnit(__func__);
+ return (0);
+}
+
+int MyMoneyStorageSql::upgradeToV3() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeToV3");
+ //SQLite3 now supports ALTER TABLE...ADD COLUMN, so only die if version < 3
+ //if (m_dbType == Sqlite3) qFatal("SQLite upgrade NYI");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ // The default value is given here to populate the column.
+ q.prepare ("ALTER TABLE kmmSchedules ADD COLUMN " +
+ MyMoneyDbIntColumn("occurenceMultiplier",
+ MyMoneyDbIntColumn::SMALL, false, false, true)
+ .generateDDL(m_dbType) + " DEFAULT 0;");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error adding kmmSchedules.occurenceMultiplier");
+ return (1);
+ }
+ //The default is less than any useful value, so as each schedule is hit, it will update
+ //itself to the appropriate value.
+ endCommitUnit(__func__);
+ return 0;
+}
+
+int MyMoneyStorageSql::upgradeToV4() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeToV4");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ QStringList list;
+ list << "transactionId" << "splitId";
+ q.prepare (MyMoneyDbIndex("kmmSplits", "kmmTx_Split", list, false).generateDDL(m_dbType) + ";");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error adding kmmSplits index on (transactionId, splitId)");
+ return (1);
+ }
+ endCommitUnit(__func__);
+ return 0;
+}
+
+int MyMoneyStorageSql::upgradeToV5() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeToV5");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ if (!addColumn(m_db.m_tables["kmmSplits"],
+ MyMoneyDbTextColumn("bankId")))
+ return (1);
+ if (!addColumn(m_db.m_tables["kmmPayees"],
+ MyMoneyDbTextColumn("notes", MyMoneyDbTextColumn::LONG)))
+ return (1);
+ if (!addColumn(m_db.m_tables["kmmPayees"],
+ MyMoneyDbColumn("defaultAccountId", "varchar(32)")))
+ return (1);
+ if (!addColumn(m_db.m_tables["kmmPayees"],
+ MyMoneyDbIntColumn("matchData", MyMoneyDbIntColumn::TINY,
+ false)))
+ return (1);
+ if (!addColumn(m_db.m_tables["kmmPayees"],
+ MyMoneyDbColumn("matchIgnoreCase", "char(1)")))
+ return (1);
+ if (!addColumn(m_db.m_tables["kmmPayees"],
+ MyMoneyDbTextColumn("matchKeys")))
+ return (1);
+ const MyMoneyDbTable& t = m_db.m_tables["kmmReportConfig"];
+ if (m_dbType != Sqlite3) {
+ q.prepare (t.dropPrimaryKeyString(m_dbType));
+ if (!q.exec()) {
+ buildError (q, __func__, "Error dropping Report table keys");
+ return (1);
+ }
+ } else {
+ if (!sqliteAlterTable(t))
+ return (1);
+ }
+ endCommitUnit(__func__);
+ return 0;
+}
+
+int MyMoneyStorageSql::upgradeToV6() {
+ DBG("*** Entering MyMoneyStorageSql::upgradeToV6");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ // add separate fix level in file info
+ if (!addColumn("kmmFileInfo", "fixLevel"))
+ return (1);
+ // upgrade Mysql to InnoDB transaction-safe engine
+ if (m_dbType == Mysql) {
+ for (QMapConstIterator<QString, MyMoneyDbTable> tt = m_db.tableBegin(); tt != m_db.tableEnd(); ++tt) {
+ q.prepare(QString("ALTER TABLE %1 ENGINE = InnoDB;").arg(tt.data().name()));
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating to InnoDB");
+ return (1);
+ }
+ }
+ }
+ // add unique id to reports table
+ if (!addColumn(m_db.m_tables["kmmReportConfig"],
+ MyMoneyDbColumn("id", "varchar(32)")))
+ return(1);
+ // read and write reports to get ids inserted
+ readFileInfo();
+ QMap<QString, MyMoneyReport> reportList =
+ fetchReports();
+ // the V5 database allowed lots of duplicate reports with no
+ // way to distinguish between them. The fetchReports call
+ // will have effectively removed all duplicates
+ // so we now delete from the db and re-write them
+ q.prepare("DELETE FROM kmmReportConfig;");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error deleting reports");
+ return (1);
+ }
+ unsigned long long hiReportId = 0;
+ QMap<QString, MyMoneyReport>::const_iterator it_r;
+ for(it_r = reportList.begin(); it_r != reportList.end(); ++it_r) {
+ MyMoneyReport r = *it_r;
+ hiReportId = calcHighId(hiReportId, r.id());
+ q.prepare (m_db.m_tables["kmmReportConfig"].insertString());
+ writeReport(*it_r, q);
+ }
+ m_hiIdReports = hiReportId;
+ m_storage->loadReportId(m_hiIdReports);
+ // sqlite3 doesn't support ADD PRIMARY KEY
+ if (m_dbType == Sqlite3) {
+ if (!sqliteAlterTable(m_db.m_tables["kmmReportConfig"])) {
+ return (1);
+ }
+ } else {
+ q.prepare ("ALTER TABLE kmmReportConfig ADD PRIMARY KEY (id);");
+ if (!q.exec()) {
+ buildError (q, __func__, "Error updating kmmReportConfig pkey");
+ return (1);
+ }
+ }
+ endCommitUnit(__func__);
+ return 0;
+}
+
+/* This function attempts to cater for limitations in the sqlite ALTER TABLE
+ statement. It should enable us to drop a primary key, and drop columns */
+bool MyMoneyStorageSql::sqliteAlterTable(const MyMoneyDbTable& t) {
+ DBG("*** Entering MyMoneyStorageSql::sqliteAlterTable");
+ QString tempTableName = t.name();
+ tempTableName.replace("kmm", "tmp");
+ QSqlQuery q(this);
+ q.prepare (QString("ALTER TABLE " + t.name() + " RENAME TO " + tempTableName + ";"));
+ if (!q.exec()) {
+ buildError (q, __func__, "Error renaming table");
+ return false;
+ }
+ createTable(t);
+ q.prepare (QString("INSERT INTO " + t.name() + " (" + t.columnList() +
+ ") SELECT " + t.columnList() + " FROM " + tempTableName + ";"));
+ if (!q.exec()) {
+ buildError (q, __func__, "Error inserting into new table");
+ return false;
+ }
+ q.prepare (QString("DROP TABLE " + tempTableName + ";"));
+ if (!q.exec()) {
+ buildError (q, __func__, "Error dropping old table");
+ return false;
+ }
+ return true;
+}
+
+long unsigned MyMoneyStorageSql::getRecCount (const QString& table) const {
+ DBG("*** Entering MyMoneyStorageSql::getRecCount");
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare(QString("SELECT COUNT(*) FROM %1;").arg(table));
+ if ((!q.exec()) || (!q.next())) {
+ buildError (q, __func__, "error retrieving record count");
+ qFatal("Error retrieving record count"); // definitely shouldn't happen
+ }
+ return ((unsigned long) q.value(0).toULongLong());
+}
+
+int MyMoneyStorageSql::createTables () {
+ DBG("*** Entering MyMoneyStorageSql::createTables");
+ // check tables, create if required
+ // convert everything to lower case, since SQL standard is case insensitive
+ // table and column names (when not delimited), but some DBMSs disagree.
+ QStringList lowerTables = tables(QSql::AllTables);
+ for (QStringList::iterator i = lowerTables.begin(); i != lowerTables.end(); ++i) {
+ (*i) = (*i).lower();
+ }
+
+ for (QMapConstIterator<QString, MyMoneyDbTable> tt = m_db.tableBegin(); tt != m_db.tableEnd(); ++tt) {
+ if (!lowerTables.contains(tt.key().lower())) createTable (tt.data());
+ }
+
+ MyMoneySqlQuery q(this);
+ for (QMapConstIterator<QString, MyMoneyDbView> tt = m_db.viewBegin(); tt != m_db.viewEnd(); ++tt) {
+ if (!lowerTables.contains(tt.key().lower())) {
+ q.prepare (tt.data().createString());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString ("creating view %1").arg(tt.key())));
+ }
+ }
+
+ // get the current db version from kmmFileInfo.
+ // upgrade if necessary.
+
+ return (upgradeDb()); // any errors will be caught by exception handling
+}
+
+void MyMoneyStorageSql::createTable (const MyMoneyDbTable& t) {
+ DBG("*** Entering MyMoneyStorageSql::createTable");
+// create the tables
+ QStringList ql = QStringList::split('\n', t.generateCreateSQL(m_dbType));
+ MyMoneySqlQuery q(this);
+ for (unsigned int i = 0; i < ql.count(); ++i) {
+ q.prepare (ql[i]);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString ("creating table/index %1").arg(t.name())));
+ }
+}
+
+int MyMoneyStorageSql::isEmpty () {
+ DBG("*** Entering MyMoneyStorageSql::isEmpty");
+ // check all tables are empty
+ QMapConstIterator<QString, MyMoneyDbTable> tt = m_db.tableBegin();
+ int recordCount = 0;
+ MyMoneySqlQuery q(this);
+ while ((tt != m_db.tableEnd()) && (recordCount == 0)) {
+ q.prepare (QString("select count(*) from %1;").arg((*tt).name()));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "getting record count"));
+ if (!q.next()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "retrieving record count"));
+ recordCount += q.value(0).toInt();
+ ++tt;
+ }
+
+ if (recordCount != 0) {
+ return (-1); // not empty
+ } else {
+ return (0);
+ }
+}
+
+void MyMoneyStorageSql::clean() {
+ DBG("*** Entering MyMoneyStorageSql::clean");
+// delete all existing records
+ QMapConstIterator<QString, MyMoneyDbTable> it = m_db.tableBegin();
+ MyMoneySqlQuery q(this);
+ while (it != m_db.tableEnd()) {
+ q.prepare(QString("DELETE from %1;").arg(it.key()));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString ("cleaning database")));
+ ++it;
+ }
+}
+
+//////////////////////////////////////////////////////////////////
+
+bool MyMoneyStorageSql::readFile(void) {
+ DBG("*** Entering MyMoneyStorageSql::readFile");
+ m_displayStatus = true;
+ try {
+ readFileInfo();
+ readInstitutions();
+ if (m_loadAll) {
+ readPayees();
+ } else {
+ QValueList<QString> user;
+ user.append(QString("USER"));
+ readPayees(user);
+ }
+ //TRACE("done payees");
+ readCurrencies();
+ //TRACE("done currencies");
+ readSecurities();
+ //TRACE("done securities");
+ readAccounts();
+ if (m_loadAll) {
+ readTransactions();
+ } else {
+ if (m_preferred.filterSet().singleFilter.accountFilter) readTransactions (m_preferred);
+ }
+ //TRACE("done accounts");
+ readSchedules();
+ //TRACE("done schedules");
+ readPrices();
+ //TRACE("done prices");
+ readReports();
+ //TRACE("done reports");
+ readBudgets();
+ //TRACE("done budgets");
+ //FIXME - ?? if (m_mode == 0)
+ //m_storage->rebuildAccountBalances();
+ // this seems to be nonsense, but it clears the dirty flag
+ // as a side-effect.
+ m_storage->setLastModificationDate(m_storage->lastModificationDate());
+ // FIXME?? if (m_mode == 0) m_storage = NULL;
+ // make sure the progress bar is not shown any longer
+ signalProgress(-1, -1);
+ m_displayStatus = false;
+ //MyMoneySqlQuery::traceOn();
+ return true;
+ } catch (QString& s) {
+ return false;
+ }
+}
+
+// The following is called from 'SaveAsDatabase'
+bool MyMoneyStorageSql::writeFile(void) {
+ DBG("*** Entering MyMoneyStorageSql::writeFile");
+ // initialize record counts and hi ids
+ m_institutions = m_accounts = m_payees = m_transactions = m_splits
+ = m_securities = m_prices = m_currencies = m_schedules = m_reports = m_kvps = m_budgets = 0;
+ m_hiIdInstitutions = m_hiIdPayees = m_hiIdAccounts = m_hiIdTransactions =
+ m_hiIdSchedules = m_hiIdSecurities = m_hiIdReports = m_hiIdBudgets = 0;
+ m_displayStatus = true;
+ try{
+ startCommitUnit(__func__);
+ writeInstitutions ();
+ writePayees();
+ writeAccounts();
+ writeTransactions();
+ writeSchedules();
+ writeSecurities();
+ writePrices();
+ writeCurrencies();
+ writeReports();
+ writeBudgets();
+ writeFileInfo();
+ // this seems to be nonsense, but it clears the dirty flag
+ // as a side-effect.
+ //m_storage->setLastModificationDate(m_storage->lastModificationDate());
+ // FIXME?? if (m_mode == 0) m_storage = NULL;
+ endCommitUnit(__func__);
+ // make sure the progress bar is not shown any longer
+ signalProgress(-1, -1);
+ m_displayStatus = false;
+ return true;
+} catch (QString& s) {
+ return false;
+}
+}
+// --------------- SQL Transaction (commit unit) handling -----------------------------------
+void MyMoneyStorageSql::startCommitUnit (const QString& callingFunction) {
+ DBG("*** Entering MyMoneyStorageSql::startCommitUnit");
+ if (m_commitUnitStack.isEmpty()) {
+ if (!transaction()) throw new MYMONEYEXCEPTION(buildError (MyMoneySqlQuery(), __func__, "starting commit unit"));
+ }
+ m_commitUnitStack.push(callingFunction);
+}
+
+bool MyMoneyStorageSql::endCommitUnit (const QString& callingFunction) {
+ DBG("*** Entering MyMoneyStorageSql::endCommitUnit");
+ // for now, we don't know if there were any changes made to the data so
+ // we expect the data to have changed. This assumption causes some unnecessary
+ // repaints of the UI here and there, but for now it's ok. If we can determine
+ // that the commit() really changes the data, we can return that information
+ // as value of this method.
+ bool rc = true;
+ if (callingFunction != m_commitUnitStack.top())
+ qDebug("%s", QString("%1 - %2 s/be %3").arg(__func__).arg(callingFunction).arg(m_commitUnitStack.top()).data());
+ m_commitUnitStack.pop();
+ if (m_commitUnitStack.isEmpty()) {
+ if (!commit()) throw new MYMONEYEXCEPTION(buildError (MyMoneySqlQuery(), __func__, "ending commit unit"));
+ }
+ return rc;
+}
+
+void MyMoneyStorageSql::cancelCommitUnit (const QString& callingFunction) {
+ DBG("*** Entering MyMoneyStorageSql::cancelCommitUnit");
+ if (callingFunction != m_commitUnitStack.top())
+ qDebug("%s", QString("%1 - %2 s/be %3").arg(__func__).arg(callingFunction).arg(m_commitUnitStack.top()).data());
+ if (m_commitUnitStack.isEmpty()) return;
+ m_commitUnitStack.clear();
+ if (!rollback()) throw new MYMONEYEXCEPTION(buildError (MyMoneySqlQuery(), __func__, "cancelling commit unit"));
+}
+
+/////////////////////////////////////////////////////////////////////
+void MyMoneyStorageSql::fillStorage() {
+ DBG("*** Entering MyMoneyStorageSql::fillStorage");
+// if (!m_transactionListRead) // make sure we have loaded everything
+ readTransactions();
+// if (!m_payeeListRead)
+ readPayees();
+}
+
+//------------------------------ Write SQL routines ----------------------------------------
+// **** Institutions ****
+void MyMoneyStorageSql::writeInstitutions() {
+ DBG("*** Entering MyMoneyStorageSql::writeInstitutions");
+ // first, get a list of what's on the database
+ // anything not in the list needs to be inserted
+ // anything which is will be updated and removed from the list
+ // anything left over at the end will need to be deleted
+ // this is an expensive and inconvenient way to do things; find a better way
+ // one way would be to build the lists when reading the db
+ // unfortunately this object does not persist between read and write
+ // it would also be nice if we could tell which objects had been updated since we read them in
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ q.prepare("SELECT id FROM kmmInstitutions;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Institution list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ const QValueList<MyMoneyInstitution> list = m_storage->institutionList();
+ QValueList<MyMoneyInstitution>::ConstIterator it;
+ MyMoneySqlQuery q2(this);
+ q.prepare (m_db.m_tables["kmmInstitutions"].updateString());
+ q2.prepare (m_db.m_tables["kmmInstitutions"].insertString());
+ signalProgress(0, list.count(), "Writing Institutions...");
+ for(it = list.begin(); it != list.end(); ++it) {
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writeInstitution(*it, q);
+ } else {
+ writeInstitution(*it, q2);
+ }
+ signalProgress (++m_institutions, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ QValueList<QString>::const_iterator it = dbList.begin();
+ q.prepare("DELETE FROM kmmInstitutions WHERE id = :id");
+ while (it != dbList.end()) {
+ q.bindValue(":id", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Institution"));
+ deleteKeyValuePairs("OFXSETTINGS", (*it));
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addInstitution(const MyMoneyInstitution& inst) {
+ DBG("*** Entering MyMoneyStorageSql::addInstitution");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmInstitutions"].insertString());
+ writeInstitution(inst ,q);
+ ++m_institutions;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyInstitution(const MyMoneyInstitution& inst) {
+ DBG("*** Entering MyMoneyStorageSql::modifyInstitution");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmInstitutions"].updateString());
+ deleteKeyValuePairs("OFXSETTINGS", inst.id());
+ writeInstitution(inst ,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeInstitution(const MyMoneyInstitution& inst) {
+ DBG("*** Entering MyMoneyStorageSql::removeInstitution");
+ startCommitUnit(__func__);
+ deleteKeyValuePairs("OFXSETTINGS", inst.id());
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmInstitutions"].deleteString());
+ q.bindValue(":id", inst.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Institution")));
+ --m_institutions;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writeInstitution(const MyMoneyInstitution& i, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeInstitution");
+ q.bindValue(":id", i.id());
+ q.bindValue(":name", i.name());
+ q.bindValue(":manager", i.manager());
+ q.bindValue(":routingCode", i.sortcode());
+ q.bindValue(":addressStreet", i.street());
+ q.bindValue(":addressCity", i.city());
+ q.bindValue(":addressZipcode", i.postcode());
+ q.bindValue(":telephone", i.telephone());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Institution")));
+ writeKeyValuePairs("OFXSETTINGS", i.id(), i.pairs());
+ m_hiIdInstitutions = calcHighId(m_hiIdInstitutions, i.id());
+}
+
+// **** Payees ****
+void MyMoneyStorageSql::writePayees() {
+ DBG("*** Entering MyMoneyStorageSql::writePayees");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ q.prepare("SELECT id FROM kmmPayees;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Payee list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ QValueList<MyMoneyPayee> list = m_storage->payeeList();
+ MyMoneyPayee user(QString("USER"), m_storage->user());
+ list.prepend(user);
+ signalProgress(0, list.count(), "Writing Payees...");
+ MyMoneySqlQuery q2(this);
+ q.prepare (m_db.m_tables["kmmPayees"].updateString());
+ q2.prepare (m_db.m_tables["kmmPayees"].insertString());
+ QValueList<MyMoneyPayee>::ConstIterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writePayee(*it, q);
+ } else {
+ writePayee(*it, q2);
+ }
+ signalProgress(++m_payees, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ QValueList<QString>::const_iterator it = dbList.begin();
+ q.prepare(m_db.m_tables["kmmPayees"].deleteString());
+ while (it != dbList.end()) {
+ q.bindValue(":id", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Payee"));
+ m_payees -= q.numRowsAffected();
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addPayee(const MyMoneyPayee& payee) {
+ DBG("*** Entering MyMoneyStorageSql::addPayee");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmPayees"].insertString());
+ writePayee(payee,q);
+ ++m_payees;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyPayee(const MyMoneyPayee& payee) {
+ DBG("*** Entering MyMoneyStorageSql::modifyPayee");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmPayees"].updateString());
+ writePayee(payee,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyUserInfo(const MyMoneyPayee& payee) {
+ DBG("*** Entering MyMoneyStorageSql::modifyUserInfo");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmPayees"].updateString());
+ writePayee(payee,q, true);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removePayee(const MyMoneyPayee& payee) {
+ DBG("*** Entering MyMoneyStorageSql::removePayee");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmPayees"].deleteString());
+ q.bindValue(":id", payee.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Payee")));
+ --m_payees;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writePayee(const MyMoneyPayee& p, MyMoneySqlQuery& q, bool isUserInfo) {
+ DBG("*** Entering MyMoneyStorageSql::writePayee");
+ if (isUserInfo) {
+ q.bindValue(":id", "USER");
+ } else {
+ q.bindValue(":id", p.id());
+ }
+ q.bindValue(":name", p.name());
+ q.bindValue(":reference", p.reference());
+ q.bindValue(":email", p.email());
+ q.bindValue(":addressStreet", p.address());
+ q.bindValue(":addressCity", p.city());
+ q.bindValue(":addressZipcode", p.postcode());
+ q.bindValue(":addressState", p.state());
+ q.bindValue(":telephone", p.telephone());
+ q.bindValue(":notes", p.notes());
+ q.bindValue(":defaultAccountId", p.defaultAccountId());
+ bool ignoreCase;
+ QString matchKeys;
+ MyMoneyPayee::payeeMatchType type = p.matchData(ignoreCase, matchKeys);
+ q.bindValue(":matchData", static_cast<unsigned int>(type));
+ if (ignoreCase) q.bindValue(":matchIgnoreCase", "Y");
+ else q.bindValue(":matchIgnoreCase", "N");
+ q.bindValue(":matchKeys", matchKeys);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString ("writing Payee")));
+ if (!isUserInfo) m_hiIdPayees = calcHighId(m_hiIdPayees, p.id());
+}
+
+// **** Accounts ****
+void MyMoneyStorageSql::writeAccounts() {
+ DBG("*** Entering MyMoneyStorageSql::writeAccounts");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ q.prepare("SELECT id FROM kmmAccounts;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Account list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ QValueList<MyMoneyAccount> list;
+ m_storage->accountList(list);
+ QValueList<MyMoneyAccount>::ConstIterator it;
+ signalProgress(0, list.count(), "Writing Accounts...");
+ if (dbList.isEmpty()) { // new table, insert standard accounts
+ q.prepare (m_db.m_tables["kmmAccounts"].insertString());
+ } else {
+ q.prepare (m_db.m_tables["kmmAccounts"].updateString());
+ }
+ // Attempt to write the standard accounts. For an empty db, this will fail.
+ TRY
+ writeAccount(m_storage->asset(), q); ++m_accounts;
+ writeAccount(m_storage->liability(), q); ++m_accounts;
+ writeAccount(m_storage->expense(), q); ++m_accounts;
+ writeAccount(m_storage->income(), q); ++m_accounts;
+ writeAccount(m_storage->equity(), q); ++m_accounts;
+ CATCH
+ delete e;
+
+ // If the above failed, assume that the database is empty and create
+ // the standard accounts by hand before writing them.
+ MyMoneyAccount acc_l;
+ acc_l.setAccountType(MyMoneyAccount::Liability);
+ acc_l.setName("Liability");
+ MyMoneyAccount liability(STD_ACC_LIABILITY, acc_l);
+
+ MyMoneyAccount acc_a;
+ acc_a.setAccountType(MyMoneyAccount::Asset);
+ acc_a.setName("Asset");
+ MyMoneyAccount asset(STD_ACC_ASSET, acc_a);
+
+ MyMoneyAccount acc_e;
+ acc_e.setAccountType(MyMoneyAccount::Expense);
+ acc_e.setName("Expense");
+ MyMoneyAccount expense(STD_ACC_EXPENSE, acc_e);
+
+ MyMoneyAccount acc_i;
+ acc_i.setAccountType(MyMoneyAccount::Income);
+ acc_i.setName("Income");
+ MyMoneyAccount income(STD_ACC_INCOME, acc_i);
+
+ MyMoneyAccount acc_q;
+ acc_q.setAccountType(MyMoneyAccount::Equity);
+ acc_q.setName("Equity");
+ MyMoneyAccount equity(STD_ACC_EQUITY, acc_q);
+
+ writeAccount(asset, q); ++m_accounts;
+ writeAccount(expense, q); ++m_accounts;
+ writeAccount(income, q); ++m_accounts;
+ writeAccount(liability, q); ++m_accounts;
+ writeAccount(equity, q); ++m_accounts;
+ ECATCH
+
+ int i = 0;
+ MyMoneySqlQuery q2(this);
+ q.prepare (m_db.m_tables["kmmAccounts"].updateString());
+ q2.prepare (m_db.m_tables["kmmAccounts"].insertString());
+ // Update the accounts that exist; insert the ones that do not.
+ for(it = list.begin(); it != list.end(); ++it, ++i) {
+ m_transactionCountMap[(*it).id()] = m_storagePtr->transactionCount((*it).id());
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writeAccount(*it, q);
+ } else {
+ writeAccount(*it, q2);
+ }
+ signalProgress(++m_accounts, 0);
+ }
+
+ // Delete the accounts that are in the db but no longer in memory.
+ if (!dbList.isEmpty()) {
+ QValueList<QString>::const_iterator it = dbList.begin();
+ q.prepare("DELETE FROM kmmAccounts WHERE id = :id");
+ while (it != dbList.end()) {
+ if (!m_storagePtr->isStandardAccount(*it)) {
+ q.bindValue(":id", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Account"));
+ deleteKeyValuePairs("ACCOUNT", (*it));
+ deleteKeyValuePairs("ONLINEBANKING", (*it));
+ }
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addAccount(const MyMoneyAccount& acc) {
+ DBG("*** Entering MyMoneyStorageSql::addAccount");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmAccounts"].insertString());
+ writeAccount(acc,q);
+ ++m_accounts;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyAccount(const MyMoneyAccount& acc) {
+ DBG("*** Entering MyMoneyStorageSql::modifyAccount");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmAccounts"].updateString());
+ deleteKeyValuePairs("ACCOUNT", acc.id());
+ deleteKeyValuePairs("ONLINEBANKING", acc.id());
+ writeAccount(acc,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeAccount(const MyMoneyAccount& acc) {
+ DBG("*** Entering MyMoneyStorageSql::removeAccount");
+ startCommitUnit(__func__);
+ deleteKeyValuePairs("ACCOUNT", acc.id());
+ deleteKeyValuePairs("ONLINEBANKING", acc.id());
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmAccounts"].deleteString());
+ q.bindValue(":id", acc.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Account")));
+ --m_accounts;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writeAccount(const MyMoneyAccount& acc, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeAccount");
+ //MyMoneyMoney balance = m_storagePtr->balance(acc.id(), QDate());
+ q.bindValue(":id", acc.id());
+ q.bindValue(":institutionId", acc.institutionId());
+ q.bindValue(":parentId", acc.parentAccountId());
+ if (acc.lastReconciliationDate() == QDate())
+ q.bindValue(":lastReconciled", acc.lastReconciliationDate());
+ else
+ q.bindValue(":lastReconciled", acc.lastReconciliationDate().toString(Qt::ISODate));
+
+ q.bindValue(":lastModified", acc.lastModified());
+ if (acc.openingDate() == QDate())
+ q.bindValue(":openingDate", acc.openingDate());
+ else
+ q.bindValue(":openingDate", acc.openingDate().toString(Qt::ISODate));
+
+ q.bindValue(":accountNumber", acc.number());
+ q.bindValue(":accountType", acc.accountType());
+ q.bindValue(":accountTypeString", MyMoneyAccount::accountTypeToString(acc.accountType()));
+ if (acc.accountType() == MyMoneyAccount::Stock) {
+ q.bindValue(":isStockAccount", "Y");
+ } else {
+ q.bindValue(":isStockAccount", "N");
+ }
+ q.bindValue(":accountName", acc.name());
+ q.bindValue(":description", acc.description());
+ q.bindValue(":currencyId", acc.currencyId());
+
+ // This section attempts to get the balance from the database, if possible
+ // That way, the balance fields are kept in sync. If that fails, then
+ // It is assumed that the account actually knows its correct balance.
+
+ //FIXME: Using exceptions for branching always feels like a kludge.
+ // Look for a better way.
+ TRY
+ MyMoneyMoney bal = m_storagePtr->balance(acc.id(), QDate());
+ q.bindValue(":balance", bal.toString());
+ q.bindValue(":balanceFormatted",
+ bal.formatMoney("", -1, false));
+ CATCH
+ delete e;
+ q.bindValue(":balance", acc.balance().toString());
+ q.bindValue(":balanceFormatted",
+ acc.balance().formatMoney("", -1, false));
+ ECATCH
+
+ q.bindValue(":transactionCount", Q_ULLONG(m_transactionCountMap[acc.id()]));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Account")));
+
+ //Add in Key-Value Pairs for accounts.
+ //MMAccount inherits from KVPContainer AND has a KVPContainer member
+ //so handle both
+ writeKeyValuePairs("ACCOUNT", acc.id(), acc.pairs());
+ writeKeyValuePairs("ONLINEBANKING", acc.id(), acc.onlineBankingSettings().pairs());
+ m_hiIdAccounts = calcHighId(m_hiIdAccounts, acc.id());
+}
+
+// **** Transactions and Splits ****
+void MyMoneyStorageSql::writeTransactions() {
+ DBG("*** Entering MyMoneyStorageSql::writeTransactions");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ q.prepare("SELECT id FROM kmmTransactions WHERE txType = 'N';");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Transaction list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> list;
+ m_storage->transactionList(list, filter);
+ signalProgress(0, list.count(), "Writing Transactions...");
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+ int i = 0;
+ MyMoneySqlQuery q2(this);
+ q.prepare (m_db.m_tables["kmmTransactions"].updateString());
+ q2.prepare (m_db.m_tables["kmmTransactions"].insertString());
+ for(it = list.begin(); it != list.end(); ++it, ++i) {
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writeTransaction((*it).id(), *it, q, "N");
+ } else {
+ writeTransaction((*it).id(), *it, q2, "N");
+ }
+ signalProgress(++m_transactions, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ QValueList<QString>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ deleteTransaction(*it);
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addTransaction (const MyMoneyTransaction& tx) {
+ DBG("*** Entering MyMoneyStorageSql::addTransaction");
+ startCommitUnit(__func__);
+ // add the transaction and splits
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmTransactions"].insertString());
+ writeTransaction(tx.id(), tx, q, "N");
+ ++m_transactions;
+ // for each split account, update lastMod date, balance, txCount
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = tx.splits().begin(); it_s != tx.splits().end(); ++it_s) {
+ //MyMoneyAccount acc = m_storagePtr->account((*it_s).accountId());
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ ++m_transactionCountMap[acc.id()];
+ modifyAccount(acc);
+ }
+ // in the fileinfo record, update lastMod, txCount, next TxId
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyTransaction (const MyMoneyTransaction& tx) {
+ DBG("*** Entering MyMoneyStorageSql::modifyTransaction");
+ startCommitUnit(__func__);
+ // remove the splits of the old tx from the count table
+ MyMoneySqlQuery q(this);
+ q.prepare ("SELECT accountId FROM kmmSplits WHERE transactionId = :txId;");
+ q.bindValue(":txId", tx.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "retrieving old splits"));
+ while (q.next()) {
+ QString id = q.value(0).toCString();
+ --m_transactionCountMap[id];
+ }
+ // add the transaction and splits
+ q.prepare (m_db.m_tables["kmmTransactions"].updateString());
+ writeTransaction(tx.id(), tx, q, "N");
+ // for each split account, update lastMod date, balance, txCount
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = tx.splits().begin(); it_s != tx.splits().end(); ++it_s) {
+ //MyMoneyAccount acc = m_storagePtr->account((*it_s).accountId());
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ ++m_transactionCountMap[acc.id()];
+ modifyAccount(acc);
+ }
+ writeSplits(tx.id(), "N", tx.splits());
+ // in the fileinfo record, update lastMod
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeTransaction(const MyMoneyTransaction& tx) {
+ DBG("*** Entering MyMoneyStorageSql::removeTransaction");
+ startCommitUnit(__func__);
+ deleteTransaction(tx.id());
+ --m_transactions;
+
+ // for each split account, update lastMod date, balance, txCount
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = tx.splits().begin(); it_s != tx.splits().end(); ++it_s) {
+ MyMoneyAccount acc = m_storagePtr->account((*it_s).accountId());
+ --m_transactionCountMap[acc.id()];
+ modifyAccount(acc);
+ }
+ // in the fileinfo record, update lastModDate, txCount
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::deleteTransaction(const QString& id) {
+ DBG("*** Entering MyMoneyStorageSql::deleteTransaction");
+ MyMoneySqlQuery q(this);
+ q.prepare("DELETE FROM kmmSplits WHERE transactionId = :transactionId;");
+ q.bindValue(":transactionId", id);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Splits"));
+
+ q.prepare ("DELETE FROM kmmKeyValuePairs WHERE kvpType = 'SPLIT' "
+ "AND kvpId LIKE '" + id + "%'");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Splits KVP"));
+
+ m_splits -= q.numRowsAffected();
+ deleteKeyValuePairs("TRANSACTION", id);
+ q.prepare(m_db.m_tables["kmmTransactions"].deleteString());
+ q.bindValue(":id", id);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Transaction"));
+}
+
+void MyMoneyStorageSql::writeTransaction(const QString& txId, const MyMoneyTransaction& tx, MyMoneySqlQuery& q, const QString& type) {
+ DBG("*** Entering MyMoneyStorageSql::writeTransaction");
+ q.bindValue(":id", txId);
+ q.bindValue(":txType", type);
+ q.bindValue(":postDate", tx.postDate().toString(Qt::ISODate));
+ q.bindValue(":memo", tx.memo());
+ q.bindValue(":entryDate", tx.entryDate().toString(Qt::ISODate));
+ q.bindValue(":currencyId", tx.commodity());
+ q.bindValue(":bankId", tx.bankID());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Transaction")));
+
+ m_txPostDate = tx.postDate(); // FIXME: TEMP till Tom puts date in split object
+ QValueList<MyMoneySplit> splitList = tx.splits();
+ writeSplits(txId, type, splitList);
+
+ //Add in Key-Value Pairs for transactions.
+ deleteKeyValuePairs("TRANSACTION", txId);
+ writeKeyValuePairs("TRANSACTION", txId, tx.pairs());
+ m_hiIdTransactions = calcHighId(m_hiIdTransactions, tx.id());
+}
+
+void MyMoneyStorageSql::writeSplits(const QString& txId, const QString& type, const QValueList<MyMoneySplit>& splitList) {
+ DBG("*** Entering MyMoneyStorageSql::writeSplits");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<unsigned int> dbList;
+ MyMoneySqlQuery q(this);
+ q.prepare("SELECT splitId FROM kmmSplits where transactionId = :id;");
+ q.bindValue(":id", txId);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Split list"));
+ while (q.next()) dbList.append(q.value(0).toUInt());
+
+ QValueList<MyMoneySplit>::const_iterator it;
+ unsigned int i;
+ MyMoneySqlQuery q2(this);
+ q.prepare (m_db.m_tables["kmmSplits"].updateString());
+ q2.prepare (m_db.m_tables["kmmSplits"].insertString());
+ for(it = splitList.begin(), i = 0; it != splitList.end(); ++it, ++i) {
+ if (dbList.contains(i)) {
+ dbList.remove (i);
+ writeSplit(txId, (*it), type, i, q);
+ } else {
+ ++m_splits;
+ writeSplit(txId, (*it), type, i, q2);
+ }
+ }
+
+ if (!dbList.isEmpty()) {
+ q.prepare("DELETE FROM kmmSplits WHERE transactionId = :txId AND splitId = :splitId");
+ QValueList<unsigned int>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ q.bindValue(":txId", txId);
+ q.bindValue(":splitId", *it);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Splits"));
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::writeSplit(const QString& txId, const MyMoneySplit& split,
+ const QString& type, const int splitId, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeSplit");
+ q.bindValue(":transactionId", txId);
+ q.bindValue(":txType", type);
+ q.bindValue(":splitId", splitId);
+ q.bindValue(":payeeId", split.payeeId());
+ if (split.reconcileDate() == QDate())
+ q.bindValue(":reconcileDate", split.reconcileDate());
+ else
+ q.bindValue(":reconcileDate", split.reconcileDate().toString(Qt::ISODate));
+ q.bindValue(":action", split.action());
+ q.bindValue(":reconcileFlag", split.reconcileFlag());
+ q.bindValue(":value", split.value().toString());
+ q.bindValue(":valueFormatted", split.value()
+ .formatMoney("", -1, false)
+ .replace(QChar(','), QChar('.')));
+ q.bindValue(":shares", split.shares().toString());
+ MyMoneyAccount acc = m_storagePtr->account(split.accountId());
+ MyMoneySecurity sec = m_storagePtr->security(acc.currencyId());
+ q.bindValue(":sharesFormatted",
+ split.shares().
+ formatMoney("", MyMoneyMoney::denomToPrec(sec.smallestAccountFraction()), false).
+ replace(QChar(','), QChar('.')));
+ MyMoneyMoney price = split.actualPrice();
+ if (!price.isZero()) {
+ q.bindValue(":price", price.toString());
+ q.bindValue(":priceFormatted", price.formatMoney
+ ("", KMyMoneySettings::pricePrecision(), false)
+ .replace(QChar(','), QChar('.')));
+ } else {
+ q.bindValue(":price", QString());
+ q.bindValue(":priceFormatted", QString());
+ }
+ q.bindValue(":memo", split.memo());
+ q.bindValue(":accountId", split.accountId());
+ q.bindValue(":checkNumber", split.number());
+ q.bindValue(":postDate", m_txPostDate.toString(Qt::ISODate)); // FIXME: when Tom puts date into split object
+ q.bindValue(":bankId", split.bankID());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Split")));
+ deleteKeyValuePairs("SPLIT", txId + QString::number(splitId));
+ writeKeyValuePairs("SPLIT", txId + QString::number(splitId), split.pairs());
+}
+
+// **** Schedules ****
+void MyMoneyStorageSql::writeSchedules() {
+ DBG("*** Entering MyMoneyStorageSql::writeSchedules");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ q.prepare("SELECT id FROM kmmSchedules;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Schedule list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ const QValueList<MyMoneySchedule> list = m_storage->scheduleList();
+ QValueList<MyMoneySchedule>::ConstIterator it;
+ MyMoneySqlQuery q2(this);
+ //TODO: find a way to prepare the queries outside of the loop. writeSchedule()
+ // modifies the query passed to it, so they have to be re-prepared every pass.
+ signalProgress(0, list.count(), "Writing Schedules...");
+ for(it = list.begin(); it != list.end(); ++it) {
+ q.prepare (m_db.m_tables["kmmSchedules"].updateString());
+ q2.prepare (m_db.m_tables["kmmSchedules"].insertString());
+ bool insert = true;
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ insert = false;
+ writeSchedule(*it, q, insert);
+ } else {
+ writeSchedule(*it, q2, insert);
+ }
+ signalProgress(++m_schedules, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ QValueList<QString>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ deleteSchedule(*it);
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addSchedule(const MyMoneySchedule& sched) {
+ DBG("*** Entering MyMoneyStorageSql::addSchedule");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmSchedules"].insertString());
+ writeSchedule(sched,q, true);
+ ++m_schedules;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifySchedule(const MyMoneySchedule& sched) {
+ DBG("*** Entering MyMoneyStorageSql::modifySchedule");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmSchedules"].updateString());
+ writeSchedule(sched,q, false);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeSchedule(const MyMoneySchedule& sched) {
+ DBG("*** Entering MyMoneyStorageSql::removeSchedule");
+ startCommitUnit(__func__);
+ deleteSchedule(sched.id());
+ --m_schedules;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::deleteSchedule (const QString& id) {
+ DBG("*** Entering MyMoneyStorageSql::deleteSchedule");
+ deleteTransaction(id);
+ MyMoneySqlQuery q(this);
+ q.prepare("DELETE FROM kmmSchedulePaymentHistory WHERE schedId = :id");
+ q.bindValue(":id", id);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Schedule Payment History"));
+ q.prepare(m_db.m_tables["kmmSchedules"].deleteString());
+ q.bindValue(":id", id);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Schedule"));
+ //FIXME: enable when schedules have KVPs.
+ //deleteKeyValuePairs("SCHEDULE", id);
+}
+
+void MyMoneyStorageSql::writeSchedule(const MyMoneySchedule& sch, MyMoneySqlQuery& q, bool insert) {
+ DBG("*** Entering MyMoneyStorageSql::writeSchedule");
+ q.bindValue(":id", sch.id());
+ q.bindValue(":name", sch.name());
+ q.bindValue(":type", sch.type());
+ q.bindValue(":typeString", MyMoneySchedule::scheduleTypeToString(sch.type()));
+ q.bindValue(":occurence", sch.occurencePeriod());
+ q.bindValue(":occurenceMultiplier", sch.occurenceMultiplier());
+ q.bindValue(":occurenceString", sch.occurenceToString());
+ q.bindValue(":paymentType", sch.paymentType());
+ q.bindValue(":paymentTypeString", MyMoneySchedule::paymentMethodToString(sch.paymentType()));
+ q.bindValue(":startDate", sch.startDate().toString(Qt::ISODate));
+ q.bindValue(":endDate", sch.endDate().toString(Qt::ISODate));
+ if (sch.isFixed()) {
+ q.bindValue(":fixed", "Y");
+ } else {
+ q.bindValue(":fixed", "N");
+ }
+ if (sch.autoEnter()) {
+ q.bindValue(":autoEnter", "Y");
+ } else {
+ q.bindValue(":autoEnter", "N");
+ }
+ q.bindValue(":lastPayment", sch.lastPayment());
+ q.bindValue(":nextPaymentDue", sch.nextDueDate().toString(Qt::ISODate));
+ q.bindValue(":weekendOption", sch.weekendOption());
+ q.bindValue(":weekendOptionString", MyMoneySchedule::weekendOptionToString(sch.weekendOption()));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Schedules")));
+
+ //store the payment history for this scheduled task.
+ //easiest way is to delete all and re-insert; it's not a high use table
+ q.prepare("DELETE FROM kmmSchedulePaymentHistory WHERE schedId = :id;");
+ q.bindValue(":id", sch.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Schedule Payment History")));
+
+ q.prepare (m_db.m_tables["kmmSchedulePaymentHistory"].insertString());
+ QValueList<QDate> payments = sch.recordedPayments();
+ QValueList<QDate>::ConstIterator it;
+ for (it=payments.begin(); it!=payments.end(); ++it) {
+ q.bindValue(":schedId", sch.id());
+ q.bindValue(":payDate", (*it).toString(Qt::ISODate));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Schedule Payment History")));
+ }
+
+ //store the transaction data for this task.
+ if (!insert) {
+ q.prepare (m_db.m_tables["kmmTransactions"].updateString());
+ } else {
+ q.prepare (m_db.m_tables["kmmTransactions"].insertString());
+ }
+ writeTransaction(sch.id(), sch.transaction(), q, "S");
+
+ //FIXME: enable when schedules have KVPs.
+
+ //Add in Key-Value Pairs for transactions.
+ //deleteKeyValuePairs("SCHEDULE", sch.id());
+ //writeKeyValuePairs("SCHEDULE", sch.id(), sch.pairs());
+ m_hiIdSchedules = calcHighId(m_hiIdSchedules, sch.id());
+}
+
+// **** Securities ****
+void MyMoneyStorageSql::writeSecurities() {
+ DBG("*** Entering MyMoneyStorageSql::writeSecurities");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ MyMoneySqlQuery q2(this);
+ q.prepare("SELECT id FROM kmmSecurities;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building security list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ const QValueList<MyMoneySecurity> securityList = m_storage->securityList();
+ signalProgress(0, securityList.count(), "Writing Securities...");
+ q.prepare (m_db.m_tables["kmmSecurities"].updateString());
+ q2.prepare (m_db.m_tables["kmmSecurities"].insertString());
+ for(QValueList<MyMoneySecurity>::ConstIterator it = securityList.begin(); it != securityList.end(); ++it) {
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writeSecurity((*it), q);
+ } else {
+ writeSecurity((*it), q2);
+ }
+ signalProgress(++m_securities, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ q.prepare("DELETE FROM kmmSecurities WHERE id = :id");
+ q2.prepare("DELETE FROM kmmPrices WHERE fromId = :id OR toId = :id");
+ QValueList<QString>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ q.bindValue(":id", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Security"));
+ q2.bindValue(":fromId", (*it));
+ q2.bindValue(":toId", (*it));
+ if (!q2.exec()) throw new MYMONEYEXCEPTION(buildError (q2, __func__, "deleting Security"));
+ deleteKeyValuePairs("SECURITY", (*it));
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addSecurity(const MyMoneySecurity& sec) {
+ DBG("*** Entering MyMoneyStorageSql::addSecurity");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmSecurities"].insertString());
+ writeSecurity(sec,q);
+ ++m_securities;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifySecurity(const MyMoneySecurity& sec) {
+ DBG("*** Entering MyMoneyStorageSql::modifySecurity");
+ startCommitUnit(__func__);
+ deleteKeyValuePairs("SECURITY", sec.id());
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmSecurities"].updateString());
+ writeSecurity(sec,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeSecurity(const MyMoneySecurity& sec) {
+ DBG("*** Entering MyMoneyStorageSql::removeSecurity");
+ startCommitUnit(__func__);
+ deleteKeyValuePairs("SECURITY", sec.id());
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmSecurities"].deleteString());
+ q.bindValue(":id", sec.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Security")));
+ --m_securities;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writeSecurity(const MyMoneySecurity& security, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeSecurity");
+ q.bindValue(":id", security.id());
+ q.bindValue(":name", security.name());
+ q.bindValue(":symbol", security.tradingSymbol());
+ q.bindValue(":type", static_cast<int>(security.securityType()));
+ q.bindValue(":typeString", MyMoneySecurity::securityTypeToString(security.securityType()));
+ q.bindValue(":smallestAccountFraction", security.smallestAccountFraction());
+ q.bindValue(":tradingCurrency", security.tradingCurrency());
+ q.bindValue(":tradingMarket", security.tradingMarket());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString ("writing Securities")));
+
+ //Add in Key-Value Pairs for security
+ writeKeyValuePairs("SECURITY", security.id(), security.pairs());
+ m_hiIdSecurities = calcHighId(m_hiIdSecurities, security.id());
+}
+
+// **** Prices ****
+void MyMoneyStorageSql::writePrices() {
+ DBG("*** Entering MyMoneyStorageSql::writePrices");
+ // due to difficulties in matching and determining deletes
+ // easiest way is to delete all and re-insert
+ MyMoneySqlQuery q(this);
+ q.prepare("DELETE FROM kmmPrices");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Prices")));
+ m_prices = 0;
+
+ const MyMoneyPriceList list = m_storage->priceList();
+ signalProgress(0, list.count(), "Writing Prices...");
+ MyMoneyPriceList::ConstIterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ writePricePair(*it);
+ }
+}
+
+void MyMoneyStorageSql::writePricePair(const MyMoneyPriceEntries& p) {
+ DBG("*** Entering MyMoneyStorageSql::writePricePair");
+ MyMoneyPriceEntries::ConstIterator it;
+ for(it = p.begin(); it != p.end(); ++it) {
+ writePrice (*it);
+ signalProgress(++m_prices, 0);
+ }
+}
+
+void MyMoneyStorageSql::addPrice(const MyMoneyPrice& p) {
+ DBG("*** Entering MyMoneyStorageSql::addPrice");
+ if (m_readingPrices) return;
+ // the app always calls addPrice, whether or not there is already one there
+ startCommitUnit(__func__);
+ bool newRecord = false;
+ MyMoneySqlQuery q(this);
+ QString s = m_db.m_tables["kmmPrices"].selectAllString(false);
+ s += " WHERE fromId = :fromId AND toId = :toId AND priceDate = :priceDate;";
+ q.prepare (s);
+ q.bindValue(":fromId", p.from());
+ q.bindValue(":toId", p.to());
+ q.bindValue(":priceDate", p.date().toString(Qt::ISODate));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("finding Price")));
+ if (q.next()) {
+ q.prepare(m_db.m_tables["kmmPrices"].updateString());
+ } else {
+ q.prepare(m_db.m_tables["kmmPrices"].insertString());
+ ++m_prices;
+ newRecord = true;
+ }
+ q.bindValue(":fromId", p.from());
+ q.bindValue(":toId", p.to());
+ q.bindValue(":priceDate", p.date().toString(Qt::ISODate));
+ q.bindValue(":price", p.rate(QString()).toString());
+ q.bindValue(":priceFormatted",
+ p.rate(QString()).formatMoney("", KMyMoneySettings::pricePrecision()));
+ q.bindValue(":priceSource", p.source());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Price")));
+
+ if (newRecord) writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removePrice(const MyMoneyPrice& p) {
+ DBG("*** Entering MyMoneyStorageSql::removePrice");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmPrices"].deleteString());
+ q.bindValue(":fromId", p.from());
+ q.bindValue(":toId", p.to());
+ q.bindValue(":priceDate", p.date().toString(Qt::ISODate));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Price")));
+ --m_prices;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writePrice(const MyMoneyPrice& p) {
+ DBG("*** Entering MyMoneyStorageSql::writePrice");
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmPrices"].insertString());
+ q.bindValue(":fromId", p.from());
+ q.bindValue(":toId", p.to());
+ q.bindValue(":priceDate", p.date().toString(Qt::ISODate));
+ q.bindValue(":price", p.rate(QString()).toString());
+ q.bindValue(":priceFormatted", p.rate(QString()).formatMoney("", 2));
+ q.bindValue(":priceSource", p.source());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Prices")));
+}
+
+// **** Currencies ****
+void MyMoneyStorageSql::writeCurrencies() {
+ DBG("*** Entering MyMoneyStorageSql::writeCurrencies");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ MyMoneySqlQuery q2(this);
+ q.prepare("SELECT ISOCode FROM kmmCurrencies;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Currency list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ const QValueList<MyMoneySecurity> currencyList = m_storage->currencyList();
+ signalProgress(0, currencyList.count(), "Writing Currencies...");
+ q.prepare (m_db.m_tables["kmmCurrencies"].updateString());
+ q2.prepare (m_db.m_tables["kmmCurrencies"].insertString());
+ for(QValueList<MyMoneySecurity>::ConstIterator it = currencyList.begin(); it != currencyList.end(); ++it) {
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writeCurrency((*it), q);
+ } else {
+ writeCurrency((*it), q2);
+ }
+ signalProgress(++m_currencies, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ q.prepare("DELETE FROM kmmCurrencies WHERE ISOCode = :ISOCode");
+ QValueList<QString>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ q.bindValue(":ISOCode", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Currency"));
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addCurrency(const MyMoneySecurity& sec) {
+ DBG("*** Entering MyMoneyStorageSql::addCurrency");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmCurrencies"].insertString());
+ writeCurrency(sec,q);
+ ++m_currencies;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyCurrency(const MyMoneySecurity& sec) {
+ DBG("*** Entering MyMoneyStorageSql::modifyCurrency");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmCurrencies"].updateString());
+ writeCurrency(sec,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeCurrency(const MyMoneySecurity& sec) {
+ DBG("*** Entering MyMoneyStorageSql::removeCurrency");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmCurrencies"].deleteString());
+ q.bindValue(":ISOcode", sec.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Currency")));
+ --m_currencies;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writeCurrency(const MyMoneySecurity& currency, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeCurrency");
+ q.bindValue(":ISOcode", currency.id());
+ q.bindValue(":name", currency.name());
+ q.bindValue(":type", static_cast<int>(currency.securityType()));
+ q.bindValue(":typeString", MyMoneySecurity::securityTypeToString(currency.securityType()));
+ // writing the symbol as three short ints is a PITA, but the
+ // problem is that database drivers have incompatible ways of declaring UTF8
+ QString symbol = currency.tradingSymbol() + " ";
+ q.bindValue(":symbol1", symbol.mid(0,1).unicode()->unicode());
+ q.bindValue(":symbol2", symbol.mid(1,1).unicode()->unicode());
+ q.bindValue(":symbol3", symbol.mid(2,1).unicode()->unicode());
+ q.bindValue(":symbolString", symbol);
+ q.bindValue(":partsPerUnit", currency.partsPerUnit());
+ q.bindValue(":smallestCashFraction", currency.smallestCashFraction());
+ q.bindValue(":smallestAccountFraction", currency.smallestAccountFraction());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Currencies")));
+}
+
+
+void MyMoneyStorageSql::writeReports() {
+ DBG("*** Entering MyMoneyStorageSql::writeReports");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ MyMoneySqlQuery q2(this);
+ q.prepare("SELECT id FROM kmmReportConfig;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Report list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ QValueList<MyMoneyReport> list = m_storage->reportList();
+ signalProgress(0, list.count(), "Writing Reports...");
+ QValueList<MyMoneyReport>::ConstIterator it;
+ q.prepare (m_db.m_tables["kmmReportConfig"].updateString());
+ q2.prepare (m_db.m_tables["kmmReportConfig"].insertString());
+ for(it = list.begin(); it != list.end(); ++it){
+ if (dbList.contains((*it).id())) {
+ dbList.remove ((*it).id());
+ writeReport(*it, q);
+ } else {
+ writeReport(*it, q2);
+ }
+ signalProgress(++m_reports, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ q.prepare("DELETE FROM kmmReportConfig WHERE id = :id");
+ QValueList<QString>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ q.bindValue(":id", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Report"));
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addReport(const MyMoneyReport& rep) {
+ DBG("*** Entering MyMoneyStorageSql::addReport");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmReportConfig"].insertString());
+ writeReport(rep,q);
+ ++m_reports;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyReport(const MyMoneyReport& rep) {
+ DBG("*** Entering MyMoneyStorageSql::modifyReport");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmReportConfig"].updateString());
+ writeReport(rep,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeReport(const MyMoneyReport& rep) {
+ DBG("*** Entering MyMoneyStorageSql::removeReport");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare("DELETE FROM kmmReportConfig WHERE id = :id");
+ q.bindValue(":id", rep.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Report")));
+ --m_reports;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writeReport (const MyMoneyReport& rep, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeReport");
+ QDomDocument d; // create a dummy XML document
+ QDomElement e = d.createElement("REPORTS");
+ d.appendChild (e);
+ rep.writeXML(d, e); // write the XML to document
+ q.bindValue(":id", rep.id());
+ q.bindValue(":name", rep.name());
+ q.bindValue(":XML", d.toString());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Reports")));
+ //m_hiIdReports = calcHighId(m_hiIdReports, rep.id());
+}
+
+void MyMoneyStorageSql::writeBudgets() {
+ DBG("*** Entering MyMoneyStorageSql::writeBudgets");
+ // first, get a list of what's on the database (see writeInstitutions)
+ QValueList<QString> dbList;
+ MyMoneySqlQuery q(this);
+ MyMoneySqlQuery q2(this);
+ q.prepare("SELECT name FROM kmmBudgetConfig;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "building Budget list"));
+ while (q.next()) dbList.append(q.value(0).toString());
+
+ QValueList<MyMoneyBudget> list = m_storage->budgetList();
+ signalProgress(0, list.count(), "Writing Budgets...");
+ QValueList<MyMoneyBudget>::ConstIterator it;
+ q.prepare (m_db.m_tables["kmmBudgetConfig"].updateString());
+ q2.prepare (m_db.m_tables["kmmBudgetConfig"].insertString());
+ for(it = list.begin(); it != list.end(); ++it){
+ if (dbList.contains((*it).name())) {
+ dbList.remove ((*it).name());
+ writeBudget(*it, q);
+ } else {
+ writeBudget(*it, q2);
+ }
+ signalProgress(++m_budgets, 0);
+ }
+
+ if (!dbList.isEmpty()) {
+ q.prepare("DELETE FROM kmmBudgetConfig WHERE id = :id");
+ QValueList<QString>::const_iterator it = dbList.begin();
+ while (it != dbList.end()) {
+ q.bindValue(":name", (*it));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "deleting Budget"));
+ ++it;
+ }
+ }
+}
+
+void MyMoneyStorageSql::addBudget(const MyMoneyBudget& bud) {
+ DBG("*** Entering MyMoneyStorageSql::addBudget");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmBudgetConfig"].insertString());
+ writeBudget(bud,q);
+ ++m_budgets;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::modifyBudget(const MyMoneyBudget& bud) {
+ DBG("*** Entering MyMoneyStorageSql::modifyBudget");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmBudgetConfig"].updateString());
+ writeBudget(bud,q);
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::removeBudget(const MyMoneyBudget& bud) {
+ DBG("*** Entering MyMoneyStorageSql::removeBudget");
+ startCommitUnit(__func__);
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmBudgetConfig"].deleteString());
+ q.bindValue(":id", bud.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting Budget")));
+ --m_budgets;
+ writeFileInfo();
+ endCommitUnit(__func__);
+}
+
+void MyMoneyStorageSql::writeBudget (const MyMoneyBudget& bud, MyMoneySqlQuery& q) {
+ DBG("*** Entering MyMoneyStorageSql::writeBudget");
+ QDomDocument d; // create a dummy XML document
+ QDomElement e = d.createElement("BUDGETS");
+ d.appendChild (e);
+ bud.writeXML(d, e); // write the XML to document
+ q.bindValue(":id", bud.id());
+ q.bindValue(":name", bud.name());
+ q.bindValue(":start", bud.budgetStart());
+ q.bindValue(":XML", d.toString());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing Budgets")));
+}
+
+void MyMoneyStorageSql::writeFileInfo() {
+ DBG("*** Entering MyMoneyStorageSql::writeFileInfo");
+ // we have no real way of knowing when these change, so re-write them every time
+ deleteKeyValuePairs("STORAGE", "");
+ writeKeyValuePairs("STORAGE", "", m_storage->pairs());
+ //
+ MyMoneySqlQuery q(this);
+ q.prepare ("SELECT * FROM kmmFileInfo;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, "checking fileinfo"));
+ QString qs;
+ if (q.next())
+ qs = m_db.m_tables["kmmFileInfo"].updateString();
+ else
+ qs = (m_db.m_tables["kmmFileInfo"].insertString());
+ q.prepare(qs);
+ q.bindValue(":version", m_dbVersion);
+ q.bindValue(":fixLevel", m_storage->fileFixVersion());
+ q.bindValue(":created", m_storage->creationDate().toString(Qt::ISODate));
+ //q.bindValue(":lastModified", m_storage->lastModificationDate().toString(Qt::ISODate));
+ q.bindValue(":lastModified", QDate::currentDate().toString(Qt::ISODate));
+ q.bindValue(":baseCurrency", m_storage->pairs()["kmm-baseCurrency"]);
+ q.bindValue(":institutions", (unsigned long long) m_institutions);
+ q.bindValue(":accounts", (unsigned long long) m_accounts);
+ q.bindValue(":payees", (unsigned long long) m_payees);
+ q.bindValue(":transactions", (unsigned long long) m_transactions);
+ q.bindValue(":splits", (unsigned long long) m_splits);
+ q.bindValue(":securities", (unsigned long long) m_securities);
+ q.bindValue(":prices", (unsigned long long) m_prices);
+ q.bindValue(":currencies", (unsigned long long) m_currencies);
+ q.bindValue(":schedules", (unsigned long long) m_schedules);
+ q.bindValue(":reports", (unsigned long long) m_reports);
+ q.bindValue(":kvps", (unsigned long long) m_kvps);
+ q.bindValue(":budgets", (unsigned long long) m_budgets);
+ q.bindValue(":dateRangeStart", QDate());
+ q.bindValue(":dateRangeEnd", QDate());
+
+ //FIXME: This modifies all m_<variable> used in this function.
+ // Sometimes the memory has been updated.
+
+ // Should most of these be tracked in a view?
+ // Variables actually needed are: version, fileFixVersion, creationDate,
+ // baseCurrency, encryption, update info, and logon info.
+ try {
+ //readFileInfo();
+ } catch (...) {
+ startCommitUnit(__func__);
+ }
+
+ q.bindValue(":hiInstitutionId", (unsigned long long) m_hiIdInstitutions);
+ q.bindValue(":hiPayeeId", (unsigned long long) m_hiIdPayees);
+ q.bindValue(":hiAccountId", (unsigned long long) m_hiIdAccounts);
+ q.bindValue(":hiTransactionId", (unsigned long long) m_hiIdTransactions);
+ q.bindValue(":hiScheduleId", (unsigned long long) m_hiIdSchedules);
+ q.bindValue(":hiSecurityId", (unsigned long long) m_hiIdSecurities);
+ q.bindValue(":hiReportId", (unsigned long long) m_hiIdReports);
+ q.bindValue(":hiBudgetId", (unsigned long long) m_hiIdBudgets);
+
+ q.bindValue(":encryptData", m_encryptData);
+ q.bindValue(":updateInProgress", "N");
+ q.bindValue(":logonUser", m_logonUser);
+ q.bindValue(":logonAt", m_logonAt.toString(Qt::ISODate));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing FileInfo")));
+}
+
+// **** Key/value pairs ****
+void MyMoneyStorageSql::writeKeyValuePairs(const QString& kvpType, const QString& kvpId, const QMap<QString, QString>& pairs) {
+ DBG("*** Entering MyMoneyStorageSql::writeKeyValuePairs");
+ QMap<QString, QString>::const_iterator it;
+ for(it = pairs.begin(); it != pairs.end(); ++it) {
+ writeKeyValuePair (kvpType, kvpId, it.key(), it.data());
+ }
+}
+
+void MyMoneyStorageSql::writeKeyValuePair (const QString& kvpType, const QString& kvpId, const QString& kvpKey, const QString& kvpData) {
+ DBG("*** Entering MyMoneyStorageSql::writeKeyValuePair");
+ MyMoneySqlQuery q(this);
+ q.prepare (m_db.m_tables["kmmKeyValuePairs"].insertString());
+ q.bindValue(":kvpType", kvpType);
+ q.bindValue(":kvpId", kvpId);
+ q.bindValue(":kvpKey", kvpKey);
+ q.bindValue(":kvpData", kvpData);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("writing KVP")));
+ ++m_kvps;
+}
+
+void MyMoneyStorageSql::deleteKeyValuePairs (const QString& kvpType, const QString& kvpId) {
+ DBG("*** Entering MyMoneyStorageSql::deleteKeyValuePairs");
+ MyMoneySqlQuery q(this);
+ q.prepare ("DELETE FROM kmmKeyValuePairs WHERE kvpType = :kvpType AND kvpId = :kvpId;");
+ q.bindValue(":kvpType", kvpType);
+ q.bindValue(":kvpId", kvpId);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("deleting kvp for %1 %2").arg(kvpType).arg(kvpId)));
+ m_kvps -= q.numRowsAffected();
+}
+
+//******************************** read SQL routines **************************************
+#define CASE(a) if ((*ft)->name() == #a)
+#define GETSTRING q.value(i).toString()
+#define GETCSTRING q.value(i).toCString()
+#define GETDATE getDate(GETSTRING)
+#define GETDATETIME getDateTime(GETSTRING)
+#define GETINT q.value(i).toInt()
+#define GETULL q.value(i).toULongLong()
+
+void MyMoneyStorageSql::readFileInfo(void) {
+ DBG("*** Entering MyMoneyStorageSql::readFileInfo");
+ signalProgress(0, 18, QObject::tr("Loading file information..."));
+ MyMoneyDbTable& t = m_db.m_tables["kmmFileInfo"];
+ MyMoneySqlQuery q(this);
+ q.prepare (t.selectAllString());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading FileInfo")));
+ if (!q.next()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("retrieving FileInfo")));
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ while (ft != t.end()) {
+ // versioning is now handled in open routine
+/* CASE(version) setVersion(GETSTRING); // check version == current version...
+ else*/
+ CASE(created) m_storage->setCreationDate(GETDATE);
+ else CASE(lastModified) m_storage->setLastModificationDate(GETDATE);
+ else CASE(hiInstitutionId) m_hiIdInstitutions = (unsigned long) GETULL;
+ else CASE(hiPayeeId) m_hiIdPayees = (unsigned long) GETULL;
+ else CASE(hiAccountId) m_hiIdAccounts = (unsigned long) GETULL;
+ else CASE(hiTransactionId) m_hiIdTransactions = (unsigned long) GETULL;
+ else CASE(hiScheduleId) m_hiIdSchedules = (unsigned long) GETULL;
+ else CASE(hiSecurityId) m_hiIdSecurities = (unsigned long) GETULL;
+ else CASE(hiReportId ) m_hiIdReports = (unsigned long) GETULL;
+ else CASE(hiBudgetId ) m_hiIdBudgets = (unsigned long) GETULL;
+ else CASE(institutions) m_institutions = (unsigned long) GETULL;
+ else CASE(accounts ) m_accounts = (unsigned long) GETULL;
+ else CASE(payees ) m_payees = (unsigned long) GETULL;
+ else CASE(transactions) m_transactions = (unsigned long) GETULL;
+ else CASE(splits ) m_splits = (unsigned long) GETULL;
+ else CASE(securities ) m_securities = (unsigned long) GETULL;
+ else CASE(currencies ) m_currencies = (unsigned long) GETULL;
+ else CASE(schedules ) m_schedules = (unsigned long) GETULL;
+ else CASE(prices ) m_prices = (unsigned long) GETULL;
+ else CASE(kvps ) m_kvps = (unsigned long) GETULL;
+ else CASE(reports ) m_reports = (unsigned long) GETULL;
+ else CASE(budgets ) m_budgets = (unsigned long) GETULL;
+ else CASE(encryptData) m_encryptData = GETSTRING;
+ else CASE(logonUser) m_logonUser = GETSTRING;
+ else CASE(logonAt) m_logonAt = GETDATETIME;
+ ++ft; ++i;
+ signalProgress(i,0);
+ }
+ m_storage->setPairs(readKeyValuePairs("STORAGE", QString("")).pairs());
+}
+
+/*void MyMoneyStorageSql::setVersion (const QString& version) {
+ DBG("*** Entering MyMoneyStorageSql::setVersion");
+ m_dbVersion = version.section('.', 0, 0).toUInt();
+ m_minorVersion = version.section('.', 1, 1).toUInt();
+ // Okay, I made a cockup by forgetting to include a fixversion in the database
+ // design, so we'll use the minor version as fix level (similar to VERSION
+ // and FIXVERSION in XML file format). A second mistake was setting minor version to 1
+ // in the first place, so we need to subtract one on reading and add one on writing (sigh)!!
+ m_storage->setFileFixVersion( m_minorVersion - 1);
+}*/
+
+void MyMoneyStorageSql::readInstitutions(void) {
+ TRY
+ QMap<QString, MyMoneyInstitution> iList = fetchInstitutions();
+ m_storage->loadInstitutions(iList);
+ readFileInfo();
+ m_storage->loadInstitutionId(m_hiIdInstitutions);
+ PASS
+}
+
+const QMap<QString, MyMoneyInstitution> MyMoneyStorageSql::fetchInstitutions (const QStringList& idList, bool forUpdate) const {
+ DBG("*** Entering MyMoneyStorageSql::readInstitutions");
+ signalProgress(0, m_institutions, QObject::tr("Loading institutions..."));
+ int progress = 0;
+ QMap<QString, MyMoneyInstitution> iList;
+ unsigned long lastId = 0;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmInstitutions"];
+ MyMoneySqlQuery sq(const_cast <MyMoneyStorageSql*> (this));
+ sq.prepare ("SELECT id from kmmAccounts where institutionId = :id");
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QString queryString (t.selectAllString(false));
+
+ // Use bind variables, instead of just inserting the values in the queryString,
+ // so that values containing a ':' will work.
+ if (! idList.empty()) {
+ queryString += " WHERE";
+ for (unsigned i = 0; i < idList.count(); ++i)
+ queryString += " id = :id" + QString::number(i) + " OR";
+ queryString = queryString.left(queryString.length() - 2);
+ }
+ if (forUpdate)
+ queryString += " FOR UPDATE";
+
+ queryString += ";";
+
+ q.prepare (queryString);
+
+ if (! idList.empty()) {
+ QStringList::const_iterator bindVal = idList.begin();
+ for (int i = 0; bindVal != idList.end(); ++i, ++bindVal) {
+ q.bindValue (":id" + QString::number(i), *bindVal);
+ }
+ }
+
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Institution")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QString iid;
+ MyMoneyInstitution inst;
+ while (ft != t.end()) {
+ CASE(id) iid = GETSTRING;
+ else CASE(name) inst.setName(GETSTRING);
+ else CASE(manager) inst.setManager(GETSTRING);
+ else CASE(routingCode) inst.setSortcode(GETSTRING);
+ else CASE(addressStreet) inst.setStreet(GETSTRING);
+ else CASE(addressCity) inst.setCity(GETSTRING);
+ else CASE(addressZipcode) inst.setPostcode(GETSTRING);
+ else CASE(telephone) inst.setTelephone(GETSTRING);
+ ++ft; ++i;
+ }
+ // get list of subaccounts
+ sq.bindValue(":id", iid);
+ if (!sq.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Institution AccountList")));
+ QStringList aList;
+ while (sq.next()) aList.append(sq.value(0).toString());
+ for (QStringList::ConstIterator it = aList.begin(); it != aList.end(); ++it)
+ inst.addAccountId(*it);
+
+ iList[iid] = MyMoneyInstitution(iid, inst);
+ unsigned long id = extractId(iid);
+ if(id > lastId)
+ lastId = id;
+
+ signalProgress (++progress, 0);
+ }
+ return iList;
+}
+
+void MyMoneyStorageSql::readPayees (const QString& id) {
+ DBG("*** Entering MyMoneyStorageSql::readPayees");
+ QValueList<QString> list;
+ list.append(id);
+ readPayees(list);
+}
+
+void MyMoneyStorageSql::readPayees(const QValueList<QString> pid) {
+ DBG("*** Entering MyMoneyStorageSql::readPayees");
+ TRY
+ QStringList pidList;
+ qCopy(pid.begin(), pid.end(), qBackInserter(pidList));
+
+ m_storage->loadPayees(fetchPayees(pidList));
+ readFileInfo();
+ m_storage->loadPayeeId(m_hiIdPayees);
+ CATCH
+ delete e; // ignore duplicates
+ ECATCH
+// if (pid.isEmpty()) m_payeeListRead = true;
+}
+
+const QMap<QString, MyMoneyPayee> MyMoneyStorageSql::fetchPayees (const QStringList& idList, bool /*forUpdate*/) const {
+ DBG("*** Entering MyMoneyStorageSql::readPayees");
+ if (m_displayStatus) {
+ signalProgress(0, m_payees, QObject::tr("Loading payees..."));
+ } else {
+// if (m_payeeListRead) return;
+ }
+ int progress = 0;
+ QMap<QString, MyMoneyPayee> pList;
+ //unsigned long lastId;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmPayees"];
+ MyMoneyDbTable::field_iterator payeeEnd = t.end();
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ if (idList.isEmpty()) {
+ q.prepare (t.selectAllString());
+ } else {
+ QString whereClause = " where (";
+ QString itemConnector = "";
+ QStringList::ConstIterator it;
+ for (it = idList.begin(); it != idList.end(); ++it) {
+ whereClause.append(QString("%1id = '%2'").arg(itemConnector).arg(*it));
+ itemConnector = " or ";
+ }
+ whereClause += ")";
+ q.prepare (t.selectAllString(false) + whereClause);
+ }
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Payee")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QString pid;
+ QString boolChar;
+ MyMoneyPayee payee;
+ unsigned int type;
+ bool ignoreCase;
+ QString matchKeys;
+ while (ft != payeeEnd) {
+ CASE(id) pid = GETCSTRING;
+ else CASE(name) payee.setName(GETSTRING);
+ else CASE(reference) payee.setReference(GETSTRING);
+ else CASE(email) payee.setEmail(GETSTRING);
+ else CASE(addressStreet) payee.setAddress(GETSTRING);
+ else CASE(addressCity) payee.setCity(GETSTRING);
+ else CASE(addressZipcode) payee.setPostcode(GETSTRING);
+ else CASE(addressState) payee.setState(GETSTRING);
+ else CASE(telephone) payee.setTelephone(GETSTRING);
+ else CASE(notes) payee.setNotes(GETSTRING);
+ else CASE(defaultAccountId) payee.setDefaultAccountId(GETSTRING);
+ else CASE(matchData) type = GETINT;
+ else CASE(matchIgnoreCase) ignoreCase = (GETSTRING == "Y");
+ else CASE(matchKeys) matchKeys = GETSTRING;
+ ++ft; ++i;
+ }
+ payee.setMatchData (static_cast<MyMoneyPayee::payeeMatchType>(type), ignoreCase, matchKeys);
+ if (pid == "USER") {
+ TRY
+ m_storage->setUser(payee);
+ PASS
+ } else {
+ pList[pid] = MyMoneyPayee(pid, payee);
+ //unsigned long id = extractId(QString(pid));
+ //if(id > lastId)
+ // lastId = id;
+ }
+ if (m_displayStatus) signalProgress(++progress, 0);
+ }
+ return pList;
+}
+
+const QMap<QString, MyMoneyAccount> MyMoneyStorageSql::fetchAccounts (const QStringList& idList, bool forUpdate) const {
+ DBG("*** Entering MyMoneyStorageSql::fetchAccounts");
+ signalProgress(0, m_accounts, QObject::tr("Loading accounts..."));
+ int progress = 0;
+ QMap<QString, MyMoneyAccount> accList;
+ QStringList kvpAccountList;
+
+ const MyMoneyDbTable& t = m_db.m_tables["kmmAccounts"];
+ MyMoneyDbTable::field_iterator accEnd = t.end();
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ MyMoneySqlQuery sq(const_cast <MyMoneyStorageSql*> (this));
+
+ QString childQueryString = "SELECT id, parentId FROM kmmAccounts WHERE ";
+ QString queryString (t.selectAllString(false));
+
+ // Use bind variables, instead of just inserting the values in the queryString,
+ // so that values containing a ':' will work.
+ if (! idList.empty()) {
+ kvpAccountList = idList;
+ queryString += " WHERE id IN (";
+ childQueryString += " parentId IN (";
+ for (unsigned i = 0; i < idList.count(); ++i) {
+ queryString += " :id" + QString::number(i) + ", ";
+ childQueryString += ":id" + QString::number(i) + ", ";
+ }
+ queryString = queryString.left(queryString.length() - 2) + ")";
+ childQueryString = childQueryString.left(childQueryString.length() - 2) + ")";
+ } else {
+ childQueryString += " NOT parentId IS NULL";
+ }
+
+ queryString += " ORDER BY id";
+ childQueryString += " ORDER BY parentid, id";
+
+ if (forUpdate) {
+ queryString += " FOR UPDATE";
+ childQueryString += " FOR UPDATE";
+ }
+
+ q.prepare (queryString);
+ sq.prepare (childQueryString);
+
+ if (! idList.empty()) {
+ QStringList::const_iterator bindVal = idList.begin();
+ for (int i = 0; bindVal != idList.end(); ++i, ++bindVal) {
+ q.bindValue (":id" + QString::number(i), *bindVal);
+ sq.bindValue (":id" + QString::number(i), *bindVal);
+ }
+ }
+
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Account")));
+ if (!sq.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading subAccountList")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QString aid;
+ QString balance;
+ MyMoneyAccount acc;
+
+ while (ft != accEnd) {
+ CASE(id) aid = GETCSTRING;
+ else CASE(institutionId) acc.setInstitutionId(GETCSTRING);
+ else CASE(parentId) acc.setParentAccountId(GETCSTRING);
+ else CASE(lastReconciled) acc.setLastReconciliationDate(GETDATE);
+ else CASE(lastModified) acc.setLastModified(GETDATE);
+ else CASE(openingDate) acc.setOpeningDate(GETDATE);
+ else CASE(accountNumber) acc.setNumber(GETSTRING);
+ else CASE(accountType) acc.setAccountType(static_cast<MyMoneyAccount::accountTypeE>(GETINT));
+ else CASE(accountName) acc.setName(GETSTRING);
+ else CASE(description) acc.setDescription(GETSTRING);
+ else CASE(currencyId) acc.setCurrencyId(GETCSTRING);
+ else CASE(balance) acc.setBalance(GETSTRING);
+ else CASE(transactionCount)
+ const_cast <MyMoneyStorageSql*> (this)->m_transactionCountMap[aid] = (unsigned long) GETULL;
+ ++ft; ++i;
+ }
+
+ // Process any key value pair
+ if (idList.empty())
+ kvpAccountList.append(aid);
+
+ // in database mode, load the balance from the account record
+ // else we would need to read all the transactions
+ accList.insert(aid, MyMoneyAccount(aid, acc));
+ if (acc.value("PreferredAccount") == "Yes") {
+ const_cast <MyMoneyStorageSql*> (this)->m_preferred.addAccount(aid);
+ }
+ signalProgress(++progress, 0);
+ }
+
+ QMapIterator<QString, MyMoneyAccount> it_acc;
+ QMapIterator<QString, MyMoneyAccount> accListEnd = accList.end();
+ while (sq.next()) {
+ it_acc = accList.find(sq.value(1).toString());
+ if (it_acc != accListEnd && it_acc.data().id() == sq.value(1).toString()) {
+ while (sq.isValid() && it_acc != accListEnd
+ && it_acc.data().id() == sq.value(1).toString()) {
+ it_acc.data().addAccountId(sq.value(0).toString());
+ sq.next();
+ }
+ sq.prev();
+ }
+ }
+
+ //TODO: There should be a better way than this. What's below is O(n log n) or more,
+ // where it may be able to be done in O(n), if things are just right.
+ // The operator[] call in the loop is the most expensive call in this function, according
+ // to several profile runs.
+ QMap <QString, MyMoneyKeyValueContainer> kvpResult = readKeyValuePairs("ACCOUNT", kvpAccountList);
+ QMap <QString, MyMoneyKeyValueContainer>::const_iterator kvp_end = kvpResult.end();
+ for (QMap <QString, MyMoneyKeyValueContainer>::const_iterator it_kvp = kvpResult.begin();
+ it_kvp != kvp_end; ++it_kvp) {
+ accList[it_kvp.key()].setPairs(it_kvp.data().pairs());
+ }
+
+ kvpResult = readKeyValuePairs("ONLINEBANKING", kvpAccountList);
+ kvp_end = kvpResult.end();
+ for (QMap <QString, MyMoneyKeyValueContainer>::const_iterator it_kvp = kvpResult.begin();
+ it_kvp != kvp_end; ++it_kvp) {
+ accList[it_kvp.key()].setOnlineBankingSettings(it_kvp.data());
+ }
+
+ return accList;
+}
+
+void MyMoneyStorageSql::readAccounts(void) {
+ m_storage->loadAccounts(fetchAccounts());
+ m_storage->loadAccountId(m_hiIdAccounts);
+}
+
+const QMap<QString, MyMoneyMoney> MyMoneyStorageSql::fetchBalance(const QStringList& idList, const QDate& date) const {
+
+ QMap<QString, MyMoneyMoney> returnValue;
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QString queryString = "SELECT action, shares, accountId, postDate "
+ "FROM kmmSplits WHERE txType = 'N' AND accountId in (";
+
+ for (unsigned i = 0; i < idList.count(); ++i) {
+ queryString += " :id" + QString::number(i) + ", ";
+ }
+ queryString = queryString.left(queryString.length() - 2) + " )";
+
+ // SQLite stores dates as YYYY-MM-DDTHH:mm:ss with 0s for the time part. This makes
+ // the <= operator misbehave when the date matches. To avoid this, add a day to the
+ // requested date and use the < operator.
+ if (date.isValid() && !date.isNull())
+ queryString += QString(" AND postDate < '%1'").arg(date.addDays(1).toString(Qt::ISODate));
+ DBG (queryString);
+ q.prepare(queryString);
+
+ QStringList::const_iterator bindVal = idList.begin();
+ for (int i = 0; bindVal != idList.end(); ++i, ++bindVal) {
+ q.bindValue (":id" + QString::number(i), *bindVal);
+ returnValue[*bindVal] = MyMoneyMoney(0);
+ }
+ if (!q.exec())
+ throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("fetching balance")));
+ QString id;
+ QString shares;
+ QString action;
+ while (q.next()) {
+ id = q.value(2).toString();
+ shares = q.value(1).toString();
+ action = q.value(0).toString();
+ if (MyMoneySplit::ActionSplitShares == action)
+ returnValue[id] = returnValue[id] * MyMoneyMoney(shares);
+ else
+ returnValue[id] += MyMoneyMoney(shares);
+ }
+ return returnValue;
+}
+
+void MyMoneyStorageSql::readTransactions(const QString& tidList, const QString& dateClause) {
+ TRY
+ m_storage->loadTransactions(fetchTransactions(tidList, dateClause));
+ m_storage->loadTransactionId(m_hiIdTransactions);
+ PASS
+}
+
+void MyMoneyStorageSql::readTransactions(const MyMoneyTransactionFilter& filter) {
+ TRY
+ m_storage->loadTransactions(fetchTransactions(filter));
+ m_storage->loadTransactionId(m_hiIdTransactions);
+ PASS
+}
+
+const QMap<QString, MyMoneyTransaction> MyMoneyStorageSql::fetchTransactions (const QString& tidList, const QString& dateClause, bool /*forUpdate*/) const {
+ DBG("*** Entering MyMoneyStorageSql::readTransactions");
+// if (m_transactionListRead) return; // all list already in memory
+ if (m_displayStatus) signalProgress(0, m_transactions, QObject::tr("Loading transactions..."));
+ int progress = 0;
+// m_payeeList.clear();
+ QString whereClause;
+ whereClause = " WHERE txType = 'N' ";
+ if (! tidList.isEmpty()) {
+ whereClause += " AND id IN " + tidList;
+ }
+ if (!dateClause.isEmpty()) whereClause += " and " + dateClause;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmTransactions"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare (t.selectAllString(false) + whereClause + " ORDER BY id;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Transaction")));
+ const MyMoneyDbTable& ts = m_db.m_tables["kmmSplits"];
+ whereClause = " WHERE txType = 'N' ";
+ if (! tidList.isEmpty()) {
+ whereClause += " AND transactionId IN " + tidList;
+ }
+ if (!dateClause.isEmpty()) whereClause += " and " + dateClause;
+ MyMoneySqlQuery qs(const_cast <MyMoneyStorageSql*> (this));
+ QString splitQuery = ts.selectAllString(false) + whereClause
+ + " ORDER BY transactionId, splitId;";
+ qs.prepare (splitQuery);
+ if (!qs.exec()) throw new MYMONEYEXCEPTION(buildError (qs, __func__, "reading Splits"));
+ QString splitTxId = "ZZZ";
+ MyMoneySplit s;
+ if (qs.next()) {
+ splitTxId = qs.value(0).toString();
+ readSplit (s, qs, ts);
+ } else {
+ splitTxId = "ZZZ";
+ }
+ QMap <QString, MyMoneyTransaction> txMap;
+ QStringList txList;
+ MyMoneyDbTable::field_iterator txEnd = t.end();
+ while (q.next()) {
+ MyMoneyTransaction tx;
+ QString txId;
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ while (ft != txEnd) {
+ CASE(id) txId = GETSTRING;
+ else CASE(postDate) tx.setPostDate(GETDATE);
+ else CASE(memo) tx.setMemo(GETSTRING);
+ else CASE(entryDate) tx.setEntryDate(GETDATE);
+ else CASE(currencyId) tx.setCommodity(GETCSTRING);
+ else CASE(bankId) tx.setBankID(GETSTRING);
+ ++ft; ++i;
+ }
+
+ while (txId < splitTxId && splitTxId != "ZZZ") {
+ if (qs.next()) {
+ splitTxId = qs.value(0).toString();
+ readSplit (s, qs, ts);
+ } else {
+ splitTxId = "ZZZ";
+ }
+ }
+
+ while (txId == splitTxId) {
+ tx.addSplit (s);
+ if (qs.next()) {
+ splitTxId = qs.value(0).toString();
+ readSplit (s, qs, ts);
+ } else {
+ splitTxId = "ZZZ";
+ }
+ }
+ // Process any key value pair
+ if (! txId.isEmpty()) {
+ txList.append(txId);
+ tx = MyMoneyTransaction(txId, tx);
+ txMap.insert(tx.uniqueSortKey(), tx);
+ }
+ }
+ QMap <QString, MyMoneyKeyValueContainer> kvpMap = readKeyValuePairs("TRANSACTION", txList);
+ QMap<QString, MyMoneyTransaction> tList;
+ QMapIterator<QString, MyMoneyTransaction> txMapEnd = txMap.end();
+ for (QMapIterator<QString, MyMoneyTransaction> i = txMap.begin();
+ i != txMapEnd; ++i) {
+ i.data().setPairs(kvpMap[i.data().id()].pairs());
+
+ if (m_displayStatus) signalProgress(++progress, 0);
+ }
+
+ if ((tidList.isEmpty()) && (dateClause.isEmpty())) {
+ //qDebug("setting full list read");
+ }
+ return txMap;
+}
+
+int MyMoneyStorageSql::splitState(const MyMoneyTransactionFilter::stateOptionE& state) const
+{
+ int rc = MyMoneySplit::NotReconciled;
+
+ switch(state) {
+ default:
+ case MyMoneyTransactionFilter::notReconciled:
+ break;
+
+ case MyMoneyTransactionFilter::cleared:
+ rc = MyMoneySplit::Cleared;
+ break;
+
+ case MyMoneyTransactionFilter::reconciled:
+ rc = MyMoneySplit::Reconciled;
+ break;
+
+ case MyMoneyTransactionFilter::frozen:
+ rc = MyMoneySplit::Frozen;
+ break;
+ }
+ return rc;
+}
+
+const QMap<QString, MyMoneyTransaction> MyMoneyStorageSql::fetchTransactions (const MyMoneyTransactionFilter& filter) const {
+ DBG("*** Entering MyMoneyStorageSql::readTransactions");
+ // analyze the filter
+// if (m_transactionListRead) return; // all list already in memory
+ // if the filter is restricted to certain accounts/categories
+ // check if we already have them all in memory
+ QStringList accounts;
+ QString inQuery;
+ filter.accounts(accounts);
+ filter.categories(accounts);
+// QStringList::iterator it;
+// bool allAccountsLoaded = true;
+// for (it = accounts.begin(); it != accounts.end(); ++it) {
+// if (m_accountsLoaded.find(*it) == m_accountsLoaded.end()) {
+// allAccountsLoaded = false;
+// break;
+// }
+// }
+// if (allAccountsLoaded) return;
+ /* Some filter combinations do not lend themselves to implementation
+ * in SQL, or are likely to require such extensive reading of the database
+ * as to make it easier to just read everything into memory. */
+ bool canImplementFilter = true;
+ MyMoneyMoney m1, m2;
+ if (filter.amountFilter( m1, m2 )) {
+ alert ("Amount Filter Set");
+ canImplementFilter = false;
+ }
+ QString n1, n2;
+ if (filter.numberFilter(n1, n2)) {
+ alert("Number filter set");
+ canImplementFilter = false;
+ }
+ int t1;
+ if (filter.firstType(t1)) {
+ alert("Type filter set");
+ canImplementFilter = false;
+ }
+// int s1;
+// if (filter.firstState(s1)) {
+// alert("State filter set");
+// canImplementFilter = false;
+// }
+ QRegExp t2;
+ if (filter.textFilter(t2)) {
+ alert("text filter set");
+ canImplementFilter = false;
+ }
+ MyMoneyTransactionFilter::FilterSet s = filter.filterSet();
+ if (s.singleFilter.validityFilter) {
+ alert("Validity filter set");
+ canImplementFilter = false;
+ }
+ if (!canImplementFilter) {
+ QMap<QString, MyMoneyTransaction> transactionList = fetchTransactions();
+ QMap<QString, MyMoneyTransaction>::ConstIterator it_t;
+ QMap<QString, MyMoneyTransaction>::ConstIterator txListEnd = transactionList.end();
+
+ std::remove_if(transactionList.begin(), transactionList.end(), FilterFail(filter, m_storagePtr));
+ return transactionList;
+ }
+
+ bool accountsOnlyFilter = true;
+ bool splitFilterActive = false; // the split filter is active if we are selecting on fields in the split table
+ // get start and end dates
+ QDate start = filter.fromDate();
+ QDate end = filter.toDate();
+ // not entirely sure if the following is correct, but at best, saves a lot of reads, at worst
+ // it only causes us to read a few more transactions that strictly necessary (I think...)
+ if (start == KMyMoneySettings::startDate().date()) start = QDate();
+ bool txFilterActive = ((start != QDate()) || (end != QDate())); // and this for fields in the transaction table
+ if (txFilterActive) accountsOnlyFilter = false;
+
+ QString whereClause = "";
+ QString subClauseconnector = " where txType = 'N' and ";
+ // payees
+ QStringList payees;
+ //filter.payees(payees);
+ if (filter.payees(payees)) {
+ accountsOnlyFilter = false;
+ QString itemConnector = "payeeId in (";
+ QString payeesClause = "";
+ QStringList::const_iterator it;
+ for (it = payees.begin(); it != payees.end(); ++it) {
+ payeesClause.append(QString("%1'%2'")
+ .arg(itemConnector).arg(*it));
+ itemConnector = ", ";
+ }
+ if (!payeesClause.isEmpty()) {
+ whereClause += subClauseconnector + payeesClause + ")";
+ subClauseconnector = " and ";
+ }
+ splitFilterActive = true;
+ }
+
+ // accounts and categories
+ if (!accounts.isEmpty()) {
+ splitFilterActive = true;
+ QString itemConnector = "accountId in (";
+ QString accountsClause = "";
+ QStringList::const_iterator it;
+ for (it = accounts.begin(); it != accounts.end(); ++it) {
+// if (m_accountsLoaded.find(*it) == m_accountsLoaded.end()) {
+ accountsClause.append(QString("%1 '%2'")
+ .arg(itemConnector).arg(*it));
+ itemConnector = ", ";
+ //if (accountsOnlyFilter) m_accountsLoaded.append(*it); // a bit premature...
+// }
+ }
+ if (!accountsClause.isEmpty()) {
+ whereClause += subClauseconnector + accountsClause + ")";
+ subClauseconnector = " and (";
+ }
+ }
+
+ // split states
+ QValueList <int> splitStates;
+ if (filter.states(splitStates)) {
+ splitFilterActive = true;
+ QString itemConnector = " reconcileFlag IN (";
+ QString statesClause = "";
+ for (QValueList<int>::ConstIterator it = splitStates.begin(); it != splitStates.end(); ++it) {
+ statesClause.append(QString(" %1 '%2'")
+ .arg(itemConnector)
+ .arg(splitState(MyMoneyTransactionFilter::stateOptionE(*it))));
+ itemConnector = ",";
+ }
+ if (!statesClause.isEmpty()) {
+ whereClause += subClauseconnector + statesClause + ")";
+ subClauseconnector = " and (";
+ }
+ }
+ // I've given up trying to work out the logic. we keep getting the wrong number of close brackets
+ int obc = whereClause.contains('(');
+ int cbc = whereClause.contains(')');
+ if (cbc > obc) {
+ qFatal("invalid where clause - %s", whereClause.latin1());
+ }
+ while (cbc < obc) {
+ whereClause.append(")");
+ cbc++;
+ }
+ // if the split filter is active, but the where clause is empty
+ // it means we already have all the transactions for the specified filter
+ // in memory, so just exit
+ if ((splitFilterActive) && (whereClause.isEmpty())) {
+ qDebug("all transactions already in storage");
+ return fetchTransactions();
+ }
+
+ // if we have neither a split filter, nor a tx (date) filter
+ // it's effectively a read all
+ if ((!splitFilterActive) && (!txFilterActive)) {
+ //qDebug("reading all transactions");
+ return fetchTransactions();
+ }
+ // build a date clause for the transaction table
+ QString dateClause;
+ QString connector = "";
+ if (end != QDate()) {
+ dateClause = QString("(postDate < '%1')").arg(end.addDays(1).toString(Qt::ISODate));
+ connector = " and ";
+ }
+ if (start != QDate()) {
+ dateClause += QString("%1 (postDate >= '%2')").arg(connector).arg(start.toString(Qt::ISODate));
+ }
+ // now get a list of transaction ids
+ // if we have only a date filter, we need to build the list from the tx table
+ // otherwise we need to build from the split table
+ if (splitFilterActive) {
+ inQuery = QString("(select distinct transactionId from kmmSplits %1)").arg(whereClause);
+ } else {
+ inQuery = QString("(select distinct id from kmmTransactions where %1)").arg(dateClause);
+ txFilterActive = false; // kill off the date filter now
+ }
+
+ return fetchTransactions(inQuery, dateClause);
+ //FIXME: if we have an accounts-only filter, recalc balances on loaded accounts
+}
+
+unsigned long MyMoneyStorageSql::transactionCount (const QString& aid) const {
+ DBG("*** Entering MyMoneyStorageSql::transactionCount");
+ if (aid.length() == 0)
+ return m_transactions;
+ else
+ return m_transactionCountMap[aid];
+}
+
+void MyMoneyStorageSql::readSplit (MyMoneySplit& s, const MyMoneySqlQuery& q, const MyMoneyDbTable& t) const {
+ DBG("*** Entering MyMoneyStorageSql::readSplit");
+ s.clearId();
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ MyMoneyDbTable::field_iterator splitEnd = t.end();
+ int i = 0;
+
+ // Use the QString here instead of CASE, since this is called so often.
+ QString fieldName;
+ while (ft != splitEnd) {
+ fieldName = (*ft)->name();
+ if (fieldName == "payeeId") s.setPayeeId(GETCSTRING);
+ else if (fieldName == "reconcileDate") s.setReconcileDate(GETDATE);
+ else if (fieldName == "action") s.setAction(GETCSTRING);
+ else if (fieldName == "reconcileFlag") s.setReconcileFlag(static_cast<MyMoneySplit::reconcileFlagE>(GETINT));
+ else if (fieldName == "value") s.setValue(MyMoneyMoney(QStringEmpty(GETSTRING)));
+ else if (fieldName == "shares") s.setShares(MyMoneyMoney(QStringEmpty(GETSTRING)));
+ else if (fieldName == "price") s.setPrice(MyMoneyMoney(QStringEmpty(GETSTRING)));
+ else if (fieldName == "memo") s.setMemo(GETSTRING);
+ else if (fieldName == "accountId") s.setAccountId(GETCSTRING);
+ else if (fieldName == "checkNumber") s.setNumber(GETSTRING);
+ //else if (fieldName == "postDate") s.setPostDate(GETDATETIME); // FIXME - when Tom puts date into split object
+ else if (fieldName == "bankId") s.setBankID(GETSTRING);
+ ++ft; ++i;
+ }
+
+ return;
+}
+
+bool MyMoneyStorageSql::isReferencedByTransaction(const QString& id) const {
+ DBG("*** Entering MyMoneyStorageSql::isReferencedByTransaction");
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare("SELECT COUNT(*) FROM kmmTransactions "
+ "INNER JOIN kmmSplits ON kmmTransactions.id = kmmSplits.transactionId "
+ "WHERE kmmTransactions.currencyId = :ID OR kmmSplits.payeeId = :ID "
+ "OR kmmSplits.accountId = :ID");
+ q.bindValue(":ID", id);
+ if ((!q.exec()) || (!q.next())) {
+ buildError (q, __func__, "error retrieving reference count");
+ qFatal("Error retrieving reference count"); // definitely shouldn't happen
+ }
+ return (0 != q.value(0).toULongLong());
+}
+
+void MyMoneyStorageSql::readSchedules(void) {
+
+ TRY
+ m_storage->loadSchedules(fetchSchedules());
+ readFileInfo();
+ m_storage->loadScheduleId(m_hiIdSchedules);
+ PASS
+}
+
+const QMap<QString, MyMoneySchedule> MyMoneyStorageSql::fetchSchedules (const QStringList& idList, bool forUpdate) const {
+ DBG("*** Entering MyMoneyStorageSql::readSchedules");
+ signalProgress(0, m_schedules, QObject::tr("Loading schedules..."));
+ int progress = 0;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmSchedules"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QMap<QString, MyMoneySchedule> sList;
+ //unsigned long lastId = 0;
+ const MyMoneyDbTable& ts = m_db.m_tables["kmmSplits"];
+ MyMoneySqlQuery qs(const_cast <MyMoneyStorageSql*> (this));
+ qs.prepare (ts.selectAllString(false) + " WHERE transactionId = :id ORDER BY splitId;");
+ MyMoneySqlQuery sq(const_cast <MyMoneyStorageSql*> (this));
+ sq.prepare ("SELECT payDate from kmmSchedulePaymentHistory where schedId = :id");
+
+ QString queryString (t.selectAllString(false));
+
+ // Use bind variables, instead of just inserting the values in the queryString,
+ // so that values containing a ':' will work.
+ if (! idList.empty()) {
+ queryString += " WHERE";
+ for (unsigned i = 0; i < idList.count(); ++i)
+ queryString += " id = :id" + QString::number(i) + " OR";
+ queryString = queryString.left(queryString.length() - 2);
+ }
+ queryString += " ORDER BY id;";
+
+ if (forUpdate)
+ queryString += " FOR UPDATE";
+
+ queryString += ";";
+
+ q.prepare (queryString);
+
+ if (! idList.empty()) {
+ QStringList::const_iterator bindVal = idList.begin();
+ for (int i = 0; bindVal != idList.end(); ++i, ++bindVal) {
+ q.bindValue (":id" + QString::number(i), *bindVal);
+ }
+ }
+
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Schedules")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ MyMoneySchedule s;
+ QString sId;
+ QString boolChar;
+ QDate nextPaymentDue;
+ while (ft != t.end()) {
+ CASE(id) sId = GETCSTRING;
+ else CASE(name) s.setName (GETSTRING);
+ else CASE(type) s.setType (static_cast<MyMoneySchedule::typeE>(GETINT));
+ else CASE(occurence) s.setOccurencePeriod (static_cast<MyMoneySchedule::occurenceE>(GETINT));
+ else CASE(occurenceMultiplier) s.setOccurenceMultiplier (GETINT);
+ else CASE(paymentType) s.setPaymentType (static_cast<MyMoneySchedule::paymentTypeE>(GETINT));
+ else CASE(startDate) s.setStartDate (GETDATE);
+ else CASE(endDate) s.setEndDate (GETDATE);
+ else CASE(fixed) {boolChar = GETSTRING; s.setFixed (boolChar == "Y");}
+ else CASE(autoEnter) {boolChar = GETSTRING; s.setAutoEnter (boolChar == "Y");}
+ else CASE(lastPayment) s.setLastPayment (GETDATE);
+ else CASE(weekendOption)
+ s.setWeekendOption (static_cast<MyMoneySchedule::weekendOptionE>(GETINT));
+ else CASE(nextPaymentDue) nextPaymentDue = GETDATE;
+ ++ft; ++i;
+ }
+ // convert simple occurence to compound occurence
+ int mult = s.occurenceMultiplier();
+ MyMoneySchedule::occurenceE occ = s.occurencePeriod();
+ MyMoneySchedule::simpleToCompoundOccurence(mult,occ);
+ s.setOccurencePeriod(occ);
+ s.setOccurenceMultiplier(mult);
+ // now assign the id to the schedule
+ MyMoneySchedule _s(sId, s);
+ s = _s;
+ // read the associated transaction
+// m_payeeList.clear();
+ const MyMoneyDbTable& t = m_db.m_tables["kmmTransactions"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare (t.selectAllString(false) + " WHERE id = :id;");
+ q.bindValue(":id", s.id());
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Scheduled Transaction")));
+ if (!q.next()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("retrieving scheduled transaction")));
+ MyMoneyTransaction tx(s.id(), MyMoneyTransaction());
+ ft = t.begin();
+ i = 0;
+ while (ft != t.end()) {
+ CASE(postDate) tx.setPostDate(GETDATE);
+ else CASE(memo) tx.setMemo(GETSTRING);
+ else CASE(entryDate) tx.setEntryDate(GETDATE);
+ else CASE(currencyId) tx.setCommodity(GETCSTRING);
+ else CASE(bankId) tx.setBankID(GETSTRING);
+ ++ft; ++i;
+ }
+
+ qs.bindValue(":id", s.id());
+ if (!qs.exec()) throw new MYMONEYEXCEPTION(buildError (qs, __func__, "reading Scheduled Splits"));
+ while (qs.next()) {
+ MyMoneySplit sp;
+ readSplit (sp, qs, ts);
+ tx.addSplit (sp);
+ }
+// if (!m_payeeList.isEmpty())
+// readPayees(m_payeeList);
+ // Process any key value pair
+ tx.setPairs(readKeyValuePairs("TRANSACTION", s.id()).pairs());
+
+ // If the transaction doesn't have a post date, setTransaction will reject it.
+ // The old way of handling things was to store the next post date in the schedule object
+ // and set the transaction post date to QDate().
+ // For compatibility, if this is the case, copy the next post date from the schedule object
+ // to the transaction object post date.
+ if (!tx.postDate().isValid()) {
+ tx.setPostDate(nextPaymentDue);
+ }
+
+ s.setTransaction(tx);
+
+ // read in the recorded payments
+ sq.bindValue(":id", s.id());
+ if (!sq.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading schedule payment history")));
+ while (sq.next()) s.recordPayment (sq.value(0).toDate());
+
+ sList[s.id()] = s;
+
+ //FIXME: enable when schedules have KVPs.
+ // s.setPairs(readKeyValuePairs("SCHEDULE", s.id()).pairs());
+
+ //unsigned long id = extractId(s.id().data());
+ //if(id > lastId)
+ // lastId = id;
+
+ signalProgress(++progress, 0);
+ }
+ return sList;
+}
+
+void MyMoneyStorageSql::readSecurities(void) {
+ TRY
+ m_storage->loadSecurities(fetchSecurities());
+ readFileInfo();
+ m_storage->loadSecurityId(m_hiIdSecurities);
+ PASS
+}
+
+const QMap<QString, MyMoneySecurity> MyMoneyStorageSql::fetchSecurities (const QStringList& /*idList*/, bool /*forUpdate*/) const {
+ DBG("*** Entering MyMoneyStorageSql::readSecurities");
+ signalProgress(0, m_securities, QObject::tr("Loading securities..."));
+ int progress = 0;
+ QMap<QString, MyMoneySecurity> sList;
+ unsigned long lastId = 0;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmSecurities"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare (t.selectAllString(false) + " ORDER BY id;");
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Securities")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ MyMoneySecurity e;
+ QString eid;
+ int saf = 0;
+ while (ft != t.end()) {
+ CASE(id) eid = GETSTRING;
+ else CASE(name) e.setName(GETSTRING);
+ else CASE(symbol) e.setTradingSymbol(GETSTRING);
+ else CASE(type) e.setSecurityType(static_cast<MyMoneySecurity::eSECURITYTYPE>(GETINT));
+ else CASE(smallestAccountFraction) saf = GETINT;
+ else CASE(tradingCurrency) e.setTradingCurrency(GETCSTRING);
+ else CASE(tradingMarket) e.setTradingMarket(GETSTRING);
+ ++ft; ++i;
+ }
+ if(e.tradingCurrency().isEmpty())
+ e.setTradingCurrency(m_storage->pairs()["kmm-baseCurrency"]);
+ if(saf == 0)
+ saf = 100;
+ e.setSmallestAccountFraction(saf);
+
+ // Process any key value pairs
+ e.setPairs(readKeyValuePairs("SECURITY", eid).pairs());
+ //tell the storage objects we have a new security object.
+
+ // FIXME: Adapt to new interface make sure, to take care of the currencies as well
+ // see MyMoneyStorageXML::readSecurites()
+ MyMoneySecurity security(eid,e);
+ sList[security.id()] = security;
+
+ unsigned long id = extractId(security.id());
+ if(id > lastId)
+ lastId = id;
+
+ signalProgress(++progress, 0);
+ }
+ return sList;
+}
+
+void MyMoneyStorageSql::readPrices(void) {
+
+ TRY
+// m_storage->addPrice(MyMoneyPrice(from, to, date, rate, source));
+ PASS
+
+}
+
+const MyMoneyPrice MyMoneyStorageSql::fetchSinglePrice (const QString& fromIdList, const QString& toIdList, const QDate& date_, bool exactDate, bool /*forUpdate*/) const {
+ DBG("*** Entering MyMoneyStorageSql::fetchSinglePrice");
+ const MyMoneyDbTable& t = m_db.m_tables["kmmPrices"];
+ MyMoneyDbTable::field_iterator tableEnd = t.end();
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QString queryString = t.selectAllString(false);
+
+ // Use bind variables, instead of just inserting the values in the queryString,
+ // so that values containing a ':' will work.
+ // See balance query for why the date logic seems odd.
+ queryString += " WHERE fromId = :fromId AND toId = :toId AND priceDate < :priceDate ";
+ if (exactDate)
+ queryString += "AND priceDate > :exactDate ";
+
+ queryString += "ORDER BY priceDate DESC;";
+
+ q.prepare(queryString);
+
+ QDate date (date_);
+
+ if(!date.isValid())
+ date = QDate::currentDate();
+
+ q.bindValue(":fromId", fromIdList);
+ q.bindValue(":toId", toIdList);
+ q.bindValue(":priceDate", date.addDays(1).toString(Qt::ISODate));
+
+ if (exactDate)
+ q.bindValue(":exactDate", date.toString(Qt::ISODate));
+
+ if (! q.exec()) {}
+
+ if (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QString from;
+ QString to;
+ QDate date;
+ MyMoneyMoney rate;
+ QString source;
+ bool foundFromId = false;
+ bool foundToId = false;
+ bool foundPriceDate = false;
+ bool foundPrice = false;
+ bool foundPriceSource = false;
+ while (ft != tableEnd) {
+ bool foundSomething = false;
+ if (!foundFromId && !foundSomething) {
+ CASE(fromId) {from = GETCSTRING; foundFromId = true; foundSomething = true;}
+ }
+ if (!foundToId && !foundSomething) {
+ CASE(toId) {to = GETCSTRING; foundToId = true; foundSomething = true;}
+ }
+ if (!foundPriceDate && !foundSomething) {
+ CASE(priceDate) {date = GETDATE; foundPriceDate = true; foundSomething = true;}
+ }
+ if (!foundPrice && !foundSomething) {
+ CASE(price) {rate = GETSTRING; foundPrice = true; foundSomething = true;}
+ }
+ if (!foundPriceSource && !foundSomething) {
+ CASE(priceSource) {source = GETSTRING; foundPriceSource = true; foundSomething = true;}
+ }
+ ++ft; ++i;
+ }
+
+ return MyMoneyPrice(fromIdList, toIdList, date, rate, source);
+ }
+
+ return MyMoneyPrice();
+}
+
+const MyMoneyPriceList MyMoneyStorageSql::fetchPrices (const QStringList& fromIdList, const QStringList& toIdList, bool forUpdate) const {
+ DBG("*** Entering MyMoneyStorageSql::readPrices");
+ signalProgress(0, m_prices, QObject::tr("Loading prices..."));
+ int progress = 0;
+ const_cast <MyMoneyStorageSql*> (this)->m_readingPrices = true;
+ MyMoneyPriceList pList;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmPrices"];
+ MyMoneyDbTable::field_iterator tableEnd = t.end();
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QString queryString = t.selectAllString(false);
+
+ // Use bind variables, instead of just inserting the values in the queryString,
+ // so that values containing a ':' will work.
+ if (! fromIdList.empty()) {
+ queryString += " WHERE (";
+ for (unsigned i = 0; i < fromIdList.count(); ++i) {
+ queryString += " fromId = :fromId" + QString::number(i) + " OR";
+ }
+ queryString = queryString.left(queryString.length() - 2) + ")";
+ }
+ if (! toIdList.empty()) {
+ queryString += " AND (";
+ for (unsigned i = 0; i < toIdList.count(); ++i) {
+ queryString += " toId = :toId" + QString::number(i) + " OR";
+ }
+ queryString = queryString.left(queryString.length() - 2) + ")";
+ }
+
+
+ if (forUpdate)
+ queryString += " FOR UPDATE";
+
+ queryString += ";";
+
+ q.prepare (queryString);
+
+ if (! fromIdList.empty()) {
+ QStringList::const_iterator bindVal = fromIdList.begin();
+ for (int i = 0; bindVal != fromIdList.end(); ++i, ++bindVal) {
+ q.bindValue (":fromId" + QString::number(i), *bindVal);
+ }
+ }
+ if (! toIdList.empty()) {
+ QStringList::const_iterator bindVal = toIdList.begin();
+ for (int i = 0; bindVal != toIdList.end(); ++i, ++bindVal) {
+ q.bindValue (":toId" + QString::number(i), *bindVal);
+ }
+ }
+
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Prices")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QString from;
+ QString to;
+ QDate date;
+ MyMoneyMoney rate;
+ QString source;
+
+ while (ft != tableEnd) {
+ CASE(fromId) from = GETCSTRING;
+ else CASE(toId) to = GETCSTRING;
+ else CASE(priceDate) date = GETDATE;
+ else CASE(price) rate = GETSTRING;
+ else CASE(priceSource) source = GETSTRING;
+ ++ft; ++i;
+ }
+ pList [MyMoneySecurityPair(from, to)].insert(date, MyMoneyPrice(from, to, date, rate, source));
+ signalProgress(++progress, 0);
+ }
+ const_cast <MyMoneyStorageSql*> (this)->m_readingPrices = false;
+
+ return pList;
+}
+
+void MyMoneyStorageSql::readCurrencies(void) {
+ TRY
+ m_storage->loadCurrencies(fetchCurrencies());
+ PASS
+}
+
+const QMap<QString, MyMoneySecurity> MyMoneyStorageSql::fetchCurrencies (const QStringList& idList, bool forUpdate) const {
+ DBG("*** Entering MyMoneyStorageSql::readCurrencies");
+ signalProgress(0, m_currencies, QObject::tr("Loading currencies..."));
+ int progress = 0;
+ QMap<QString, MyMoneySecurity> cList;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmCurrencies"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+
+ QString queryString (t.selectAllString(false));
+
+ // Use bind variables, instead of just inserting the values in the queryString,
+ // so that values containing a ':' will work.
+ if (! idList.empty()) {
+ queryString += " WHERE";
+ for (unsigned i = 0; i < idList.count(); ++i)
+ queryString += " isocode = :id" + QString::number(i) + " OR";
+ queryString = queryString.left(queryString.length() - 2);
+ }
+
+ queryString += " ORDER BY ISOcode";
+
+ if (forUpdate)
+ queryString += " FOR UPDATE";
+
+ queryString += ";";
+
+ q.prepare (queryString);
+
+ if (! idList.empty()) {
+ QStringList::const_iterator bindVal = idList.begin();
+ for (int i = 0; bindVal != idList.end(); ++i, ++bindVal) {
+ q.bindValue (":id" + QString::number(i), *bindVal);
+ }
+ }
+
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Currencies")));
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QString id;
+ MyMoneySecurity c;
+ QChar symbol[3];
+ while (ft != t.end()) {
+ CASE(ISOcode) id = GETCSTRING;
+ else CASE(name) c.setName(GETSTRING);
+ else CASE(type) c.setSecurityType(static_cast<MyMoneySecurity::eSECURITYTYPE>(GETINT));
+ else CASE(symbol1) symbol[0] = QChar(GETINT);
+ else CASE(symbol2) symbol[1] = QChar(GETINT);
+ else CASE(symbol3) symbol[2] = QChar(GETINT);
+ else CASE(partsPerUnit) c.setPartsPerUnit(GETINT);
+ else CASE(smallestCashFraction) c.setSmallestCashFraction(GETINT);
+ else CASE(smallestAccountFraction) c.setSmallestAccountFraction(GETINT);
+ ++ft; ++i;
+ }
+ c.setTradingSymbol(QString(symbol, 3).stripWhiteSpace());
+
+ cList[id] = MyMoneySecurity(id, c);
+
+ signalProgress(++progress, 0);
+ }
+ return cList;
+}
+
+void MyMoneyStorageSql::readReports(void) {
+ TRY
+ m_storage->loadReports(fetchReports());
+ readFileInfo();
+ m_storage->loadReportId(m_hiIdReports);
+ PASS
+}
+
+const QMap<QString, MyMoneyReport> MyMoneyStorageSql::fetchReports (const QStringList& /*idList*/, bool /*forUpdate*/) const {
+ DBG("*** Entering MyMoneyStorageSql::readReports");
+ signalProgress(0, m_reports, QObject::tr("Loading reports..."));
+ int progress = 0;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmReportConfig"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare (t.selectAllString(true));
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading reports")));
+ QMap<QString, MyMoneyReport> rList;
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QDomDocument d;
+ while (ft != t.end()) {
+ CASE(XML) d.setContent(GETSTRING, false);
+ ++ft; ++i;
+ }
+ QDomNode child = d.firstChild();
+ child = child.firstChild();
+ MyMoneyReport report;
+
+ if (report.read(child.toElement()))
+ rList[report.id()] = report;
+
+ signalProgress(++progress, 0);
+ }
+ return rList;
+}
+
+const QMap<QString, MyMoneyBudget> MyMoneyStorageSql::fetchBudgets (const QStringList& idList, bool forUpdate) const {
+ DBG("*** Entering MyMoneyStorageSql::readBudgets");
+ signalProgress(0, m_budgets, QObject::tr("Loading budgets..."));
+ int progress = 0;
+ const MyMoneyDbTable& t = m_db.m_tables["kmmBudgetConfig"];
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QString queryString (t.selectAllString(false));
+ if (! idList.empty()) {
+ queryString += " WHERE id = '" + idList.join("' OR id = '") + "'";
+ }
+ if (forUpdate)
+ queryString += " FOR UPDATE";
+
+ queryString += ";";
+
+ q.prepare (queryString);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading budgets")));
+ QMap<QString, MyMoneyBudget> budgets;
+ while (q.next()) {
+ MyMoneyDbTable::field_iterator ft = t.begin();
+ int i = 0;
+ QDomDocument d;
+ while (ft != t.end()) {
+ CASE(XML) d.setContent(GETSTRING, false);
+ ++ft; ++i;
+ }
+ QDomNode child = d.firstChild();
+ child = child.firstChild();
+ MyMoneyBudget budget (child.toElement());
+ budgets.insert(budget.id(), budget);
+ signalProgress(++progress, 0);
+ }
+ return budgets;
+}
+
+void MyMoneyStorageSql::readBudgets(void) {
+ m_storage->loadBudgets(fetchBudgets());
+}
+
+const MyMoneyKeyValueContainer MyMoneyStorageSql::readKeyValuePairs (const QString& kvpType, const QString& kvpId) const {
+ DBG("*** Entering MyMoneyStorageSql::readKeyValuePairs");
+ MyMoneyKeyValueContainer list;
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ q.prepare ("SELECT kvpKey, kvpData from kmmKeyValuePairs where kvpType = :type and kvpId = :id;");
+ q.bindValue(":type", kvpType);
+ q.bindValue(":id", kvpId);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Kvp for %1 %2").arg(kvpType)
+ .arg(kvpId)));
+ while (q.next()) list.setValue(q.value(0).toString(), q.value(1).toString());
+ return (list);
+}
+
+const QMap<QString, MyMoneyKeyValueContainer> MyMoneyStorageSql::readKeyValuePairs (const QString& kvpType, const QStringList& kvpIdList) const {
+ DBG("*** Entering MyMoneyStorageSql::readKeyValuePairs");
+ QMap<QString, MyMoneyKeyValueContainer> retval;
+
+ MyMoneySqlQuery q(const_cast <MyMoneyStorageSql*> (this));
+ QString query ("SELECT kvpId, kvpKey, kvpData from kmmKeyValuePairs where kvpType = :type");
+
+ if (!kvpIdList.empty()) {
+ query += " and kvpId IN ('" + kvpIdList.join("', '") + "')";
+ }
+
+ query += " order by kvpId;";
+ q.prepare (query);
+ q.bindValue(":type", kvpType);
+ if (!q.exec()) throw new MYMONEYEXCEPTION(buildError (q, __func__, QString("reading Kvp List for %1").arg(kvpType)));
+ while (q.next()) {
+ retval [q.value(0).toString()].setValue(q.value(1).toString(), q.value(2).toString());
+ }
+
+ return (retval);
+}
+
+long unsigned MyMoneyStorageSql::getNextBudgetId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdBudgets;
+}
+
+long unsigned MyMoneyStorageSql::getNextAccountId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdAccounts;
+}
+
+long unsigned MyMoneyStorageSql::getNextInstitutionId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdInstitutions;
+}
+
+long unsigned MyMoneyStorageSql::getNextPayeeId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdPayees;
+}
+
+long unsigned MyMoneyStorageSql::getNextReportId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdReports;
+}
+
+long unsigned MyMoneyStorageSql::getNextScheduleId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdSchedules;
+}
+
+long unsigned MyMoneyStorageSql::getNextSecurityId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdSecurities;
+}
+
+long unsigned MyMoneyStorageSql::getNextTransactionId() const {
+ const_cast <MyMoneyStorageSql*> (this)->readFileInfo();
+ return m_hiIdTransactions;
+}
+
+long unsigned MyMoneyStorageSql::incrementBudgetId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiBudgetId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiBudgetId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdBudgets = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementAccountId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiAccountId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiAccountId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdAccounts = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementInstitutionId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiInstitutionId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiInstitutionId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdInstitutions = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementPayeeId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiPayeeId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiPayeeId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdPayees = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementReportId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiReportId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiReportId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdReports = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementScheduleId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiScheduleId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiScheduleId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdSchedules = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementSecurityId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiSecurityId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiSecurityId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdSecurities = returnValue;
+ return returnValue;
+}
+
+long unsigned MyMoneyStorageSql::incrementTransactionId() {
+ MyMoneySqlQuery q(this);
+
+ startCommitUnit (__func__);
+ q.prepare("SELECT hiTransactionId FROM kmmFileInfo FOR UPDATE");
+ q.exec();
+ q.next();
+ long unsigned returnValue = (unsigned long) q.value(0).toULongLong();
+ ++returnValue;
+ q.prepare("UPDATE kmmFileInfo SET hiTransactionId = " + QString::number(returnValue));
+ q.exec();
+ endCommitUnit (__func__);
+ m_hiIdTransactions = returnValue;
+ return returnValue;
+}
+
+void MyMoneyStorageSql::loadAccountId(const unsigned long& id)
+{
+ m_hiIdAccounts = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadTransactionId(const unsigned long& id)
+{
+ m_hiIdTransactions = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadPayeeId(const unsigned long& id)
+{
+ m_hiIdPayees = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadInstitutionId(const unsigned long& id)
+{
+ m_hiIdInstitutions = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadScheduleId(const unsigned long& id)
+{
+ m_hiIdSchedules = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadSecurityId(const unsigned long& id)
+{
+ m_hiIdSecurities = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadReportId(const unsigned long& id)
+{
+ m_hiIdReports = id;
+ writeFileInfo();
+}
+
+void MyMoneyStorageSql::loadBudgetId(const unsigned long& id)
+{
+ m_hiIdBudgets = id;
+ writeFileInfo();
+}
+
+//****************************************************
+long unsigned MyMoneyStorageSql::calcHighId
+ (const long unsigned& i, const QString& id) {
+ DBG("*** Entering MyMoneyStorageSql::calcHighId");
+ QString nid = id;
+ long unsigned high = (unsigned long) nid.replace(QRegExp("[A-Z]*"), "").toULongLong();
+ return std::max(high, i);
+}
+
+void MyMoneyStorageSql::setProgressCallback(void(*callback)(int, int, const QString&)) {
+ m_progressCallback = callback;
+}
+
+void MyMoneyStorageSql::signalProgress(int current, int total, const QString& msg) const {
+ if (m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+}
+
+// **************************** Error display routine *******************************
+QString& MyMoneyStorageSql::buildError (const QSqlQuery& q, const QString& function, const QString& message) const {
+ QString s = QString("Error in function %1 : %2").arg(function).arg(message);
+ QSqlError e = lastError();
+ s += QString ("\nDriver = %1, Host = %2, User = %3, Database = %4")
+ .arg(driverName()).arg(hostName()).arg(userName()).arg(databaseName());
+ s += QString ("\nDriver Error: %1").arg(e.driverText());
+ s += QString ("\nDatabase Error No %1: %2").arg(e.number()).arg(e.databaseText());
+ e = q.lastError();
+ s += QString ("\nExecuted: %1").arg(q.executedQuery());
+ s += QString ("\nQuery error No %1: %2").arg(e.number()).arg(e.text());
+
+ const_cast <MyMoneyStorageSql*> (this)->m_error = s;
+ qDebug("%s", s.ascii());
+ const_cast <MyMoneyStorageSql*> (this)->cancelCommitUnit(function);
+ return (const_cast <MyMoneyStorageSql*> (this)->m_error);
+}
+
+// ************************* Build table descriptions ****************************
+MyMoneyDbDef::MyMoneyDbDef () {
+ FileInfo();
+ Institutions();
+ Payees();
+ Accounts();
+ Transactions();
+ Splits();
+ KeyValuePairs();
+ Schedules();
+ SchedulePaymentHistory();
+ Securities();
+ Prices();
+ Currencies();
+ Reports();
+ Budgets();
+ Balances();
+}
+
+/* PRIMARYKEY - these fields combine to form a unique key field on which the db will create an index
+ NOTNULL - this field should never be null
+ UNSIGNED - for numeric types, indicates the field is UNSIGNED
+ ?ISKEY - where there is no primary key, these fields can be used to uniquely identify a record
+ Default is that a field is not a part of a primary key, nullable, and if numeric, signed */
+
+#define PRIMARYKEY true
+#define NOTNULL true
+#define UNSIGNED false
+//#define ISKEY true
+
+void MyMoneyDbDef::FileInfo(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("version", "varchar(16)"));
+ fields.append(new MyMoneyDbColumn("created", "date"));
+ fields.append(new MyMoneyDbColumn("lastModified", "date"));
+ fields.append(new MyMoneyDbColumn("baseCurrency", "char(3)"));
+ fields.append(new MyMoneyDbIntColumn("institutions", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("accounts", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("payees", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("transactions", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("splits", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("securities", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("prices", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("currencies", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("schedules", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("reports", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("kvps", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbColumn("dateRangeStart", "date"));
+ fields.append(new MyMoneyDbColumn("dateRangeEnd", "date"));
+ fields.append(new MyMoneyDbIntColumn("hiInstitutionId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiPayeeId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiAccountId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiTransactionId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiScheduleId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiSecurityId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiReportId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbColumn("encryptData", "varchar(255)"));
+ fields.append(new MyMoneyDbColumn("updateInProgress", "char(1)"));
+ fields.append(new MyMoneyDbIntColumn("budgets", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("hiBudgetId", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ fields.append(new MyMoneyDbColumn("logonUser", "varchar(255)"));
+ fields.append(new MyMoneyDbDatetimeColumn("logonAt"));
+ fields.append(new MyMoneyDbIntColumn("fixLevel",
+ MyMoneyDbIntColumn::MEDIUM, UNSIGNED));
+ MyMoneyDbTable t("kmmFileInfo", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Institutions(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("name", MyMoneyDbTextColumn::NORMAL, false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("manager"));
+ fields.append(new MyMoneyDbTextColumn("routingCode"));
+ fields.append(new MyMoneyDbTextColumn("addressStreet"));
+ fields.append(new MyMoneyDbTextColumn("addressCity"));
+ fields.append(new MyMoneyDbTextColumn("addressZipcode"));
+ fields.append(new MyMoneyDbTextColumn("telephone"));
+ MyMoneyDbTable t("kmmInstitutions", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Payees(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("name"));
+ fields.append(new MyMoneyDbTextColumn("reference"));
+ fields.append(new MyMoneyDbTextColumn("email"));
+ fields.append(new MyMoneyDbTextColumn("addressStreet"));
+ fields.append(new MyMoneyDbTextColumn("addressCity"));
+ fields.append(new MyMoneyDbTextColumn("addressZipcode"));
+ fields.append(new MyMoneyDbTextColumn("addressState"));
+ fields.append(new MyMoneyDbTextColumn("telephone"));
+ fields.append(new MyMoneyDbTextColumn("notes", MyMoneyDbTextColumn::LONG));
+ fields.append(new MyMoneyDbColumn("defaultAccountId", "varchar(32)"));
+ fields.append(new MyMoneyDbIntColumn("matchData", MyMoneyDbIntColumn::TINY, UNSIGNED));
+ fields.append(new MyMoneyDbColumn("matchIgnoreCase", "char(1)"));
+ fields.append(new MyMoneyDbTextColumn("matchKeys"));
+ MyMoneyDbTable t("kmmPayees", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Accounts(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("institutionId", "varchar(32)"));
+ fields.append(new MyMoneyDbColumn("parentId", "varchar(32)"));
+ fields.append(new MyMoneyDbDatetimeColumn("lastReconciled"));
+ fields.append(new MyMoneyDbDatetimeColumn("lastModified"));
+ fields.append(new MyMoneyDbColumn("openingDate", "date"));
+ fields.append(new MyMoneyDbTextColumn("accountNumber"));
+ fields.append(new MyMoneyDbColumn("accountType", "varchar(16)", false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("accountTypeString"));
+ fields.append(new MyMoneyDbColumn("isStockAccount", "char(1)"));
+ fields.append(new MyMoneyDbTextColumn("accountName"));
+ fields.append(new MyMoneyDbTextColumn("description"));
+ fields.append(new MyMoneyDbColumn("currencyId", "varchar(32)"));
+ fields.append(new MyMoneyDbTextColumn("balance"));
+ fields.append(new MyMoneyDbTextColumn("balanceFormatted"));
+ fields.append(new MyMoneyDbIntColumn("transactionCount", MyMoneyDbIntColumn::BIG, UNSIGNED));
+ MyMoneyDbTable t("kmmAccounts", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Transactions(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("txType", "char(1)"));
+ fields.append(new MyMoneyDbDatetimeColumn("postDate"));
+ fields.append(new MyMoneyDbTextColumn("memo"));
+ fields.append(new MyMoneyDbDatetimeColumn("entryDate"));
+ fields.append(new MyMoneyDbColumn("currencyId", "char(3)"));
+ fields.append(new MyMoneyDbTextColumn("bankId"));
+ MyMoneyDbTable t("kmmTransactions", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Splits(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("transactionId", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("txType", "char(1)"));
+ fields.append(new MyMoneyDbIntColumn("splitId", MyMoneyDbIntColumn::SMALL, UNSIGNED, PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("payeeId", "varchar(32)"));
+ fields.append(new MyMoneyDbDatetimeColumn("reconcileDate"));
+ fields.append(new MyMoneyDbColumn("action", "varchar(16)"));
+ fields.append(new MyMoneyDbColumn("reconcileFlag", "char(1)"));
+ fields.append(new MyMoneyDbTextColumn("value", MyMoneyDbTextColumn::NORMAL, false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("valueFormatted", "text"));
+ fields.append(new MyMoneyDbTextColumn("shares", MyMoneyDbTextColumn::NORMAL, false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("sharesFormatted"));
+ fields.append(new MyMoneyDbTextColumn("price", MyMoneyDbTextColumn::NORMAL, false));
+ fields.append(new MyMoneyDbTextColumn("priceFormatted"));
+ fields.append(new MyMoneyDbTextColumn("memo"));
+ fields.append(new MyMoneyDbColumn("accountId", "varchar(32)", false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("checkNumber", "varchar(32)"));
+ fields.append(new MyMoneyDbDatetimeColumn("postDate"));
+ fields.append(new MyMoneyDbTextColumn("bankId"));
+ MyMoneyDbTable t("kmmSplits", fields);
+ QStringList list;
+ list << "accountId" << "txType";
+ t.addIndex("kmmSplitsaccount_type", list, false);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::KeyValuePairs(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("kvpType", "varchar(16)", false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("kvpId", "varchar(32)"));
+ fields.append(new MyMoneyDbColumn("kvpKey", "varchar(255)", false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("kvpData"));
+ MyMoneyDbTable t("kmmKeyValuePairs", fields);
+ QStringList list;
+ list << "kvpType" << "kvpId";
+ t.addIndex("type_id", list, false);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Schedules(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("name", MyMoneyDbTextColumn::NORMAL, false, NOTNULL));
+ fields.append(new MyMoneyDbIntColumn("type", MyMoneyDbIntColumn::TINY, UNSIGNED, false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("typeString"));
+ fields.append(new MyMoneyDbIntColumn("occurence", MyMoneyDbIntColumn::SMALL, UNSIGNED, false,
+ NOTNULL));
+ fields.append(new MyMoneyDbIntColumn("occurenceMultiplier", MyMoneyDbIntColumn::SMALL, UNSIGNED,
+ false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("occurenceString"));
+ fields.append(new MyMoneyDbIntColumn("paymentType", MyMoneyDbIntColumn::TINY, UNSIGNED));
+ fields.append(new MyMoneyDbTextColumn("paymentTypeString", MyMoneyDbTextColumn::LONG));
+ fields.append(new MyMoneyDbColumn("startDate", "date", false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("endDate", "date"));
+ fields.append(new MyMoneyDbColumn("fixed", "char(1)", false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("autoEnter", "char(1)", false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("lastPayment", "date"));
+ fields.append(new MyMoneyDbColumn("nextPaymentDue", "date"));
+ fields.append(new MyMoneyDbIntColumn("weekendOption", MyMoneyDbIntColumn::TINY, UNSIGNED, false,
+ NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("weekendOptionString"));
+ MyMoneyDbTable t("kmmSchedules", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::SchedulePaymentHistory(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("schedId", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("payDate", "date", PRIMARYKEY, NOTNULL));
+ MyMoneyDbTable t("kmmSchedulePaymentHistory", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Securities(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("name", "text", false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("symbol"));
+ fields.append(new MyMoneyDbIntColumn("type", MyMoneyDbIntColumn::SMALL, UNSIGNED, false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("typeString"));
+ fields.append(new MyMoneyDbColumn("smallestAccountFraction", "varchar(24)"));
+ fields.append(new MyMoneyDbTextColumn("tradingMarket"));
+ fields.append(new MyMoneyDbColumn("tradingCurrency", "char(3)"));
+ MyMoneyDbTable t("kmmSecurities", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Prices(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("fromId", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("toId", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("priceDate", "date", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("price", MyMoneyDbTextColumn::NORMAL, false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("priceFormatted"));
+ fields.append(new MyMoneyDbTextColumn("priceSource"));
+ MyMoneyDbTable t("kmmPrices", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Currencies(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("ISOcode", "char(3)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("name", MyMoneyDbTextColumn::NORMAL, false, NOTNULL));
+ fields.append(new MyMoneyDbIntColumn("type", MyMoneyDbIntColumn::SMALL, UNSIGNED));
+ fields.append(new MyMoneyDbTextColumn("typeString"));
+ fields.append(new MyMoneyDbIntColumn("symbol1", MyMoneyDbIntColumn::SMALL, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("symbol2", MyMoneyDbIntColumn::SMALL, UNSIGNED));
+ fields.append(new MyMoneyDbIntColumn("symbol3", MyMoneyDbIntColumn::SMALL, UNSIGNED));
+ fields.append(new MyMoneyDbColumn("symbolString", "varchar(255)"));
+ fields.append(new MyMoneyDbColumn("partsPerUnit", "varchar(24)"));
+ fields.append(new MyMoneyDbColumn("smallestCashFraction", "varchar(24)"));
+ fields.append(new MyMoneyDbColumn("smallestAccountFraction", "varchar(24)"));
+ MyMoneyDbTable t("kmmCurrencies", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Reports(void) {
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("name", "varchar(255)", false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("XML", MyMoneyDbTextColumn::LONG));
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ MyMoneyDbTable t("kmmReportConfig", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Budgets(void){
+ QValueList<KSharedPtr <MyMoneyDbColumn> > fields;
+ fields.append(new MyMoneyDbColumn("id", "varchar(32)", PRIMARYKEY, NOTNULL));
+ fields.append(new MyMoneyDbColumn("name", "text", false, NOTNULL));
+ fields.append(new MyMoneyDbColumn("start", "date", false, NOTNULL));
+ fields.append(new MyMoneyDbTextColumn("XML", MyMoneyDbTextColumn::LONG));
+ MyMoneyDbTable t("kmmBudgetConfig", fields);
+ t.buildSQLStrings();
+ m_tables[t.name()] = t;
+}
+
+void MyMoneyDbDef::Balances(void){
+ MyMoneyDbView v("kmmBalances", "CREATE VIEW kmmBalances AS "
+ "SELECT kmmAccounts.id AS id, kmmAccounts.currencyId, "
+ "kmmSplits.txType, kmmSplits.value, kmmSplits.shares, "
+ "kmmSplits.postDate AS balDate, "
+ "kmmTransactions.currencyId AS txCurrencyId "
+ "FROM kmmAccounts, kmmSplits, kmmTransactions "
+ "WHERE kmmSplits.txType = 'N' "
+ "AND kmmSplits.accountId = kmmAccounts.id "
+ "AND kmmSplits.transactionId = kmmTransactions.id;");
+ m_views[v.name()] = v;
+}
+
+// function to write create SQL to a stream
+const QString MyMoneyDbDef::generateSQL (const QString& driver) const {
+ QString retval;
+ databaseTypeE dbType = m_drivers.driverToType(driver);
+ table_iterator tt = tableBegin();
+ while (tt != tableEnd()) {
+ retval += (*tt).generateCreateSQL(dbType) + '\n';
+ ++tt;
+ }
+ view_iterator vt = viewBegin();
+ while (vt != viewEnd()) {
+ retval += (*vt).createString() + '\n';
+ ++vt;
+ }
+ retval += '\n';
+
+ MyMoneyDbTable fi = m_tables["kmmFileInfo"];
+ QString qs = fi.insertString();
+ MyMoneyDbTable::field_iterator fit;
+ for (fit = fi.begin(); fit != fi.end(); ++fit) {
+ QString toReplace = (*fit)->name();
+ toReplace.prepend(':');
+ QString replace = "NULL";
+ if ((*fit)->name() == "version")
+ replace = QString::number(m_currentVersion);
+ if ((*fit)->name() == "fixLevel")
+ replace = QString::number
+ (MyMoneyFile::instance()->storage()->currentFixVersion());
+ if ((*fit)->name() == "created")
+ replace = QDate::currentDate().toString(Qt::ISODate);
+ if ((*fit)->name() == "lastModified")
+ replace = QDate::currentDate().toString(Qt::ISODate);
+ if ((*fit)->name() == "updateInProgress")
+ replace = enclose("N");
+ qs.replace(toReplace, replace);
+ }
+ qs += "\n\n";
+ retval += qs;
+
+ qs = QString();
+ unsigned int i;
+ QValueList<MyMoneyAccount> stdList;
+ stdList.append (MyMoneyFile::instance()->asset());
+ stdList.append (MyMoneyFile::instance()->equity());
+ stdList.append (MyMoneyFile::instance()->expense());
+ stdList.append (MyMoneyFile::instance()->income());
+ stdList.append (MyMoneyFile::instance()->liability());
+ for (i = 0; i < stdList.count(); ++i) {
+ MyMoneyAccount* pac = &stdList[i];
+ MyMoneyDbTable ac = m_tables["kmmAccounts"];
+ qs = ac.insertString();
+ MyMoneyDbTable::field_iterator act;
+ // do the following in reverse so the 'formatted' fields are
+ // correctly handled.
+ // Hmm, how does one use a QValueListIterator in reverse
+ // It'll be okay in Qt4 with QListIterator
+ for (act = ac.end(), --act; act != ac.begin(); --act) {
+ QString toReplace = (*act)->name();
+ toReplace.prepend(':');
+ QString replace = "NULL";
+ if ((*act)->name() == "accountType")
+ replace = QString::number(pac->accountType());
+ if ((*act)->name() == "accountTypeString")
+ replace = enclose(pac->name());
+ if ((*act)->name() == "isStockAccount")
+ replace = enclose("N");
+ if ((*act)->name() == "accountName")
+ replace = enclose(pac->name());
+ qs.replace(toReplace, replace);
+ }
+ qs.replace (":id", enclose(pac->id())); // a real kludge
+ qs += "\n\n";
+ retval += qs;
+ }
+ return retval;
+}
+
+//*****************************************************************************
+
+void MyMoneyDbTable::addIndex(const QString& name, const QStringList& columns, bool unique) {
+ m_indices.push_back (MyMoneyDbIndex (m_name, name, columns, unique));
+}
+
+void MyMoneyDbTable::buildSQLStrings (void) {
+ // build fixed SQL strings for this table
+ // build the insert string with placeholders for each field
+ QString qs = QString("INSERT INTO %1 (").arg(name());
+ QString ws = ") VALUES (";
+ field_iterator ft = m_fields.begin();
+ while (ft != m_fields.end()) {
+ qs += QString("%1, ").arg((*ft)->name());
+ ws += QString(":%1, ").arg((*ft)->name());
+ ++ft;
+ }
+ qs = qs.left(qs.length() - 2);
+ ws = ws.left(ws.length() - 2);
+ m_insertString = qs + ws + ");";
+ // build a 'select all' string (select * is deprecated)
+ // don't terminate with semicolon coz we may want a where or order clause
+ m_selectAllString = "SELECT " + columnList() + " FROM " + name();;
+
+ // build an update string; key fields go in the where clause
+ qs = "UPDATE " + name() + " SET ";
+ ws = QString();
+ ft = m_fields.begin();
+ while (ft != m_fields.end()) {
+ if ((*ft)->isPrimaryKey()) {
+ if (!ws.isEmpty()) ws += " AND ";
+ ws += QString("%1 = :%2").arg((*ft)->name()).arg((*ft)->name());
+ } else {
+ qs += QString("%1 = :%2, ").arg((*ft)->name()).arg((*ft)->name());
+ }
+ ++ft;
+ }
+ qs = qs.left(qs.length() - 2);
+ if (!ws.isEmpty()) qs += " WHERE " + ws;
+ m_updateString = qs + ";";
+ // build a delete string; where clause as for update
+ qs = "DELETE FROM " + name();
+ if (!ws.isEmpty()) qs += " WHERE " + ws;
+ m_deleteString = qs + ";";
+ }
+
+const QString MyMoneyDbTable::columnList() const {
+ field_iterator ft = m_fields.begin();
+ QString qs;
+ ft = m_fields.begin();
+ while (ft != m_fields.end()) {
+ qs += QString("%1, ").arg((*ft)->name());
+ ++ft;
+ }
+ return (qs.left(qs.length() - 2));
+}
+
+const QString MyMoneyDbTable::generateCreateSQL (databaseTypeE dbType) const {
+ QString qs = QString("CREATE TABLE %1 (").arg(name());
+ QString pkey;
+ for (field_iterator it = m_fields.begin(); it != m_fields.end(); ++it) {
+ qs += (*it)->generateDDL (dbType) + ", ";
+ if ((*it)->isPrimaryKey ())
+ pkey += (*it)->name () + ", ";
+ }
+
+ if (!pkey.isEmpty()) {
+ qs += "PRIMARY KEY (" + pkey;
+ qs = qs.left(qs.length() -2) + "))";
+ } else {
+ qs = qs.left(qs.length() -2) + ")";
+ }
+
+ if (dbType == Mysql)
+ qs += " ENGINE = InnoDB;\n";
+ else
+ qs += ";\n";
+
+ for (index_iterator ii = m_indices.begin(); ii != m_indices.end(); ++ii) {
+ qs += (*ii).generateDDL(dbType);
+ }
+ return qs;
+}
+
+const QString MyMoneyDbTable::dropPrimaryKeyString(databaseTypeE dbType) const
+{
+ if (dbType == Mysql || dbType == Oracle8)
+ return "ALTER TABLE " + m_name + " DROP PRIMARY KEY;";
+ else if (dbType == Postgresql)
+ return "ALTER TABLE " + m_name + " DROP CONSTRAINT " + m_name + "_pkey;";
+ else if (dbType == Sqlite3)
+ return "";
+
+ return "";
+}
+
+const QString MyMoneyDbTable::modifyColumnString(databaseTypeE dbType, const QString& columnName, const MyMoneyDbColumn& newDef) const {
+ QString qs = "ALTER TABLE " + m_name + " ";
+ if (dbType == Mysql)
+ qs += "CHANGE " + columnName + " " + newDef.generateDDL(dbType);
+ else if (dbType == Postgresql)
+ qs += "ALTER COLUMN " + columnName + " TYPE " + newDef.generateDDL(dbType).section(' ', 1);
+ else if (dbType == Sqlite3)
+ qs = "";
+ else if (dbType == Oracle8)
+ qs = "MODIFY " + columnName + " " + newDef.generateDDL(dbType);
+
+ return qs;
+}
+
+//*****************************************************************************
+const QString MyMoneyDbIndex::generateDDL (databaseTypeE dbType) const
+{
+ Q_UNUSED(dbType);
+
+ QString qs = "CREATE ";
+
+ if (m_unique)
+ qs += "UNIQUE ";
+
+ qs += "INDEX " + m_table + "_" + m_name + "_idx ON "
+ + m_table + " (";
+
+ // The following should probably be revised. MySQL supports an index on
+ // partial columns, but not on a function. Postgres supports an index on
+ // the result of an SQL function, but not a partial column. There should be
+ // a way to merge these, and support other DBMSs like SQLite at the same time.
+ // For now, if we just use plain columns, this will work fine.
+ for (QStringList::const_iterator it = m_columns.begin(); it != m_columns.end(); ++it) {
+ qs += *it + ",";
+ }
+
+ qs = qs.left(qs.length() - 1) + ");\n";
+
+ return qs;
+}
+
+//*****************************************************************************
+// These are the actual column types.
+// TODO: consider changing all the else-if statements to driver classes.
+//
+
+MyMoneyDbColumn* MyMoneyDbColumn::clone () const
+{ return (new MyMoneyDbColumn (*this)); }
+
+MyMoneyDbIntColumn* MyMoneyDbIntColumn::clone () const
+{ return (new MyMoneyDbIntColumn (*this)); }
+
+MyMoneyDbDatetimeColumn* MyMoneyDbDatetimeColumn::clone () const
+{ return (new MyMoneyDbDatetimeColumn (*this)); }
+
+MyMoneyDbTextColumn* MyMoneyDbTextColumn::clone () const
+{ return (new MyMoneyDbTextColumn (*this)); }
+
+const QString MyMoneyDbColumn::generateDDL (databaseTypeE dbType) const
+{
+ Q_UNUSED(dbType);
+
+ QString qs = name() + " " + type();
+ if (isNotNull()) qs += " NOT NULL";
+ return qs;
+}
+
+const QString MyMoneyDbIntColumn::generateDDL (databaseTypeE dbType) const
+{
+ QString qs = name() + " ";
+
+ switch (m_type) {
+ case MyMoneyDbIntColumn::TINY:
+ if (dbType == Mysql || dbType == Sqlite3) {
+ qs += "tinyint ";
+ } else if (dbType == Postgresql) {
+ qs += "int2 ";
+ } else if (dbType == Db2) {
+ qs += "smallint ";
+ } else if (dbType == Oracle8) {
+ qs += "number(3) ";
+ } else {
+ // cross your fingers...
+ qs += "smallint ";
+ }
+ break;
+ case MyMoneyDbIntColumn::SMALL:
+ if (dbType == Mysql || dbType == Db2 || dbType == Sqlite3) {
+ qs += "smallint ";
+ } else if (dbType == Postgresql) {
+ qs += "int2 ";
+ } else if (dbType == Oracle8) {
+ qs += "number(5) ";
+ } else {
+ // cross your fingers...
+ qs += "smallint ";
+ }
+ break;
+ case MyMoneyDbIntColumn::MEDIUM:
+ if (dbType == Mysql || dbType == Db2) {
+ qs += "int ";
+ } else if (dbType == Postgresql) {
+ qs += "int4 ";
+ } else if (dbType == Sqlite3) {
+ qs += "integer ";
+ } else if (dbType == Oracle8) {
+ qs += "number(10) ";
+ } else {
+ // cross your fingers...
+ qs += "int ";
+ }
+ break;
+ case MyMoneyDbIntColumn::BIG:
+ if (dbType == Mysql || dbType == Db2 || dbType == Sqlite3) {
+ qs += "bigint ";
+ } else if (dbType == Postgresql) {
+ qs += "int8 ";
+ } else if (dbType == Oracle8) {
+ qs += "number(20) ";
+ } else {
+ // cross your fingers...
+ qs += "bigint ";
+ }
+ break;
+ default:
+ qs += "int ";
+ break;
+ }
+
+ if ((! m_isSigned) && (dbType == Mysql || dbType == Sqlite3)) {
+ qs += "unsigned ";
+ }
+
+ if (isNotNull()) qs += " NOT NULL";
+ if ((! m_isSigned) && (dbType == Postgresql)) {
+ qs += " check(" + name() + " >= 0)";
+ }
+ return qs;
+}
+
+const QString MyMoneyDbTextColumn::generateDDL (databaseTypeE dbType) const
+{
+ QString qs = name() + " ";
+
+ switch (m_type) {
+ case MyMoneyDbTextColumn::TINY:
+ if (dbType == Mysql || dbType == Sqlite3) {
+ qs += "tinytext ";
+ } else if (dbType == Postgresql) {
+ qs += "text ";
+ } else if (dbType == Db2) {
+ qs += "varchar(255) ";
+ } else if (dbType == Oracle8) {
+ qs += "varchar2(255) ";
+ } else {
+ // cross your fingers...
+ qs += "tinytext ";
+ }
+ break;
+ case MyMoneyDbTextColumn::NORMAL:
+ if (dbType == Mysql || dbType == Sqlite3 || dbType == Postgresql) {
+ qs += "text ";
+ } else if (dbType == Db2) {
+ qs += "clob(64K) ";
+ } else if (dbType == Oracle8) {
+ qs += "clob ";
+ } else {
+ // cross your fingers...
+ qs += "text ";
+ }
+ break;
+ case MyMoneyDbTextColumn::MEDIUM:
+ if (dbType == Mysql || dbType == Sqlite3 ) {
+ qs += "mediumtext ";
+ } else if (dbType == Postgresql) {
+ qs += "text ";
+ } else if (dbType == Db2) {
+ qs += "clob(16M) ";
+ } else if (dbType == Oracle8) {
+ qs += "clob ";
+ } else {
+ // cross your fingers...
+ qs += "mediumtext ";
+ }
+ break;
+ case MyMoneyDbTextColumn::LONG:
+ if (dbType == Mysql || dbType == Sqlite3 ) {
+ qs += "longtext ";
+ } else if (dbType == Postgresql) {
+ qs += "text ";
+ } else if (dbType == Db2) {
+ qs += "clob(2G) ";
+ } else if (dbType == Oracle8) {
+ qs += "clob ";
+ } else {
+ // cross your fingers...
+ qs += "longtext ";
+ }
+ break;
+ default:
+ if (dbType == Oracle8) {
+ qs += "clob ";
+ } else {
+ qs += "text ";
+ }
+ break;
+ }
+
+ if (isNotNull()) qs += " NOT NULL";
+
+ return qs;
+}
+
+const QString MyMoneyDbDatetimeColumn::generateDDL (databaseTypeE dbType) const
+{
+ QString qs = name() + " ";
+ if (dbType == Mysql || dbType == ODBC3) {
+ qs += "datetime ";
+ } else if (dbType == Postgresql || dbType == Db2 || dbType == Oracle8 || dbType == Sqlite3 ) {
+ qs += "timestamp ";
+ } else {
+ qs += "";
+ }
+ if (isNotNull()) qs += " NOT NULL";
+ return qs;
+}
diff --git a/kmymoney2/mymoney/storage/mymoneystoragesql.h b/kmymoney2/mymoney/storage/mymoneystoragesql.h
new file mode 100644
index 0000000..1abe70b
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragesql.h
@@ -0,0 +1,807 @@
+/***************************************************************************
+ mymoneystoragesql.h
+ -------------------
+ begin : 11 November 2005
+ copyright : (C) 2005 by Tony Bloomfield
+ email : tonybloom@users.sourceforge.net
+ : Fernando Vilas <fvilas@iname.com>
+ ***************************************************************************/
+
+#ifndef MYMONEYSTORAGESQL_H
+#define MYMONEYSTORAGESQL_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qsqldatabase.h>
+#include <qsqlquery.h>
+#include <qsqlerror.h>
+#include <qvaluestack.h>
+
+class QIODevice;
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kurl.h>
+#include <ksharedptr.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "imymoneystorageformat.h"
+#include "../mymoneyinstitution.h"
+#include "../mymoneypayee.h"
+#include "../mymoneyaccount.h"
+#include "../mymoneytransaction.h"
+#include "../mymoneysplit.h"
+#include "../mymoneyscheduled.h"
+#include "../mymoneysecurity.h"
+#include "../mymoneyprice.h"
+#include "../mymoneyreport.h"
+#include "../mymoneybudget.h"
+#include "../mymoneyfile.h"
+#include "../mymoneykeyvaluecontainer.h"
+#include "mymoneymap.h"
+#include "../mymoneymoney.h"
+#include "../mymoneytransactionfilter.h"
+
+// This is a convenience functor to make it easier to use STL algorithms
+// It will return false if the MyMoneyTransaction DOES match the filter.
+// This functor may disappear when all filtering can be handled in SQL.
+class FilterFail {
+ public:
+ FilterFail (const MyMoneyTransactionFilter& filter,
+ IMyMoneyStorage* storage)
+ : m_filter (filter),
+ m_storage (storage)
+ {}
+
+ inline bool operator() (const QPair<QString, MyMoneyTransaction>& transactionPair)
+ { return (*this) (transactionPair.second); }
+
+ inline bool operator() (const MyMoneyTransaction& transaction)
+ {
+ return (! m_filter.match(transaction)) && (m_filter.matchingSplits().count() == 0);
+ }
+
+ private:
+ MyMoneyTransactionFilter m_filter;
+ IMyMoneyStorage *m_storage;
+};
+
+/**
+@author Tony Bloomfield
+ */
+typedef enum databaseTypeE { // database (driver) type
+ Db2 = 0, //
+ Interbase, //
+ Mysql, //
+ Oracle8, //
+ ODBC3, //
+ Postgresql, //
+ Sqlite, //
+ Sybase, //
+ Sqlite3 //
+} _databaseType;
+
+class MyMoneyStorageSql;
+
+/**
+ * The MyMoneySqlQuery class is derived from QSqlQuery to provide
+ * a way to adjust some queries based on databaseTypeE and make
+ * debugging easier by providing a place to put debug statements.
+ */
+class MyMoneySqlQuery : public QSqlQuery {
+ public:
+ MyMoneySqlQuery (MyMoneyStorageSql* db = 0);
+ virtual ~MyMoneySqlQuery() {}
+ bool exec ();
+ bool prepare ( const QString & query );
+ private:
+ const MyMoneyStorageSql* m_db;
+};
+
+/**
+ * The MyMoneyDbDrivers class is a map from string to enum of db types.
+ */
+class MyMoneyDbDrivers {
+ public:
+ MyMoneyDbDrivers ();
+ /**
+ * @return a list ofsupported Qt database driver types, their qt names and useful names
+ **/
+ const QMap<QString, QString> driverMap() const {return (m_driverMap);};
+ databaseTypeE driverToType (const QString& driver) const;
+ bool isTested (databaseTypeE dbType) const;
+ private:
+ QMap<QString, QString> m_driverMap;
+};
+
+/**
+ * The MyMoneyDbColumn class is a base type for generic db columns.
+ * Derived types exist for several common column types.
+ */
+class MyMoneyDbColumn : public KShared {
+ public:
+ MyMoneyDbColumn (const QString& iname,
+ const QString& itype = QString::null,
+ const bool iprimary = false,
+ const bool inotnull = false,
+ const QString &initVersion = "0.1"):
+ m_name(iname),
+ m_type(itype),
+ m_isPrimary(iprimary),
+ m_isNotNull(inotnull),
+ m_initVersion(initVersion) {}
+ MyMoneyDbColumn (void) {}
+ virtual ~MyMoneyDbColumn () {}
+
+ /**
+ * This method is used to copy column objects. Because there are several derived types,
+ * clone() is more appropriate than a copy ctor in most cases.
+ */
+ virtual MyMoneyDbColumn* clone () const;
+
+ /**
+ * This method generates the DDL (Database Design Language) string for the column.
+ *
+ * @param dbType Database driver type
+ *
+ * @return QString of the DDL for the column, tailored for what the driver supports.
+ */
+ virtual const QString generateDDL (databaseTypeE dbType) const;
+
+ const QString& name(void) const {return (m_name);}
+ const QString& type(void) const {return (m_type);}
+ bool isPrimaryKey(void) const {return (m_isPrimary);}
+ bool isNotNull(void) const {return (m_isNotNull);}
+ private:
+ QString m_name;
+ QString m_type;
+ bool m_isPrimary;
+ bool m_isNotNull;
+ QString m_initVersion;
+};
+
+/**
+ * The MyMoneyDbDatetimeColumn class is a representation of datetime columns.
+ */
+class MyMoneyDbDatetimeColumn : public MyMoneyDbColumn {
+ public:
+ MyMoneyDbDatetimeColumn (const QString& iname,
+ const bool iprimary = false,
+ const bool inotnull = false,
+ const QString &initVersion = "0.1"):
+ MyMoneyDbColumn (iname, "", iprimary, inotnull, initVersion)
+ {}
+ virtual ~MyMoneyDbDatetimeColumn() {}
+ virtual const QString generateDDL (databaseTypeE dbType) const;
+ virtual MyMoneyDbDatetimeColumn* clone () const;
+ private:
+ static const QString calcType(void);
+};
+
+/**
+ * The MyMoneyDbColumn class is a representation of integer db columns.
+ */
+class MyMoneyDbIntColumn : public MyMoneyDbColumn {
+ public:
+ enum size {TINY, SMALL, MEDIUM, BIG};
+ MyMoneyDbIntColumn (const QString& iname,
+ const size type = MEDIUM,
+ const bool isigned = true,
+ const bool iprimary = false,
+ const bool inotnull = false,
+ const QString &initVersion = "0.1"):
+ MyMoneyDbColumn (iname, "", iprimary, inotnull, initVersion),
+ m_type (type),
+ m_isSigned (isigned) {}
+ virtual ~MyMoneyDbIntColumn() {}
+ virtual const QString generateDDL (databaseTypeE dbType) const;
+ virtual MyMoneyDbIntColumn* clone () const;
+ private:
+ size m_type;
+ bool m_isSigned;
+};
+
+/**
+ * The MyMoneyDbTextColumn class is a representation of text db columns,
+ * for drivers that support it. If the driver does not support it, it is
+ * usually some sort of really large varchar or varchar2.
+ */
+class MyMoneyDbTextColumn : public MyMoneyDbColumn {
+ public:
+ enum size {TINY, NORMAL, MEDIUM, LONG};
+ MyMoneyDbTextColumn (const QString& iname,
+ const size type = MEDIUM,
+ const bool iprimary = false,
+ const bool inotnull = false,
+ const QString &initVersion = "0.1"):
+ MyMoneyDbColumn (iname, "", iprimary, inotnull, initVersion),
+ m_type (type) {}
+ virtual ~MyMoneyDbTextColumn() {}
+ virtual const QString generateDDL (databaseTypeE dbType) const;
+ virtual MyMoneyDbTextColumn* clone () const;
+ private:
+ size m_type;
+};
+
+/**
+ * The MyMoneyDbIndex class is a representation of a db index.
+ * To provide generic support for most databases, the table name,
+ * name of the index, and list of columns for the index are required.
+ * Additionally, the user can specify whether the index is unique or not.
+ *
+ * At this time, different types of index are not supported, since the portability
+ * is fairly limited.
+ */
+class MyMoneyDbIndex {
+ public:
+ MyMoneyDbIndex (const QString& table,
+ const QString& name,
+ const QStringList& columns,
+ bool unique = false):
+ m_table(table),
+ m_unique(unique),
+ m_name(name),
+ m_columns(columns)
+ {}
+ MyMoneyDbIndex () {}
+ inline const QString table () const {return m_table;}
+ inline bool isUnique () const {return m_unique;}
+ inline const QString name () const {return m_name;}
+ inline const QStringList columns () const {return m_columns;}
+ const QString generateDDL (databaseTypeE dbType) const;
+ private:
+ QString m_table;
+ bool m_unique;
+ QString m_name;
+ QStringList m_columns;
+};
+
+/**
+ * The MyMoneyDbTable class is a representation of a db table.
+ * It has a list of the columns (pointers to MyMoneyDbColumn types) and a
+ * list of any indices that may be on the table.
+ * Additionally, a string for a parameterized query for each of some common
+ * tasks on a table is created by the ctor.
+ *
+ * Const iterators over the list of columns are provided as a convenience.
+ */
+class MyMoneyDbTable {
+ public:
+ MyMoneyDbTable (const QString& iname,
+ const QValueList<KSharedPtr <MyMoneyDbColumn> >& ifields,
+ const QString& initVersion = "1.0"):
+ m_name(iname),
+ m_fields(ifields),
+ m_initVersion(initVersion) {}
+ MyMoneyDbTable (void) {}
+
+ inline const QString& name(void) const {return (m_name);}
+ inline const QString& insertString(void) const {return (m_insertString);};
+ inline const QString selectAllString(bool terminate = true) const
+ {return (terminate ? QString(m_selectAllString + ";") : m_selectAllString);};
+ inline const QString& updateString(void) const {return (m_updateString);};
+ inline const QString& deleteString(void) const {return (m_deleteString);};
+
+ /**
+ * This method determines the string required to drop the primary key for the table
+ * based on the db specific syntax.
+ *
+ * @param dbType The driver type of the database.
+ *
+ * @return QString for the syntax to drop the primary key.
+ */
+ const QString dropPrimaryKeyString(databaseTypeE dbType) const;
+ /**
+ * This method returns a comma-separated list of all column names in the table
+ *
+ * @return QString column list.
+ */
+ const QString columnList() const;
+ /**
+ * This method returns the string for changing a column's definition. It covers statements
+ * like ALTER TABLE..CHANGE COLUMN, MODIFY COLUMN, etc.
+ *
+ * @param dbType The driver type of the database.
+ * @param columnName The name of the column to be modified.
+ * @param newDef The MyMoneyColumn object of the new column definition.
+ *
+ * @return QString containing DDL to change the column.
+ */
+ const QString modifyColumnString(databaseTypeE dbType, const QString& columnName, const MyMoneyDbColumn& newDef) const;
+
+ /**
+ * This method builds all of the SQL strings for common operations.
+ */
+ void buildSQLStrings(void);
+
+ /**
+ * This method generates the DDL required to create the table.
+ *
+ * @param dbType The driver type of the database.
+ *
+ * @return QString of the DDL.
+ */
+ const QString generateCreateSQL (databaseTypeE dbType) const;
+
+ /**
+ * This method creates a MyMoneyDbIndex object and adds it to the list of indices for the table.
+ *
+ * @param name The name of the index.
+ * @param columns The list of the columns affected.
+ * @param unique Whether or not this should be a unique index.
+ */
+ void addIndex(const QString& name, const QStringList& columns, bool unique = false);
+
+ typedef QValueList<KSharedPtr <MyMoneyDbColumn> >::const_iterator field_iterator;
+ inline field_iterator begin(void) const {return m_fields.constBegin();}
+ inline field_iterator end(void) const {return m_fields.constEnd(); }
+ private:
+ QString m_name;
+ QValueList<KSharedPtr <MyMoneyDbColumn> > m_fields;
+
+ typedef QValueList<MyMoneyDbIndex>::const_iterator index_iterator;
+ QValueList<MyMoneyDbIndex> m_indices;
+ QString m_initVersion;
+ QString m_insertString; // string to insert a record
+ QString m_selectAllString; // to select all fields
+ QString m_updateString; // normal string for record update
+ QString m_deleteString; // string to delete 1 record
+};
+
+/**
+ * The MyMoneyDbView class is a representation of a db view.
+ *
+ * Views will be dropped and recreated on upgrade, so there is no need
+ * to do anything more complex than storing the name of the view and
+ * the CREATE VIEW string.
+ */
+class MyMoneyDbView {
+ public:
+ MyMoneyDbView (const QString& name,
+ const QString& createString,
+ const QString& initVersion = "0.1")
+ : m_name (name), m_createString (createString), m_initVersion (initVersion)
+ {}
+
+ MyMoneyDbView (void) {}
+
+ inline const QString& name(void) const {return (m_name);}
+ inline const QString createString(void) const {return (m_createString);};
+
+ private:
+ QString m_name;
+ QString m_createString;
+ QString m_initVersion;
+};
+
+/**
+ * The MyMoneyDbDef class is
+ */
+class MyMoneyDbDef {
+ friend class MyMoneyStorageSql;
+ friend class MyMoneyDatabaseMgr;
+public:
+ MyMoneyDbDef();
+ ~MyMoneyDbDef() {}
+
+ const QString generateSQL (const QString& driver) const;
+
+ typedef QMap<QString, MyMoneyDbTable>::const_iterator table_iterator;
+ inline table_iterator tableBegin(void) const {return m_tables.constBegin();}
+ inline table_iterator tableEnd(void) const {return m_tables.constEnd();}
+
+ typedef QMap<QString, MyMoneyDbView>::const_iterator view_iterator;
+ inline view_iterator viewBegin(void) const {return m_views.constBegin();}
+ inline view_iterator viewEnd(void) const {return m_views.constEnd();}
+
+ inline unsigned int currentVersion() const {return (m_currentVersion);};
+
+private:
+ const QString enclose(const QString& text) const
+ {return (QString("'" + text + "'"));};
+ static unsigned int m_currentVersion; // The current version of the database layout
+ MyMoneyDbDrivers m_drivers;
+#define TABLE(name) void name();
+#define VIEW(name) void name();
+ TABLE(FileInfo);
+ TABLE(Institutions);
+ TABLE(Payees);
+ TABLE(Accounts);
+ TABLE(Transactions);
+ TABLE(Splits);
+ TABLE(KeyValuePairs);
+ TABLE(Schedules);
+ TABLE(SchedulePaymentHistory);
+ TABLE(Securities);
+ TABLE(Prices);
+ TABLE(Currencies);
+ TABLE(Reports);
+ TABLE(Budgets);
+ VIEW(Balances);
+protected:
+ QMap<QString, MyMoneyDbTable> m_tables;
+ QMap<QString, MyMoneyDbView> m_views;
+};
+
+class IMyMoneySerialize;
+
+/**
+ * The MyMoneyDbColumn class is a base type for generic db columns.
+ * Derived types exist for several common column types.
+ */
+class MyMoneyStorageSql : public IMyMoneyStorageFormat, public QSqlDatabase, public KShared {
+public:
+
+ MyMoneyStorageSql (IMyMoneySerialize *storage, const KURL& = KURL());
+ virtual ~MyMoneyStorageSql() {close(true);}
+
+ unsigned int currentVersion() const {return (m_db.currentVersion());};
+
+ /**
+ * MyMoneyStorageSql - open database file
+ *
+ * @param url pseudo-URL of database to be opened
+ * @param openMode open mode, same as for QFile::open
+ * @param clear whether existing data can be deleted
+
+ * @return 0 - database successfully opened
+ * @return 1 - database not opened, use lastError function for reason
+ * @return -1 - output database not opened, contains data, clean not specified
+ *
+ */
+ int open(const KURL& url, int openMode, bool clear = false);
+ /**
+ * MyMoneyStorageSql close the database
+ *
+ * @return void
+ *
+ */
+ void close(bool logoff = true);
+ /**
+ * MyMoneyStorageSql read all the database into storage
+ *
+ * @return void
+ *
+ */
+ bool readFile(void);
+ /**
+ * MyMoneyStorageSql write/update the database from storage
+ *
+ * @return void
+ *
+ */
+ bool writeFile(void);
+
+ // check database type
+ bool isDb2() const { return (m_dbType == Db2);};
+ bool isInterbase() const { return (m_dbType == Interbase);};
+ bool isMysql() const { return (m_dbType == Mysql);};
+ bool isOracle8() const { return (m_dbType == Oracle8);};
+ bool isODBC3() const { return (m_dbType == ODBC3);};
+ bool isPostgresql() const { return (m_dbType == Postgresql);};
+ bool isSybase() const { return (m_dbType == Sybase);};
+ bool isSqlite3() const { return (m_dbType == Sqlite3);};
+
+ /**
+ * MyMoneyStorageSql generalized error routine
+ *
+ * @return : error message to be displayed
+ *
+ */
+ const QString& lastError() const {return (m_error);};
+ /**
+ * This method is used when a database file is open, and the data is to
+ * be saved in a different file or format. It will ensure that all data
+ * from the database is available in memory to enable it to be written.
+ */
+ virtual void fillStorage();
+ /**
+ * The following functions correspond to the identically named (usually) functions
+ * within the Storage Manager, and are called to update the database
+ */
+ void modifyUserInfo(const MyMoneyPayee& payee);
+ void addInstitution(const MyMoneyInstitution& inst);
+ void modifyInstitution(const MyMoneyInstitution& inst);
+ void removeInstitution(const MyMoneyInstitution& inst);
+ void addPayee(const MyMoneyPayee& payee);
+ void modifyPayee(const MyMoneyPayee& payee);
+ void removePayee(const MyMoneyPayee& payee);
+ void addAccount(const MyMoneyAccount& acc);
+ void modifyAccount(const MyMoneyAccount& acc);
+ void removeAccount(const MyMoneyAccount& acc);
+ void addTransaction(const MyMoneyTransaction& tx);
+ void modifyTransaction(const MyMoneyTransaction& tx);
+ void removeTransaction(const MyMoneyTransaction& tx);
+ void addSchedule(const MyMoneySchedule& sch);
+ void modifySchedule(const MyMoneySchedule& sch);
+ void removeSchedule(const MyMoneySchedule& sch);
+ void addSecurity(const MyMoneySecurity& sec);
+ void modifySecurity(const MyMoneySecurity& sec);
+ void removeSecurity(const MyMoneySecurity& sec);
+ void addPrice(const MyMoneyPrice& p);
+ void removePrice(const MyMoneyPrice& p);
+ void addCurrency(const MyMoneySecurity& sec);
+ void modifyCurrency(const MyMoneySecurity& sec);
+ void removeCurrency(const MyMoneySecurity& sec);
+ void addReport(const MyMoneyReport& rep);
+ void modifyReport(const MyMoneyReport& rep);
+ void removeReport(const MyMoneyReport& rep);
+ void addBudget(const MyMoneyBudget& bud);
+ void modifyBudget(const MyMoneyBudget& bud);
+ void removeBudget(const MyMoneyBudget& bud);
+
+ unsigned long transactionCount (const QString& aid = QString()) const;
+ inline const QMap<QString, unsigned long> transactionCountMap () const
+ {return (m_transactionCountMap);};
+ /**
+ * the storage manager also needs the following read entry points
+ */
+ const QMap<QString, MyMoneyAccount> fetchAccounts (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneyMoney> fetchBalance(const QStringList& id, const QDate& date) const;
+ const QMap<QString, MyMoneyBudget> fetchBudgets (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneySecurity> fetchCurrencies (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneyInstitution> fetchInstitutions (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneyPayee> fetchPayees (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const MyMoneyPriceList fetchPrices (const QStringList& fromIdList = QStringList (), const QStringList& toIdList = QStringList(), bool forUpdate = false) const;
+ const MyMoneyPrice fetchSinglePrice (const QString& fromIdList, const QString& toIdList, const QDate& date, bool exactDate, bool forUpdate = false) const;
+ const QMap<QString, MyMoneyReport> fetchReports (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneySchedule> fetchSchedules (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneySecurity> fetchSecurities (const QStringList& idList = QStringList (), bool forUpdate = false) const;
+ const QMap<QString, MyMoneyTransaction> fetchTransactions (const QString& tidList = QString (), const QString& dateClause = QString(), bool forUpdate = false) const;
+ const QMap<QString, MyMoneyTransaction> fetchTransactions (const MyMoneyTransactionFilter& filter) const;
+ bool isReferencedByTransaction(const QString& id) const;
+
+ void readPayees(const QString&);
+ void readPayees(const QValueList<QString> payeeList = QValueList<QString>());
+ void readTransactions(const MyMoneyTransactionFilter& filter);
+ void setProgressCallback(void(*callback)(int, int, const QString&));
+
+ virtual void readFile(QIODevice* s, IMyMoneySerialize* storage) { Q_UNUSED(s); Q_UNUSED(storage) };
+ virtual void writeFile(QIODevice* s, IMyMoneySerialize* storage){ Q_UNUSED(s); Q_UNUSED(storage) };
+
+ void startCommitUnit (const QString& callingFunction);
+ bool endCommitUnit (const QString& callingFunction);
+ void cancelCommitUnit (const QString& callingFunction);
+
+ long unsigned getRecCount(const QString& table) const;
+ long unsigned getNextBudgetId() const;
+ long unsigned getNextAccountId() const;
+ long unsigned getNextInstitutionId() const;
+ long unsigned getNextPayeeId() const;
+ long unsigned getNextReportId() const;
+ long unsigned getNextScheduleId() const;
+ long unsigned getNextSecurityId() const;
+ long unsigned getNextTransactionId() const;
+
+ long unsigned incrementBudgetId();
+ long unsigned incrementAccountId();
+ long unsigned incrementInstitutionId();
+ long unsigned incrementPayeeId();
+ long unsigned incrementReportId();
+ long unsigned incrementScheduleId();
+ long unsigned incrementSecurityId();
+ long unsigned incrementTransactionId();
+
+ void loadAccountId(const unsigned long& id);
+ void loadTransactionId(const unsigned long& id);
+ void loadPayeeId(const unsigned long& id);
+ void loadInstitutionId(const unsigned long& id);
+ void loadScheduleId(const unsigned long& id);
+ void loadSecurityId(const unsigned long& id);
+ void loadReportId(const unsigned long& id);
+ void loadBudgetId(const unsigned long& id);
+
+private:
+ // a function to build a comprehensive error message
+ QString& buildError (const QSqlQuery& q, const QString& function, const QString& message) const;
+ // write routines
+ void writeUserInformation(void);
+ void writeInstitutions(void);
+ void writePayees(void);
+ void writeAccounts(void);
+ void writeTransactions(void);
+ void writeSchedules(void);
+ void writeSecurities(void);
+ void writePrices(void);
+ void writeCurrencies(void);
+ void writeFileInfo(void);
+ void writeReports(void);
+ void writeBudgets(void);
+
+ void writeInstitution(const MyMoneyInstitution& i, MyMoneySqlQuery& q);
+ void writePayee(const MyMoneyPayee& p, MyMoneySqlQuery& q, bool isUserInfo = false);
+ void writeAccount (const MyMoneyAccount& a, MyMoneySqlQuery& q);
+ void writeTransaction(const QString& txId, const MyMoneyTransaction& tx, MyMoneySqlQuery& q, const QString& type);
+ void writeSplits(const QString& txId, const QString& type, const QValueList<MyMoneySplit>& splitList);
+ void writeSplit(const QString& txId, const MyMoneySplit& split, const QString& type, const int splitId, MyMoneySqlQuery& q);
+ void writeSchedule(const MyMoneySchedule& sch, MyMoneySqlQuery& q, bool insert);
+ void writeSecurity(const MyMoneySecurity& security, MyMoneySqlQuery& q);
+ void writePricePair ( const MyMoneyPriceEntries& p);
+ void writePrice (const MyMoneyPrice& p);
+ void writeCurrency(const MyMoneySecurity& currency, MyMoneySqlQuery& q);
+ void writeReport (const MyMoneyReport& rep, MyMoneySqlQuery& q);
+ void writeBudget (const MyMoneyBudget& bud, MyMoneySqlQuery& q);
+ void writeKeyValuePairs(const QString& kvpType, const QString& kvpId, const QMap<QString, QString>& pairs);
+ void writeKeyValuePair(const QString& kvpType, const QString& kvpId,
+ const QString& kvpKey, const QString& kvpData);
+ // read routines
+ void readFileInfo(void);
+ void readLogonData(void);
+ void readUserInformation(void);
+ void readInstitutions(void);
+ void readAccounts(void);
+ void readTransaction(const QString id);
+ void readTransactions(const QString& tidList = QString(), const QString& dateClause = QString());
+ void readTransaction(MyMoneyTransaction &tx, const QString& tid);
+ void readSplit (MyMoneySplit& s, const MyMoneySqlQuery& q, const MyMoneyDbTable& t) const;
+ const MyMoneyKeyValueContainer readKeyValuePairs (const QString& kvpType, const QString& kvpId) const;
+ const QMap<QString, MyMoneyKeyValueContainer> readKeyValuePairs (const QString& kvpType, const QStringList& kvpIdList) const;
+ void readSchedules(void);
+ void readSecurities(void);
+ void readPrices(void);
+ void readCurrencies(void);
+ void readReports(void);
+ void readBudgets(void);
+
+ void deleteTransaction(const QString& id);
+ void deleteSchedule(const QString& id);
+ void deleteKeyValuePairs(const QString& kvpType, const QString& kvpId);
+ long unsigned calcHighId (const long unsigned&, const QString&);
+
+ void setVersion (const QString& version);
+
+ void signalProgress(int current, int total, const QString& = "") const;
+ void (*m_progressCallback)(int, int, const QString&);
+
+ //void startCommitUnit (const QString& callingFunction);
+ //void endCommitUnit (const QString& callingFunction);
+ //void cancelCommitUnit (const QString& callingFunction);
+ int splitState(const MyMoneyTransactionFilter::stateOptionE& state) const;
+
+ inline const QDate getDate (const QString& date) const {
+ return (date.isNull() ? QDate() : QDate::fromString(date, Qt::ISODate));
+ }
+
+ inline const QDateTime getDateTime (const QString& date) const {
+ return (date.isNull() ? QDateTime() : QDateTime::fromString(date, Qt::ISODate));
+ }
+
+ // open routines
+ /**
+ * MyMoneyStorageSql create database
+ *
+ * @param url pseudo-URL of database to be opened
+ *
+ * @return true - creation successful
+ * @return false - could not create
+ *
+ */
+ int createDatabase(const KURL& url);
+ int upgradeDb();
+ int upgradeToV1();
+ int upgradeToV2();
+ int upgradeToV3();
+ int upgradeToV4();
+ int upgradeToV5();
+ int upgradeToV6();
+ bool sqliteAlterTable(const MyMoneyDbTable& t);
+ bool addColumn(const MyMoneyDbTable& t,
+ const MyMoneyDbColumn& c,
+ const QString& after = QString());
+ bool addColumn(const QString& table,
+ const QString& column,
+ const QString& after = QString());
+ bool dropColumn(const MyMoneyDbTable& t,
+ const QString& c);
+ bool dropColumn(const QString& table,
+ const QString& column);
+
+// long long unsigned getRecCount(const QString& table);
+ int createTables();
+ void createTable(const MyMoneyDbTable& t);
+ void clean ();
+ int isEmpty();
+ // data
+ MyMoneyDbDrivers m_drivers;
+ databaseTypeE m_dbType;
+
+ MyMoneyDbDef m_db;
+ unsigned int m_dbVersion;
+ IMyMoneySerialize *m_storage;
+ IMyMoneyStorage *m_storagePtr;
+ // input options
+ bool m_loadAll; // preload all data
+ bool m_override; // override open if already in use
+ // error message
+ QString m_error;
+ // record counts
+ long unsigned m_institutions;
+ long unsigned m_accounts;
+ long unsigned m_payees;
+ long unsigned m_transactions;
+ long unsigned m_splits;
+ long unsigned m_securities;
+ long unsigned m_prices;
+ long unsigned m_currencies;
+ long unsigned m_schedules;
+ long unsigned m_reports;
+ long unsigned m_kvps;
+ long unsigned m_budgets;
+ // next id to use (for future archive)
+ long unsigned m_hiIdInstitutions;
+ long unsigned m_hiIdPayees;
+ long unsigned m_hiIdAccounts;
+ long unsigned m_hiIdTransactions;
+ long unsigned m_hiIdSchedules;
+ long unsigned m_hiIdSecurities;
+ long unsigned m_hiIdReports;
+ long unsigned m_hiIdBudgets;
+ // encrypt option - usage TBD
+ QString m_encryptData;
+
+ /**
+ * This variable is used to suppress status messages except during
+ * initial data load and final write
+
+ */
+ bool m_displayStatus;
+ /**
+ * On occasions, e.g. after a complex transaction search, or for populating a
+ * payee popup list, it becomes necessary to load all data into memory. The
+ * following flags will be set after such a load, to indicate that further
+ * retrievals are not needed.
+ */
+// bool m_transactionListRead;
+// bool m_payeeListRead;
+ /**
+ * This member variable holds a list of those accounts for which all
+ * transactions are in memory, thus saving reading them again
+ */
+// QValueList<QString> m_accountsLoaded;
+ /**
+ * This member variable is used when loading transactions to list all
+ * referenced payees, which can then be read into memory (if not already there)
+ */
+// QValueList<QString> m_payeeList;
+
+ void alert(QString s) const {qDebug("%s", s.ascii());}; // FIXME: remove...
+ /** The following keeps track of commitment units (known as transactions in SQL
+ * though it would be confusing to use that term within KMM). It is implemented
+ * as a stack for debug purposes. Long term, probably a count would suffice
+ */
+ QValueStack<QString> m_commitUnitStack;
+ /**
+ * This member variable is used to preload transactions for preferred accounts
+ */
+ MyMoneyTransactionFilter m_preferred;
+ /**
+ * This member variable is used because reading prices from a file uses the 'add...' function rather than a
+ * 'load...' function which other objects use. Having this variable allows us to avoid needing to check the
+ * database to see if this really is a new or modified price
+ */
+ bool m_readingPrices;
+ /**
+ * This member variable holds a map of transaction counts per account, indexed by
+ * the account id. It is used
+ * to avoid having to scan all transactions whenever a count is needed. It should
+ * probably be moved into the MyMoneyAccount object; maybe we will do that once
+ * the database code has been properly checked out
+ */
+ QMap<QString, unsigned long> m_transactionCountMap;
+ /**
+ * These member variables hold the user name and date/time of logon
+ */
+ QString m_logonUser;
+ QDateTime m_logonAt;
+ QDateTime m_txPostDate; // FIXME: remove when Tom puts date into split object
+
+ //Disable copying
+ MyMoneyStorageSql (const MyMoneyStorageSql& rhs);
+ MyMoneyStorageSql& operator= (const MyMoneyStorageSql& rhs);
+ //
+ bool m_newDatabase;
+};
+#endif // MYMONEYSTORAGESQL_H
diff --git a/kmymoney2/mymoney/storage/mymoneystoragexml.cpp b/kmymoney2/mymoney/storage/mymoneystoragexml.cpp
new file mode 100644
index 0000000..e8027d1
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragexml.cpp
@@ -0,0 +1,908 @@
+/***************************************************************************
+ mymoneystoragexml.cpp - description
+ -------------------
+ begin : Thu Oct 24 2002
+ copyright : (C) 2002 by Kevin Tambascio
+ (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "config.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfile.h>
+#include <qdom.h>
+#include <qmap.h>
+#include <qxml.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneystoragexml.h"
+#include "../mymoneyreport.h"
+#include "../mymoneybudget.h"
+#include "../mymoneyinstitution.h"
+
+unsigned int MyMoneyStorageXML::fileVersionRead = 0;
+unsigned int MyMoneyStorageXML::fileVersionWrite = 0;
+
+
+class MyMoneyStorageXML::Private
+{
+ friend class MyMoneyStorageXML;
+public:
+ Private() {}
+
+ QMap<QString, MyMoneyInstitution> iList;
+ QMap<QString, MyMoneyAccount> aList;
+ QMap<QString, MyMoneyTransaction> tList;
+ QMap<QString, MyMoneyPayee> pList;
+ QMap<QString, MyMoneySchedule> sList;
+ QMap<QString, MyMoneySecurity> secList;
+ QMap<QString, MyMoneyReport> rList;
+ QMap<QString, MyMoneyBudget> bList;
+ QMap<MyMoneySecurityPair, MyMoneyPriceEntries> prList;
+
+ QString m_fromSecurity;
+ QString m_toSecurity;
+
+};
+
+
+class MyMoneyXmlContentHandler : public QXmlContentHandler
+{
+public:
+ MyMoneyXmlContentHandler(MyMoneyStorageXML* reader);
+ virtual ~MyMoneyXmlContentHandler() {}
+ virtual void setDocumentLocator (QXmlLocator * locator) { m_loc = locator; }
+ virtual bool startDocument (void);
+ virtual bool endDocument (void);
+ virtual bool startPrefixMapping(const QString & prefix, const QString & uri);
+ virtual bool endPrefixMapping(const QString & prefix);
+ virtual bool startElement(const QString & namespaceURI, const QString & localName, const QString & qName, const QXmlAttributes & atts);
+ virtual bool endElement(const QString & namespaceURI, const QString & localName, const QString & qName);
+ virtual bool characters(const QString & ch);
+ virtual bool ignorableWhitespace(const QString & ch);
+ virtual bool processingInstruction(const QString & target, const QString & data);
+ virtual bool skippedEntity(const QString & name);
+ virtual QString errorString(void);
+
+private:
+ MyMoneyStorageXML* m_reader;
+ QXmlLocator* m_loc;
+ int m_level;
+ int m_elementCount;
+ QDomDocument m_doc;
+ QDomElement m_baseNode;
+ QDomElement m_currNode;
+ QString m_errMsg;
+};
+
+MyMoneyXmlContentHandler::MyMoneyXmlContentHandler(MyMoneyStorageXML* reader) :
+ m_reader(reader),
+ m_loc(0),
+ m_level(0),
+ m_elementCount(0)
+{
+}
+
+bool MyMoneyXmlContentHandler::startDocument(void)
+{
+ qDebug("startDocument");
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::endDocument(void)
+{
+ qDebug("endDocument");
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::skippedEntity (const QString & /* name */)
+{
+ // qDebug(QString("Skipped entity '%1'").arg(name));
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::startPrefixMapping (const QString& /*prefix */, const QString & /* uri */)
+{
+ // qDebug(QString("start prefix '%1', '%2'").arg(prefix).arg(uri));
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::endPrefixMapping (const QString& /* prefix */)
+{
+ // qDebug(QString("end prefix '%1'").arg(prefix));
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::startElement (const QString& /* namespaceURI */, const QString& /* localName */, const QString& qName, const QXmlAttributes & atts)
+{
+ if(m_level == 0) {
+ QString s = qName.lower();
+ if(s == "transaction"
+ || s == "account"
+ || s == "price"
+ || s == "payee"
+ || s == "currency"
+ || s == "security"
+ || s == "keyvaluepairs"
+ || s == "institution"
+ || s == "report"
+ || s == "budget"
+ || s == "fileinfo"
+ || s == "user"
+ || s == "scheduled_tx") {
+ m_baseNode = m_doc.createElement(qName);
+ for(int i=0; i < atts.count(); ++i) {
+ m_baseNode.setAttribute(atts.qName(i), atts.value(i));
+ }
+ m_currNode = m_baseNode;
+ m_level = 1;
+
+ } else if(s == "transactions") {
+ qDebug("reading transactions");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading transactions..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "accounts") {
+ qDebug("reading accounts");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading accounts..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "securities") {
+ qDebug("reading securities");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading securities..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "reports") {
+ qDebug("reading reports");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading reports..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "prices") {
+ qDebug("reading prices");
+ m_elementCount = 0;
+ } else if(s == "pricepair") {
+ if(atts.count()) {
+ m_reader->d->m_fromSecurity = atts.value(QString("from"));
+ m_reader->d->m_toSecurity = atts.value(QString("to"));
+ }
+ }
+
+ } else {
+ m_level++;
+ QDomElement node = m_doc.createElement(qName);
+ for(int i=0; i < atts.count(); ++i) {
+ node.setAttribute(atts.qName(i), atts.value(i));
+ }
+ m_currNode.appendChild(node);
+ m_currNode = node;
+ }
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::endElement(const QString& /* namespaceURI */, const QString& /* localName */, const QString& qName)
+{
+ bool rc = true;
+ QString s = qName.lower();
+ if(m_level) {
+ m_currNode = m_currNode.parentNode().toElement();
+ m_level--;
+ if(!m_level) {
+ try {
+ if(s == "transaction") {
+ MyMoneyTransaction t(m_baseNode);
+ if(!t.id().isEmpty())
+ m_reader->d->tList[t.uniqueSortKey()] = t;
+ } else if(s == "account") {
+ MyMoneyAccount a(m_baseNode);
+ if(!a.id().isEmpty())
+ m_reader->d->aList[a.id()] = a;
+ } else if(s == "payee") {
+ MyMoneyPayee p(m_baseNode);
+ if(!p.id().isEmpty())
+ m_reader->d->pList[p.id()] = p;
+ } else if(s == "currency") {
+ MyMoneySecurity s(m_baseNode);
+ if(!s.id().isEmpty())
+ m_reader->d->secList[s.id()] = s;
+ } else if(s == "security") {
+ MyMoneySecurity s(m_baseNode);
+ if(!s.id().isEmpty())
+ m_reader->d->secList[s.id()] = s;
+ } else if(s == "keyvaluepairs") {
+ MyMoneyKeyValueContainer kvp(m_baseNode);
+ m_reader->m_storage->setPairs(kvp.pairs());
+ } else if(s == "institution") {
+ MyMoneyInstitution i(m_baseNode);
+ if(!i.id().isEmpty())
+ m_reader->d->iList[i.id()] = i;
+ } else if(s == "report") {
+ MyMoneyReport r(m_baseNode);
+ if(!r.id().isEmpty())
+ m_reader->d->rList[r.id()] = r;
+ } else if(s == "budget") {
+ MyMoneyBudget b(m_baseNode);
+ if(!b.id().isEmpty())
+ m_reader->d->bList[b.id()] = b;
+ } else if(s == "fileinfo") {
+ rc = m_reader->readFileInformation(m_baseNode);
+ } else if(s == "user") {
+ rc = m_reader->readUserInformation(m_baseNode);
+ } else if(s == "scheduled_tx") {
+ MyMoneySchedule s(m_baseNode);
+ if(!s.id().isEmpty())
+ m_reader->d->sList[s.id()] = s;
+ } else if(s == "price") {
+ MyMoneyPrice p(m_reader->d->m_fromSecurity, m_reader->d->m_toSecurity, m_baseNode);
+ m_reader->d->prList[MyMoneySecurityPair(m_reader->d->m_fromSecurity, m_reader->d->m_toSecurity)][p.date()] = p;
+ } else {
+ m_errMsg = i18n("Unknown XML tag %1 found in line %2").arg(qName).arg(m_loc->lineNumber());
+ kdWarning() << m_errMsg << endl;
+ rc = false;
+ }
+ m_reader->signalProgress(++m_elementCount, 0);
+ } catch(MyMoneyException* e) {
+ m_errMsg = i18n("Exception while creating a %1 element: %2").arg(s).arg(e->what());
+ kdWarning() << m_errMsg << endl;
+ delete e;
+ rc = false;
+ }
+ m_doc = QDomDocument();
+ }
+ } else {
+ if(s == "institutions") {
+ // last institution read, now dump them into the engine
+ m_reader->m_storage->loadInstitutions(m_reader->d->iList);
+ m_reader->d->iList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "accounts") {
+ // last account read, now dump them into the engine
+ m_reader->m_storage->loadAccounts(m_reader->d->aList);
+ m_reader->d->aList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "payees") {
+ // last payee read, now dump them into the engine
+ m_reader->m_storage->loadPayees(m_reader->d->pList);
+ m_reader->d->pList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "transactions") {
+ // last transaction read, now dump them into the engine
+ m_reader->m_storage->loadTransactions(m_reader->d->tList);
+ m_reader->d->tList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "schedules") {
+ // last schedule read, now dump them into the engine
+ m_reader->m_storage->loadSchedules(m_reader->d->sList);
+ m_reader->d->sList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "securities") {
+ // last security read, now dump them into the engine
+ m_reader->m_storage->loadSecurities(m_reader->d->secList);
+ m_reader->d->secList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "currencies") {
+ // last currency read, now dump them into the engine
+ m_reader->m_storage->loadCurrencies(m_reader->d->secList);
+ m_reader->d->secList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "reports") {
+ // last report read, now dump them into the engine
+ m_reader->m_storage->loadReports(m_reader->d->rList);
+ m_reader->d->rList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "budgets") {
+ // last budget read, now dump them into the engine
+ m_reader->m_storage->loadBudgets(m_reader->d->bList);
+ m_reader->d->bList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "prices") {
+ // last price read, now dump them into the engine
+ m_reader->m_storage->loadPrices(m_reader->d->prList);
+ m_reader->d->bList.clear();
+ m_reader->signalProgress(-1, -1);
+ }
+ }
+ return rc;
+}
+
+bool MyMoneyXmlContentHandler::characters(const QString& /* ch */)
+{
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::ignorableWhitespace(const QString& /* ch */)
+{
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::processingInstruction(const QString& /* target */, const QString& /* data */)
+{
+ return true;
+}
+
+QString MyMoneyXmlContentHandler::errorString(void)
+{
+ return m_errMsg;
+}
+
+
+
+
+
+
+
+MyMoneyStorageXML::MyMoneyStorageXML() :
+ m_storage(0),
+ m_doc(0),
+ d(new Private())
+{
+}
+
+MyMoneyStorageXML::~MyMoneyStorageXML()
+{
+ delete d;
+}
+
+// Function to read in the file, send to XML parser.
+void MyMoneyStorageXML::readFile(QIODevice* pDevice, IMyMoneySerialize* storage)
+{
+ Q_CHECK_PTR(storage);
+ Q_CHECK_PTR(pDevice);
+ if(!storage)
+ return;
+
+ m_storage = storage;
+
+ m_doc = new QDomDocument;
+ Q_CHECK_PTR(m_doc);
+
+ qDebug("reading file");
+ // creating the QXmlInputSource object based on a QIODevice object
+ // reads all data of the underlying object into memory. I have not
+ // found an object that reads on the fly. I tried to derive one myself,
+ // but there could be a severe problem with decoding when reading
+ // blocks of data and not a stream. So I left it the way it is. (ipwizard)
+ QXmlInputSource xml(pDevice);
+
+ qDebug("start parsing file");
+ MyMoneyXmlContentHandler mmxml(this);
+ QXmlSimpleReader reader;
+ reader.setContentHandler(&mmxml);
+
+ if(!reader.parse(&xml, false)) {
+ delete m_doc;
+ m_doc = NULL;
+ signalProgress(-1, -1);
+ throw new MYMONEYEXCEPTION("File was not parsable!");
+ }
+
+ // check if we need to build up the account balances
+ if(fileVersionRead < 2)
+ m_storage->rebuildAccountBalances();
+
+ delete m_doc;
+ m_doc = NULL;
+
+ // this seems to be nonsense, but it clears the dirty flag
+ // as a side-effect.
+ m_storage->setLastModificationDate(m_storage->lastModificationDate());
+ m_storage = NULL;
+
+ //hides the progress bar.
+ signalProgress(-1, -1);
+}
+
+void MyMoneyStorageXML::writeFile(QIODevice* qf, IMyMoneySerialize* storage)
+{
+ Q_CHECK_PTR(qf);
+ Q_CHECK_PTR(storage);
+ if(!storage)
+ {
+ return;
+ }
+ m_storage = storage;
+
+ // qDebug("XMLWRITER: Starting file write");
+ m_doc = new QDomDocument("KMYMONEY-FILE");
+ Q_CHECK_PTR(m_doc);
+ QDomProcessingInstruction instruct = m_doc->createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");
+ m_doc->appendChild(instruct);
+
+ QDomElement mainElement = m_doc->createElement("KMYMONEY-FILE");
+ m_doc->appendChild(mainElement);
+
+ QDomElement fileInfo = m_doc->createElement("FILEINFO");
+ writeFileInformation(fileInfo);
+ mainElement.appendChild(fileInfo);
+
+ QDomElement userInfo = m_doc->createElement("USER");
+ writeUserInformation(userInfo);
+ mainElement.appendChild(userInfo);
+
+ QDomElement institutions = m_doc->createElement("INSTITUTIONS");
+ writeInstitutions(institutions);
+ mainElement.appendChild(institutions);
+
+ QDomElement payees = m_doc->createElement("PAYEES");
+ writePayees(payees);
+ mainElement.appendChild(payees);
+
+ QDomElement accounts = m_doc->createElement("ACCOUNTS");
+ writeAccounts(accounts);
+ mainElement.appendChild(accounts);
+
+ QDomElement transactions = m_doc->createElement("TRANSACTIONS");
+ writeTransactions(transactions);
+ mainElement.appendChild(transactions);
+
+ QDomElement keyvalpairs = writeKeyValuePairs(m_storage->pairs());
+ mainElement.appendChild(keyvalpairs);
+
+ QDomElement schedules = m_doc->createElement("SCHEDULES");
+ writeSchedules(schedules);
+ mainElement.appendChild(schedules);
+
+ QDomElement equities = m_doc->createElement("SECURITIES");
+ writeSecurities(equities);
+ mainElement.appendChild(equities);
+
+ QDomElement currencies = m_doc->createElement("CURRENCIES");
+ writeCurrencies(currencies);
+ mainElement.appendChild(currencies);
+
+ QDomElement prices = m_doc->createElement("PRICES");
+ writePrices(prices);
+ mainElement.appendChild(prices);
+
+ QDomElement reports = m_doc->createElement("REPORTS");
+ writeReports(reports);
+ mainElement.appendChild(reports);
+
+ QDomElement budgets = m_doc->createElement("BUDGETS");
+ writeBudgets(budgets);
+ mainElement.appendChild(budgets);
+
+ QTextStream stream(qf);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << m_doc->toString();
+
+ delete m_doc;
+ m_doc = NULL;
+
+ //hides the progress bar.
+ signalProgress(-1, -1);
+
+ // this seems to be nonsense, but it clears the dirty flag
+ // as a side-effect.
+ m_storage->setLastModificationDate(m_storage->lastModificationDate());
+
+ m_storage = NULL;
+}
+
+bool MyMoneyStorageXML::readFileInformation(const QDomElement& fileInfo)
+{
+ signalProgress(0, 3, i18n("Loading file information..."));
+ bool rc = true;
+ QDomElement temp = findChildElement("CREATION_DATE", fileInfo);
+ if (temp == QDomElement()) {
+ rc = false;
+ }
+ QString strDate = QStringEmpty(temp.attribute("date"));
+ m_storage->setCreationDate(stringToDate(strDate));
+ signalProgress(1, 0);
+
+ temp = findChildElement("LAST_MODIFIED_DATE", fileInfo);
+ if (temp == QDomElement()) {
+ rc = false;
+ }
+ strDate = QStringEmpty(temp.attribute("date"));
+ m_storage->setLastModificationDate(stringToDate(strDate));
+ signalProgress(2, 0);
+
+ temp = findChildElement("VERSION", fileInfo);
+ if (temp == QDomElement()) {
+ rc = false;
+ }
+ QString strVersion = QStringEmpty(temp.attribute("id"));
+ fileVersionRead = strVersion.toUInt(NULL, 16);
+
+ temp = findChildElement("FIXVERSION", fileInfo);
+ if (temp != QDomElement()) {
+ QString strFixVersion = QStringEmpty(temp.attribute("id"));
+ m_storage->setFileFixVersion (strFixVersion.toUInt());
+ }
+ // FIXME The old version stuff used this rather odd number
+ // We now use increments
+ if(fileVersionRead == VERSION_0_60_XML)
+ fileVersionRead = 1;
+ signalProgress(3, 0);
+
+ return rc;
+}
+
+void MyMoneyStorageXML::writeFileInformation(QDomElement& fileInfo)
+{
+ QDomElement creationDate = m_doc->createElement("CREATION_DATE");
+ creationDate.setAttribute("date", dateToString(m_storage->creationDate()));
+ fileInfo.appendChild(creationDate);
+
+ QDomElement lastModifiedDate = m_doc->createElement("LAST_MODIFIED_DATE");
+ lastModifiedDate.setAttribute("date", dateToString(m_storage->lastModificationDate()));
+ fileInfo.appendChild(lastModifiedDate);
+
+ QDomElement version = m_doc->createElement("VERSION");
+
+ version.setAttribute("id", "1");
+ fileInfo.appendChild(version);
+
+ QDomElement fixVersion = m_doc->createElement("FIXVERSION");
+ fixVersion.setAttribute("id", m_storage->fileFixVersion());
+ fileInfo.appendChild(fixVersion);
+}
+
+void MyMoneyStorageXML::writeUserInformation(QDomElement& userInfo)
+{
+ MyMoneyPayee user = m_storage->user();
+ userInfo.setAttribute("name", user.name());
+ userInfo.setAttribute("email", user.email());
+
+ QDomElement address = m_doc->createElement("ADDRESS");
+ address.setAttribute("street", user.address());
+ address.setAttribute("city", user.city());
+ address.setAttribute("county", user.state());
+ address.setAttribute("zipcode", user.postcode());
+ address.setAttribute("telephone", user.telephone());
+
+ userInfo.appendChild(address);
+}
+
+bool MyMoneyStorageXML::readUserInformation(const QDomElement& userElement)
+{
+ bool rc = true;
+ signalProgress(0, 1, i18n("Loading user information..."));
+
+ MyMoneyPayee user;
+ user.setName(QStringEmpty(userElement.attribute("name")));
+ user.setEmail(QStringEmpty(userElement.attribute("email")));
+
+ QDomElement addressNode = findChildElement("ADDRESS", userElement);
+ if(!addressNode.isNull()) {
+ user.setAddress(QStringEmpty(addressNode.attribute("street")));
+ user.setCity(QStringEmpty(addressNode.attribute("city")));
+ user.setState(QStringEmpty(addressNode.attribute("county")));
+ user.setPostcode(QStringEmpty(addressNode.attribute("zipcode")));
+ user.setTelephone(QStringEmpty(addressNode.attribute("telephone")));
+ }
+
+ m_storage->setUser(user);
+ signalProgress(1, 0);
+
+ return rc;
+}
+
+void MyMoneyStorageXML::writeInstitutions(QDomElement& institutions)
+{
+ const QValueList<MyMoneyInstitution> list = m_storage->institutionList();
+ QValueList<MyMoneyInstitution>::ConstIterator it;
+ institutions.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ writeInstitution(institutions, *it);
+}
+
+void MyMoneyStorageXML::writeInstitution(QDomElement& institution, const MyMoneyInstitution& i)
+{
+ i.writeXML(*m_doc, institution);
+}
+
+void MyMoneyStorageXML::writePayees(QDomElement& payees)
+{
+ const QValueList<MyMoneyPayee> list = m_storage->payeeList();
+ QValueList<MyMoneyPayee>::ConstIterator it;
+ payees.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ writePayee(payees, *it);
+}
+
+void MyMoneyStorageXML::writePayee(QDomElement& payee, const MyMoneyPayee& p)
+{
+ p.writeXML(*m_doc, payee);
+}
+
+void MyMoneyStorageXML::writeAccounts(QDomElement& accounts)
+{
+ QValueList<MyMoneyAccount> list;
+ m_storage->accountList(list);
+ QValueList<MyMoneyAccount>::ConstIterator it;
+ accounts.setAttribute("count", list.count()+5);
+
+ writeAccount(accounts, m_storage->asset());
+ writeAccount(accounts, m_storage->liability());
+ writeAccount(accounts, m_storage->expense());
+ writeAccount(accounts, m_storage->income());
+ writeAccount(accounts, m_storage->equity());
+
+ signalProgress(0, list.count(), i18n("Saving accounts..."));
+ int i = 0;
+ for(it = list.begin(); it != list.end(); ++it, ++i) {
+ writeAccount(accounts, *it);
+ signalProgress(i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeAccount(QDomElement& account, const MyMoneyAccount& p)
+{
+ p.writeXML(*m_doc, account);
+}
+
+void MyMoneyStorageXML::writeTransactions(QDomElement& transactions)
+{
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> list;
+ m_storage->transactionList(list, filter);
+ transactions.setAttribute("count", list.count());
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+
+ signalProgress(0, list.count(), i18n("Saving transactions..."));
+
+ int i = 0;
+ for(it = list.begin(); it != list.end(); ++it, ++i)
+ {
+ writeTransaction(transactions, *it);
+ signalProgress(i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeTransaction(QDomElement& transaction, const MyMoneyTransaction& tx)
+{
+ tx.writeXML(*m_doc, transaction);
+}
+
+void MyMoneyStorageXML::writeSchedules(QDomElement& scheduled)
+{
+ const QValueList<MyMoneySchedule> list = m_storage->scheduleList();
+ QValueList<MyMoneySchedule>::ConstIterator it;
+ scheduled.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ this->writeSchedule(scheduled, *it);
+ }
+}
+
+void MyMoneyStorageXML::writeSchedule(QDomElement& scheduledTx, const MyMoneySchedule& tx)
+{
+ tx.writeXML(*m_doc, scheduledTx);
+}
+
+void MyMoneyStorageXML::writeSecurities(QDomElement& equities)
+{
+ const QValueList<MyMoneySecurity> securityList = m_storage->securityList();
+ equities.setAttribute("count", securityList.count());
+ if(securityList.size())
+ {
+ for(QValueList<MyMoneySecurity>::ConstIterator it = securityList.begin(); it != securityList.end(); ++it)
+ {
+ writeSecurity(equities, (*it));
+ }
+ }
+}
+
+void MyMoneyStorageXML::writeSecurity(QDomElement& securityElement, const MyMoneySecurity& security)
+{
+ security.writeXML(*m_doc, securityElement);
+}
+
+void MyMoneyStorageXML::writeCurrencies(QDomElement& currencies)
+{
+ const QValueList<MyMoneySecurity> currencyList = m_storage->currencyList();
+ currencies.setAttribute("count", currencyList.count());
+ if(currencyList.size())
+ {
+ for(QValueList<MyMoneySecurity>::ConstIterator it = currencyList.begin(); it != currencyList.end(); ++it)
+ {
+ writeSecurity(currencies, (*it));
+ }
+ }
+}
+
+void MyMoneyStorageXML::writeReports(QDomElement& parent)
+{
+ const QValueList<MyMoneyReport> list = m_storage->reportList();
+ QValueList<MyMoneyReport>::ConstIterator it;
+ parent.setAttribute("count", list.count());
+
+ signalProgress(0, list.count(), i18n("Saving reports..."));
+ unsigned i = 0;
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ (*it).writeXML(*m_doc, parent);
+ signalProgress(++i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeBudgets(QDomElement& parent)
+{
+ const QValueList<MyMoneyBudget> list = m_storage->budgetList();
+ QValueList<MyMoneyBudget>::ConstIterator it;
+ parent.setAttribute("count", list.count());
+
+ signalProgress(0, list.count(), i18n("Saving budgets..."));
+ unsigned i = 0;
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ writeBudget(parent, (*it));
+ signalProgress(++i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeBudget(QDomElement& budget, const MyMoneyBudget& b)
+{
+ b.writeXML(*m_doc, budget);
+}
+
+
+QDomElement MyMoneyStorageXML::findChildElement(const QString& name, const QDomElement& root)
+{
+ QDomNode child = root.firstChild();
+ while(!child.isNull())
+ {
+ if(child.isElement())
+ {
+ QDomElement childElement = child.toElement();
+ if(name == childElement.tagName())
+ {
+ return childElement;
+ }
+ }
+
+ child = child.nextSibling();
+ }
+ return QDomElement();
+}
+
+QDomElement MyMoneyStorageXML::writeKeyValuePairs(const QMap<QString, QString> pairs)
+{
+ if(m_doc)
+ {
+ QDomElement keyValPairs = m_doc->createElement("KEYVALUEPAIRS");
+
+ QMap<QString, QString>::const_iterator it;
+ for(it = pairs.begin(); it != pairs.end(); ++it)
+ {
+ QDomElement pair = m_doc->createElement("PAIR");
+ pair.setAttribute("key", it.key());
+ pair.setAttribute("value", it.data());
+ keyValPairs.appendChild(pair);
+ }
+ return keyValPairs;
+ }
+ return QDomElement();
+}
+
+void MyMoneyStorageXML::writePrices(QDomElement& prices)
+{
+ const MyMoneyPriceList list = m_storage->priceList();
+ MyMoneyPriceList::ConstIterator it;
+ prices.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ QDomElement price = m_doc->createElement("PRICEPAIR");
+ price.setAttribute("from", it.key().first);
+ price.setAttribute("to", it.key().second);
+ writePricePair(price, *it);
+ prices.appendChild(price);
+ }
+}
+
+void MyMoneyStorageXML::writePricePair(QDomElement& price, const MyMoneyPriceEntries& p)
+{
+ MyMoneyPriceEntries::ConstIterator it;
+ for(it = p.begin(); it != p.end(); ++it) {
+ QDomElement entry = m_doc->createElement("PRICE");
+ writePrice(entry, *it);
+ price.appendChild(entry);
+ }
+}
+
+void MyMoneyStorageXML::writePrice(QDomElement& price, const MyMoneyPrice& p)
+{
+ price.setAttribute("date", p.date().toString(Qt::ISODate));
+ price.setAttribute("price", p.rate(QString()).toString());
+ price.setAttribute("source", p.source());
+}
+
+void MyMoneyStorageXML::setProgressCallback(void(*callback)(int, int, const QString&))
+{
+ m_progressCallback = callback;
+}
+
+void MyMoneyStorageXML::signalProgress(int current, int total, const QString& msg)
+{
+ if(m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+}
+
+/*!
+ This convenience function returns all of the remaining data in the
+ device.
+
+ @note It's copied from the original Qt sources and modified to
+ fix a problem with KFilterDev that does not correctly return
+ atEnd() status in certain circumstances which caused our
+ application to lock at startup.
+*/
+QByteArray QIODevice::readAll()
+{
+ if ( isDirectAccess() ) {
+ // we know the size
+ int n = size()-at(); // ### fix for 64-bit or large files?
+ int totalRead = 0;
+ QByteArray ba( n );
+ char* c = ba.data();
+ while ( n ) {
+ int r = readBlock( c, n );
+ if ( r < 0 )
+ return QByteArray();
+ n -= r;
+ c += r;
+ totalRead += r;
+ // If we have a translated file, then it is possible that
+ // we read less bytes than size() reports
+ if ( atEnd() ) {
+ ba.resize( totalRead );
+ break;
+ }
+ }
+ return ba;
+ } else {
+ // read until we reach the end
+ const int blocksize = 512;
+ int nread = 0;
+ QByteArray ba;
+ int r = 1;
+ while ( !atEnd() && r != 0) {
+ ba.resize( nread + blocksize );
+ r = readBlock( ba.data()+nread, blocksize );
+ if ( r < 0 )
+ return QByteArray();
+ nread += r;
+ }
+ ba.resize( nread );
+ return ba;
+ }
+}
+
diff --git a/kmymoney2/mymoney/storage/mymoneystoragexml.h b/kmymoney2/mymoney/storage/mymoneystoragexml.h
new file mode 100644
index 0000000..8485978
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragexml.h
@@ -0,0 +1,156 @@
+/***************************************************************************
+ mymoneystoragexml.h - description
+ -------------------
+ begin : Thu Oct 24 2002
+ copyright : (C) 2002 by Kevin Tambascio
+ (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYSTORAGEXML_H
+#define MYMONEYSTORAGEXML_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdom.h>
+#include <qdatastream.h>
+class QIODevice;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "imymoneyserialize.h"
+#include "imymoneystorageformat.h"
+class MyMoneyXmlContentHandler;
+
+/**
+ *@author Kevin Tambascio (ktambascio@users.sourceforge.net)
+ */
+
+#define VERSION_0_60_XML 0x10000010 // Version 0.5 file version info
+#define VERSION_0_61_XML 0x10000011 // use 8 bytes for MyMoneyMoney objects
+
+class MyMoneyStorageXML : public IMyMoneyStorageFormat
+{
+ friend class MyMoneyXmlContentHandler;
+public:
+ MyMoneyStorageXML();
+ virtual ~MyMoneyStorageXML();
+
+ enum fileVersionDirectionType {
+ Reading = 0, /**< version of file to be read */
+ Writing = 1 /**< version to be used when writing a file */
+ };
+
+protected:
+ void setProgressCallback(void(*callback)(int, int, const QString&));
+ void signalProgress(int current, int total, const QString& = "");
+
+ /**
+ * This method returns the version of the underlying file. It
+ * is used by the MyMoney objects contained in a MyMoneyStorageBin object (e.g.
+ * MyMoneyAccount, MyMoneyInstitution, MyMoneyTransaction, etc.) to
+ * determine the layout used when reading/writing a persistant file.
+ * A parameter is used to determine the direction.
+ *
+ * @param dir information about the direction (reading/writing). The
+ * default is reading.
+ *
+ * @return version QString of file's version
+ *
+ * @see m_fileVersionRead, m_fileVersionWrite
+ */
+ static unsigned int fileVersion(fileVersionDirectionType dir = Reading);
+
+ QValueList<QDomElement> readElements(QString groupTag, QString itemTag = QString());
+
+ bool readFileInformation(const QDomElement& fileInfo);
+ virtual void writeFileInformation(QDomElement& fileInfo);
+
+ virtual void writeUserInformation(QDomElement& userInfo);
+
+ virtual void writeInstitution(QDomElement& institutions, const MyMoneyInstitution& i);
+ virtual void writeInstitutions(QDomElement& institutions);
+
+ virtual void writePrices(QDomElement& prices);
+ virtual void writePricePair(QDomElement& price, const MyMoneyPriceEntries& p);
+ virtual void writePrice(QDomElement& prices, const MyMoneyPrice& p);
+
+ virtual void writePayees(QDomElement& payees);
+ virtual void writePayee(QDomElement& payees, const MyMoneyPayee& p);
+
+ virtual void writeAccounts(QDomElement& accounts);
+ virtual void writeAccount(QDomElement& accounts, const MyMoneyAccount& p);
+
+ virtual void writeTransactions(QDomElement& transactions);
+ virtual void writeTransaction(QDomElement& transactions, const MyMoneyTransaction& tx);
+
+ virtual void writeSchedules(QDomElement& scheduled);
+ virtual void writeSchedule(QDomElement& scheduledTx, const MyMoneySchedule& tx);
+
+ virtual void writeReports(QDomElement& e);
+ virtual void writeBudgets(QDomElement& e);
+ virtual void writeBudget(QDomElement& budget, const MyMoneyBudget& b);
+
+ virtual void writeSecurities(QDomElement& securities);
+ virtual void writeSecurity(QDomElement& securityElement, const MyMoneySecurity& security);
+
+ virtual void writeCurrencies(QDomElement& currencies);
+
+ virtual QDomElement writeKeyValuePairs(const QMap<QString, QString> pairs);
+
+ virtual void readFile(QIODevice* s, IMyMoneySerialize* storage);
+ virtual void writeFile(QIODevice* s, IMyMoneySerialize* storage);
+
+ bool readUserInformation(const QDomElement& userElement);
+
+ void readPricePair(const QDomElement& pricePair);
+ const MyMoneyPrice readPrice(const QString& from, const QString& to, const QDomElement& price);
+
+ QDomElement findChildElement(const QString& name, const QDomElement& root);
+
+private:
+ void (*m_progressCallback)(int, int, const QString&);
+
+protected:
+ IMyMoneySerialize *m_storage;
+ QDomDocument *m_doc;
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ /**
+ * This member is used to store the file version information
+ * obtained while reading a file.
+ */
+ static unsigned int fileVersionRead;
+
+ /**
+ * This member is used to store the file version information
+ * to be used when writing a file.
+ */
+ static unsigned int fileVersionWrite;
+ /**
+ * This member keeps the id of the base currency. We need this
+ * temporarily to convert the price history from the old to the
+ * new format. This should go at some time beyond 0.8 (ipwizard)
+ */
+ QString m_baseCurrencyId;
+
+};
+
+#endif
diff --git a/kmymoney2/pics/CMakeLists.txt b/kmymoney2/pics/CMakeLists.txt
new file mode 100644
index 0000000..6723c09
--- /dev/null
+++ b/kmymoney2/pics/CMakeLists.txt
@@ -0,0 +1,16 @@
+INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR} )
+
+
+########### install files ###############
+
+INSTALL(FILES startlogo.png titlelabel_background.png
+ DESTINATION share/apps/kmymoney2/pics/
+)
+
+
+
+#original Makefile.am contents follow:
+
+#kmymoneydir = $(kde_datadir)/kmymoney2/pics/
+#kmymoney_DATA = startlogo.png titlelabel_background.png
+#
diff --git a/kmymoney2/pics/Makefile.am b/kmymoney2/pics/Makefile.am
new file mode 100644
index 0000000..8d4cd65
--- /dev/null
+++ b/kmymoney2/pics/Makefile.am
@@ -0,0 +1,3 @@
+kmymoneydir = $(kde_datadir)/kmymoney2/pics/
+kmymoney_DATA = startlogo.png titlelabel_background.png
+
diff --git a/kmymoney2/pics/check-16.png b/kmymoney2/pics/check-16.png
new file mode 100644
index 0000000..10dac2d
--- /dev/null
+++ b/kmymoney2/pics/check-16.png
Binary files differ
diff --git a/kmymoney2/pics/check-20.png b/kmymoney2/pics/check-20.png
new file mode 100644
index 0000000..c2c0428
--- /dev/null
+++ b/kmymoney2/pics/check-20.png
Binary files differ
diff --git a/kmymoney2/pics/frozen.png b/kmymoney2/pics/frozen.png
new file mode 100644
index 0000000..1472125
--- /dev/null
+++ b/kmymoney2/pics/frozen.png
Binary files differ
diff --git a/kmymoney2/pics/kmm-frozen.png b/kmymoney2/pics/kmm-frozen.png
new file mode 100644
index 0000000..b71b9ed
--- /dev/null
+++ b/kmymoney2/pics/kmm-frozen.png
Binary files differ
diff --git a/kmymoney2/pics/lock-16.png b/kmymoney2/pics/lock-16.png
new file mode 100644
index 0000000..e104273
--- /dev/null
+++ b/kmymoney2/pics/lock-16.png
Binary files differ
diff --git a/kmymoney2/pics/paperclip-diag.png b/kmymoney2/pics/paperclip-diag.png
new file mode 100644
index 0000000..3e55a06
--- /dev/null
+++ b/kmymoney2/pics/paperclip-diag.png
Binary files differ
diff --git a/kmymoney2/pics/paperclip-diag16.png b/kmymoney2/pics/paperclip-diag16.png
new file mode 100644
index 0000000..b5d7c5f
--- /dev/null
+++ b/kmymoney2/pics/paperclip-diag16.png
Binary files differ
diff --git a/kmymoney2/pics/paperclip-vert.png b/kmymoney2/pics/paperclip-vert.png
new file mode 100644
index 0000000..1453e25
--- /dev/null
+++ b/kmymoney2/pics/paperclip-vert.png
Binary files differ
diff --git a/kmymoney2/pics/reconciled-frozen.png b/kmymoney2/pics/reconciled-frozen.png
new file mode 100644
index 0000000..edb2e9f
--- /dev/null
+++ b/kmymoney2/pics/reconciled-frozen.png
Binary files differ
diff --git a/kmymoney2/pics/reconciled-frozen2.png b/kmymoney2/pics/reconciled-frozen2.png
new file mode 100644
index 0000000..798ecd9
--- /dev/null
+++ b/kmymoney2/pics/reconciled-frozen2.png
Binary files differ
diff --git a/kmymoney2/pics/reconciled.png b/kmymoney2/pics/reconciled.png
new file mode 100644
index 0000000..efca356
--- /dev/null
+++ b/kmymoney2/pics/reconciled.png
Binary files differ
diff --git a/kmymoney2/pics/split-1.png b/kmymoney2/pics/split-1.png
new file mode 100644
index 0000000..0602343
--- /dev/null
+++ b/kmymoney2/pics/split-1.png
Binary files differ
diff --git a/kmymoney2/pics/split-2.png b/kmymoney2/pics/split-2.png
new file mode 100644
index 0000000..5f5acb0
--- /dev/null
+++ b/kmymoney2/pics/split-2.png
Binary files differ
diff --git a/kmymoney2/pics/startlogo.png b/kmymoney2/pics/startlogo.png
new file mode 100644
index 0000000..d295a1f
--- /dev/null
+++ b/kmymoney2/pics/startlogo.png
Binary files differ
diff --git a/kmymoney2/pics/titlelabel_background.png b/kmymoney2/pics/titlelabel_background.png
new file mode 100644
index 0000000..173de04
--- /dev/null
+++ b/kmymoney2/pics/titlelabel_background.png
Binary files differ
diff --git a/kmymoney2/plugins/Makefile.am b/kmymoney2/plugins/Makefile.am
new file mode 100644
index 0000000..9b67654
--- /dev/null
+++ b/kmymoney2/plugins/Makefile.am
@@ -0,0 +1,24 @@
+KDE_OPTIONS = noautodist
+
+METASOURCES = AUTO
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+
+# since some of the subdirs are conditional, we need to define DIST_SUBDIRS
+SUBDIRS = interfaces @OFX_IMPORTERPLUGIN@
+DIST_SUBDIRS = interfaces ofximport
+
+# The library containing the plugin base class
+lib_LTLIBRARIES = libkmm_plugin.la
+libkmm_plugin_la_SOURCES = kmymoneyplugin.cpp pluginloader.cpp viewinterface.cpp statementinterface.cpp importinterface.cpp
+libkmm_plugin_la_LDFLAGS = $(all_libraries) -version-info 0:0:0
+
+#definition of the service type
+kde_servicetypes_DATA = kmymoneyplugin.desktop kmymoneyimporterplugin.desktop
+
+# make sure this lib is build before any subdirectory
+BUILT_SOURCES = libkmm_plugin.la
+
+pluginsincludedir = $(includedir)/kmymoney
+pluginsinclude_HEADERS = kmymoneyplugin.h pluginloader.h viewinterface.h statementinterface.h importinterface.h
+
+EXTRA_DIST = kmymoneyplugin.desktop kmymoneyimporterplugin.desktop
diff --git a/kmymoney2/plugins/importinterface.cpp b/kmymoney2/plugins/importinterface.cpp
new file mode 100644
index 0000000..ce867c8
--- /dev/null
+++ b/kmymoney2/plugins/importinterface.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ importinterface.cpp
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "importinterface.h"
+
+KMyMoneyPlugin::ImportInterface::ImportInterface(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+#include "importinterface.moc"
diff --git a/kmymoney2/plugins/importinterface.h b/kmymoney2/plugins/importinterface.h
new file mode 100644
index 0000000..4b8a347
--- /dev/null
+++ b/kmymoney2/plugins/importinterface.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ importinterface.h
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMPORTINTERFACE_H
+#define IMPORTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kfile.h>
+#include <kurl.h>
+class KPopupMenu;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This abstract class represents the ImportInterface to
+ * add new importers to KMyMoney.
+ */
+class KMYMONEY_EXPORT ImportInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+ ImportInterface(QObject* parent, const char* name = 0);
+ ~ImportInterface() {}
+
+ virtual KURL selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode) const = 0;
+
+signals:
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/interfaces/Makefile.am b/kmymoney2/plugins/interfaces/Makefile.am
new file mode 100644
index 0000000..2b3c761
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/Makefile.am
@@ -0,0 +1,13 @@
+KDE_OPTIONS = noautodist
+
+METASOURCES = AUTO
+INCLUDES = $(all_includes) -I$(top_srcdir) -I. -I$(top_srcdir)/kmymoney2/widgets
+
+SUBDIRS =
+
+noinst_LIBRARIES = libinterfaces.a
+
+libinterfaces_a_SOURCES = kmmviewinterface.cpp kmmstatementinterface.cpp kmmimportinterface.cpp
+
+noinst_HEADERS = kmmviewinterface.h kmmstatementinterface.h kmmimportinterface.h
+
diff --git a/kmymoney2/plugins/interfaces/kmmimportinterface.cpp b/kmymoney2/plugins/interfaces/kmmimportinterface.cpp
new file mode 100644
index 0000000..b3c54d8
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmimportinterface.cpp
@@ -0,0 +1,41 @@
+/***************************************************************************
+ kmmimportinterface.cpp
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../../kmymoney2.h"
+#include "kmmimportinterface.h"
+
+KMyMoneyPlugin::KMMImportInterface::KMMImportInterface(KMyMoney2App* app, QObject* parent, const char* name) :
+ ImportInterface(parent, name),
+ m_app(app)
+{
+}
+
+KURL KMyMoneyPlugin::KMMImportInterface::selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode) const
+{
+ return m_app->selectFile(title, path, mask, mode);
+}
+
+#include "kmmimportinterface.moc"
diff --git a/kmymoney2/plugins/interfaces/kmmimportinterface.h b/kmymoney2/plugins/interfaces/kmmimportinterface.h
new file mode 100644
index 0000000..484a228
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmimportinterface.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ kmmimportinterface.h
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMMIMPORTINTERFACE_H
+#define KMMIMPORTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kfile.h>
+#include <kurl.h>
+class KMyMoney2App;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../importinterface.h"
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class represents the implementation of the
+ * ViewInterface.
+ */
+class KMMImportInterface : public ImportInterface {
+ Q_OBJECT
+
+public:
+ KMMImportInterface(KMyMoney2App* app, QObject* parent, const char* name = 0);
+ ~KMMImportInterface() {}
+
+ KURL selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode) const;
+
+private:
+ KMyMoney2App* m_app;
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/interfaces/kmmstatementinterface.cpp b/kmymoney2/plugins/interfaces/kmmstatementinterface.cpp
new file mode 100644
index 0000000..9e09db2
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmstatementinterface.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ kmmstatementinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmmstatementinterface.h"
+#include "../../kmymoney2.h"
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+
+KMyMoneyPlugin::KMMStatementInterface::KMMStatementInterface(KMyMoney2App* app, QObject* parent, const char* name) :
+ StatementInterface(parent, name),
+ m_app(app)
+{
+}
+
+bool KMyMoneyPlugin::KMMStatementInterface::import(const MyMoneyStatement& s)
+{
+ qDebug("KMyMoneyPlugin::KMMStatementInterface::import start");
+ return m_app->slotStatementImport(s);
+}
+
+const MyMoneyAccount& KMyMoneyPlugin::KMMStatementInterface::account(const QString& key, const QString& value) const
+{
+ return m_app->account(key, value);
+}
+
+void KMyMoneyPlugin::KMMStatementInterface::setAccountOnlineParameters(const MyMoneyAccount& acc, const MyMoneyKeyValueContainer& kvps) const
+{
+ m_app->setAccountOnlineParameters(acc, kvps);
+}
+
+#include "kmmstatementinterface.moc"
diff --git a/kmymoney2/plugins/interfaces/kmmstatementinterface.h b/kmymoney2/plugins/interfaces/kmmstatementinterface.h
new file mode 100644
index 0000000..7890002
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmstatementinterface.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ kmmstatementinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMMSTATEMENTINTERFACE_H
+#define KMMSTATEMENTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KMyMoney2App;
+class MyMoneyAccount;
+class MyMoneyKeyValueContainer;
+
+#include "../statementinterface.h"
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class represents the implementation of the
+ * StatementInterface.
+ */
+class KMMStatementInterface : public StatementInterface
+{
+ Q_OBJECT
+
+public:
+ KMMStatementInterface(KMyMoney2App* app, QObject* parent, const char* name = 0);
+ ~KMMStatementInterface() {}
+
+ /**
+ * This method imports a MyMoneyStatement into the engine
+ */
+ bool import(const MyMoneyStatement& s);
+
+ /**
+ * This method returns the account for a given @a key - @a value pair.
+ * If the account is not found in the list of accounts, MyMoneyAccount()
+ * is returned.
+ */
+ const MyMoneyAccount& account(const QString& key, const QString& value) const;
+
+ /**
+ * This method stores the online parameters in @a kvps used by the plugin
+ * with the account @a acc.
+ */
+ void setAccountOnlineParameters(const MyMoneyAccount&acc, const MyMoneyKeyValueContainer& kvps) const;
+
+private:
+ KMyMoney2App* m_app;
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/interfaces/kmmviewinterface.cpp b/kmymoney2/plugins/interfaces/kmmviewinterface.cpp
new file mode 100644
index 0000000..9779876
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmviewinterface.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ viewinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../../kmymoney2.h"
+#include "../../views/kmymoneyview.h"
+#include "../../widgets/selectedtransaction.h"
+#include "kmmviewinterface.h"
+
+KMyMoneyPlugin::KMMViewInterface::KMMViewInterface(KMyMoney2App* app, KMyMoneyView* view, QObject* parent, const char* name) :
+ ViewInterface(parent, name),
+ m_app(app),
+ m_view(view)
+{
+ connect(app, SIGNAL(accountSelected(const MyMoneyAccount&)), this, SIGNAL(accountSelected(const MyMoneyAccount&)));
+ connect(app, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)), this, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(app, SIGNAL(accountReconciled(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&, const MyMoneyMoney&, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >&)),
+ this, SIGNAL(accountReconciled(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&, const MyMoneyMoney&, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >&)));
+
+ connect(app, SIGNAL(institutionSelected(const MyMoneyInstitution&)), this, SIGNAL(institutionSelected(const MyMoneyInstitution&)));
+
+ connect(m_view, SIGNAL(viewStateChanged(bool)), this, SIGNAL(viewStateChanged(bool)));
+ connect(m_view, SIGNAL(kmmFilePlugin(unsigned int)), this, SIGNAL(kmmFilePlugin(unsigned int)));
+}
+
+KMyMoneyViewBase* KMyMoneyPlugin::KMMViewInterface::addPage(const QString& item, const QString& icon)
+{
+ return m_view->addPage(item, icon);
+}
+
+void KMyMoneyPlugin::KMMViewInterface::addWidget(KMyMoneyViewBase* view, QWidget* w)
+{
+ if(view && w)
+ view->addWidget(w);
+}
+
+
+#include "kmmviewinterface.moc"
diff --git a/kmymoney2/plugins/interfaces/kmmviewinterface.h b/kmymoney2/plugins/interfaces/kmmviewinterface.h
new file mode 100644
index 0000000..d06b4f8
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmviewinterface.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ kmmviewinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMMVIEWINTERFACE_H
+#define KMMVIEWINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KMyMoney2App;
+class KMyMoneyView;
+class KMyMoneyViewBase;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../viewinterface.h"
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class represents the implementation of the
+ * ViewInterface.
+ */
+class KMMViewInterface : public ViewInterface {
+ Q_OBJECT
+
+public:
+ KMMViewInterface(KMyMoney2App* app, KMyMoneyView* view, QObject* parent, const char* name = 0);
+ ~KMMViewInterface() {}
+
+ /**
+ * This method returns a pointer to a newly created view
+ * with title @p item and icon @p pixmap.
+ *
+ * @param item Name of view
+ * @param icon name for the icon to be used for the view
+ *
+ * @return pointer to KMyMoneyViewBase object
+ */
+ KMyMoneyViewBase* addPage(const QString& item, const QString& icon);
+
+ /**
+ * This method allows to add a widget to the view
+ * created with addPage()
+ *
+ * @param view pointer to view object
+ * @param w pointer to widget
+ */
+ void addWidget(KMyMoneyViewBase* view, QWidget* w);
+
+private:
+ KMyMoney2App* m_app;
+ KMyMoneyView* m_view;
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/kmymoneyimporterplugin.desktop b/kmymoney2/plugins/kmymoneyimporterplugin.desktop
new file mode 100644
index 0000000..d8277e6
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyimporterplugin.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=ServiceType
+Name=KMyMoney Importer Plugin
+X-KDE-ServiceType=KMyMoneyImporterPlugin
+Comment=A KMyMoney plugin
+
diff --git a/kmymoney2/plugins/kmymoneyplugin.cpp b/kmymoney2/plugins/kmymoneyplugin.cpp
new file mode 100644
index 0000000..ddca52a
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyplugin.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+ kmymoneyplugin.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kaction.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include "kmymoneyplugin.h"
+
+KMyMoneyPlugin::Plugin::Plugin(QObject* o, const char* name) :
+ QObject(o, name)
+{
+}
+
+KMyMoneyPlugin::Plugin::~Plugin()
+{
+}
+
+KAction* KMyMoneyPlugin::Plugin::action(const QString& actionName) const
+{
+ static KShortcut shortcut("");
+ static KAction dummyAction(QString("Dummy"), QString(), shortcut, static_cast<const QObject*>(this), 0, static_cast<KActionCollection*>(0), "");
+
+ KAction* p = actionCollection()->action(actionName.latin1());
+ if(p)
+ return p;
+
+ qWarning("Action with name '%s' not found!", actionName.latin1());
+ return &dummyAction;
+}
+
+KToggleAction* KMyMoneyPlugin::Plugin::toggleAction(const QString& actionName) const
+{
+ static KShortcut shortcut("");
+ static KToggleAction dummyAction(QString("Dummy"), QString(), shortcut, static_cast<const QObject*>(this), 0, static_cast<KActionCollection*>(0), "");
+
+ KAction* q = actionCollection()->action(actionName.latin1());
+
+ if(q) {
+ KToggleAction* p = dynamic_cast<KToggleAction*>(q);
+ if(!p) {
+ qWarning("Action '%s' is not of type KToggleAction", actionName.latin1());
+ p = &dummyAction;
+ }
+ return p;
+ }
+
+ qWarning("Action with name '%s' not found!", actionName.latin1());
+ return &dummyAction;
+}
+
+KMyMoneyPlugin::ViewInterface* KMyMoneyPlugin::Plugin::viewInterface() const
+{
+ return static_cast<ViewInterface*>( parent()->child( 0, "KMyMoneyPlugin::ViewInterface" ) );
+}
+
+KMyMoneyPlugin::StatementInterface* KMyMoneyPlugin::Plugin::statementInterface() const
+{
+ return static_cast<StatementInterface*>( parent()->child( 0, "KMyMoneyPlugin::StatementInterface" ) );
+}
+
+KMyMoneyPlugin::ImportInterface* KMyMoneyPlugin::Plugin::importInterface() const
+{
+ return static_cast<ImportInterface*>( parent()->child( 0, "KMyMoneyPlugin::ImportInterface" ) );
+}
+
+#include "kmymoneyplugin.moc"
diff --git a/kmymoney2/plugins/kmymoneyplugin.desktop b/kmymoney2/plugins/kmymoneyplugin.desktop
new file mode 100644
index 0000000..000b84a
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyplugin.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=ServiceType
+Name=KMyMoney Plugin
+X-KDE-ServiceType=KMyMoneyPlugin
+Comment=A KMyMoney plugin
+
diff --git a/kmymoney2/plugins/kmymoneyplugin.h b/kmymoney2/plugins/kmymoneyplugin.h
new file mode 100644
index 0000000..2978fde
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyplugin.h
@@ -0,0 +1,214 @@
+/***************************************************************************
+ kmymoneyplugin.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYPLUGIN_H
+#define KMYMONEYPLUGIN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kxmlguiclient.h>
+class KAboutData;
+class KInstance;
+class KAction;
+class KToggleAction;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/viewinterface.h>
+#include <kmymoney/statementinterface.h>
+#include <kmymoney/importinterface.h>
+#include <kmymoney/export.h>
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class describes the interface between the KMyMoney
+ * application and it's plugins. All plugins must be derived
+ * from this class.
+ *
+ * A good tutorial on how to design and develop a plugin
+ * structure for a KDE application (e.g. KMyMoney) can be found at
+ * http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+ *
+ */
+ class KMYMONEY_EXPORT Plugin : public QObject, public KXMLGUIClient
+ {
+ Q_OBJECT
+ public:
+ Plugin(QObject* parent, const char* name);
+ virtual ~Plugin();
+
+ protected:
+ /** See KMyMoney2App::action() for a description */
+ KAction* action(const QString& name) const;
+
+ /** See KMyMoney2App::toggleAction() for a description */
+ KToggleAction* toggleAction(const QString& name) const;
+
+ // define interface classes here. The interface classes provide a mechanism
+ // for the plugin to interact with KMyMoney
+ // they are defined in the following form for an interface
+ // named Xxx:
+ //
+ // XxxInterface* xxxInterface();
+ ViewInterface* viewInterface() const;
+ StatementInterface* statementInterface() const;
+ ImportInterface* importInterface() const;
+ };
+
+/**
+ * This class describes the interface between the KMyMoney
+ * application and it's ONLINE-BANKING plugins. All online banking plugins
+ * must provide this interface.
+ *
+ * A good tutorial on how to design and develop a plugin
+ * structure for a KDE application (e.g. KMyMoney) can be found at
+ * http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+ *
+ */
+ class KMYMONEY_EXPORT OnlinePlugin
+ {
+ public:
+ OnlinePlugin() {}
+ virtual ~OnlinePlugin() {}
+
+ virtual void protocols(QStringList& protocolList) const = 0;
+
+ /**
+ * This method returns a pointer to a widget representing an additional
+ * tab that will be added to the KNewAccountDlg. The string referenced
+ * with @a tabName will be filled with the text that should be placed
+ * on the tab. It should return 0 if no additional tab is needed.
+ *
+ * Information about the account can be taken out of @a account.
+ *
+ * Once the pointer to the widget is returned to KMyMoney, it takes care
+ * of destruction of all included widgets when the dialog is closed. The plugin
+ * can access the widgets created after the call to storeConfigParameters()
+ * happened.
+ */
+ virtual QWidget* accountConfigTab(const MyMoneyAccount& account, QString& tabName) = 0;
+
+ /**
+ * This method is called by the framework whenever it is time to store
+ * the configuration data maintained by the plugin. The plugin should use
+ * the widgets created in accountConfigTab() to extract the current values.
+ *
+ * @param current The @a current container contains the current settings
+ */
+ virtual MyMoneyKeyValueContainer onlineBankingSettings(const MyMoneyKeyValueContainer& current) = 0;
+
+ /**
+ * This method is called by the framework when the user wants to map
+ * a KMyMoney account onto an online account. The KMyMoney account is identified
+ * by @a acc and the online provider should store its data in @a onlineBankingSettings
+ * upon success.
+ *
+ * @retval true if account is mapped
+ * @retval false if account is not mapped
+ */
+ virtual bool mapAccount(const MyMoneyAccount& acc, MyMoneyKeyValueContainer& onlineBankingSettings) = 0;
+
+ /**
+ * This method is called by the framework when the user wants to update
+ * a KMyMoney account with data from an online account. The KMyMoney account is identified
+ * by @a acc. The online provider should read its data from acc.onlineBankingSettings().
+ * @a true is returned upon success. The plugin might consider to stack the requests
+ * in case @a moreAccounts is @p true. @a moreAccounts defaults to @p false.
+ *
+ * @retval true if account is updated
+ * @retval false if account is not updated
+ */
+ virtual bool updateAccount(const MyMoneyAccount& acc, bool moreAccounts = false) = 0;
+ };
+
+/**
+ * This class describes the interface between the KMyMoney
+ * application and it's IMPORTER plugins. All importer plugins
+ * must provide this interface.
+ *
+ * A good tutorial on how to design and develop a plugin
+ * structure for a KDE application (e.g. KMyMoney) can be found at
+ * http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+ *
+ */
+ class KMYMONEY_EXPORT ImporterPlugin
+ {
+ public:
+ ImporterPlugin() {}
+ virtual ~ImporterPlugin() {}
+
+ /**
+ * This method returns the english-language name of the format
+ * this plugin imports, e.g. "OFX"
+ *
+ * @return QString Name of the format
+ */
+ virtual QString formatName(void) const = 0;
+
+ /**
+ * This method returns the filename filter suitable for passing to
+ * KFileDialog::setFilter(), e.g. "*.ofx *.qfx" which describes how
+ * files of this format are likely to be named in the file system
+ *
+ * @return QString Filename filter string
+ */
+ virtual QString formatFilenameFilter(void) const = 0;
+
+ /**
+ * This method returns whether this plugin is able to import
+ * a particular file.
+ *
+ * @param filename Fully-qualified pathname to a file
+ *
+ * @return bool Whether the indicated file is importable by this plugin
+ */
+ virtual bool isMyFormat( const QString& filename ) const = 0;
+
+ /**
+ * Import a file
+ *
+ * @param filename File to import
+ *
+ * @return bool Whether the import was successful.
+ */
+ virtual bool import( const QString& filename) = 0;
+
+ /**
+ * Returns the error result of the last import
+ *
+ * @return QString English-language name of the error encountered in the
+ * last import, or QString() if it was successful.
+ *
+ */
+ virtual QString lastError(void) const = 0;
+
+ };
+
+}; // end of namespace
+#endif
diff --git a/kmymoney2/plugins/ofximport/Makefile.am b/kmymoney2/plugins/ofximport/Makefile.am
new file mode 100644
index 0000000..d4729f4
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/Makefile.am
@@ -0,0 +1,33 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I.. -I. -I${srcdir}/dialogs -Idialogs
+METASOURCES = AUTO
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = kmm_ofximport.la
+
+# Srcs for the plugin
+kmm_ofximport_la_SOURCES = ofximporterplugin.cpp ofxpartner.cpp
+#nodeparser.cpp
+
+# Libs needed by the plugin
+kmm_ofximport_la_LIBADD = @OFX_LIBS@ dialogs/libdialogs.la ../libkmm_plugin.la ../libkmm_plugin.la $(top_builddir)/kmymoney2/mymoney/libkmm_mymoney.la
+
+# LD flags for the plugin
+# -module says: this is a module, i.e. something you're going to dlopen
+# so e.g. it has no version number like a normal shared lib would have.
+kmm_ofximport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) $(LIB_KHTML) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_QT) -L../.libs
+
+# rc file containing the GUI for the plugin
+pluginsdir = $(kde_datadir)/kmm_ofximport
+plugins_DATA = kmm_ofximport.rc
+
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = kmm_ofximport.desktop
+
+noinst_HEADERS = ofximporterplugin.h ofxpartner.h
+# nodeparser.h
+
+EXTRA_DIST = kmm_ofximport.desktop kmm_ofximport.rc
+
+SUBDIRS = dialogs
diff --git a/kmymoney2/plugins/ofximport/dialogs/Makefile.am b/kmymoney2/plugins/ofximport/dialogs/Makefile.am
new file mode 100644
index 0000000..5d79074
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libdialogs.la
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir)
+
+libdialogs_la_METASOURCES = AUTO
+
+libdialogs_la_SOURCES = konlinebankingsetupdecl.ui konlinebankingstatusdecl.ui konlinebankingsetupwizard.cpp konlinebankingstatus.cpp kofxdirectconnectdlgdecl.ui kofxdirectconnectdlg.cpp mymoneyofxconnector.cpp
+
+EXTRA_DIST = konlinebankingsetupdecl.ui konlinebankingstatusdecl.ui kofxdirectconnectdlgdecl.ui
+
+DISTCLEANFILES= konlinebankingsetupdecl.h konlinebankingsetupdecl.cpp konlinebankingstatusdecl.h konlinebankingstatusdecl.cpp kofxdirectconnectdlgdecl.h kofxdirectconnectdlgdecl.cpp
+
+noinst_HEADERS = konlinebankingsetupwizard.h konlinebankingstatus.h kofxdirectconnectdlg.h mymoneyofxconnector.h
+
+messages: rc.cpp
diff --git a/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp
new file mode 100644
index 0000000..3db8fbc
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp
@@ -0,0 +1,223 @@
+/***************************************************************************
+ kofxdirectconnectdlg.cpp
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kurl.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <kprogress.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyfile.h>
+#include "mymoneyofxconnector.h"
+#include "kofxdirectconnectdlg.h"
+
+
+class KOfxDirectConnectDlg::Private
+{
+public:
+ QFile m_fpTrace;
+};
+
+KOfxDirectConnectDlg::KOfxDirectConnectDlg(const MyMoneyAccount& account, QWidget *parent, const char *name) :
+ KOfxDirectConnectDlgDecl(parent, name),
+ d(new Private),
+ m_tmpfile(NULL),
+ m_connector(account),
+ m_job(NULL)
+{
+}
+
+KOfxDirectConnectDlg::~KOfxDirectConnectDlg()
+{
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.close();
+ }
+ delete m_tmpfile;
+ delete d;
+}
+
+void KOfxDirectConnectDlg::init(void)
+{
+ show();
+
+ QByteArray request = m_connector.statementRequest();
+
+ // For debugging, dump out the request
+#if 0
+ QFile g( "request.ofx" );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << m_connector.url() << "\n" << QString(request);
+ g.close();
+#endif
+
+ QDir homeDir(QDir::home());
+ if(homeDir.exists("ofxlog.txt")) {
+ d->m_fpTrace.setName(QString("%1/ofxlog.txt").arg(QDir::homeDirPath()));
+ d->m_fpTrace.open(IO_WriteOnly | IO_Append);
+ }
+
+ m_job = KIO::http_post(
+ m_connector.url(),
+ request,
+ true
+ );
+ if(d->m_fpTrace.isOpen()) {
+ QByteArray data = m_connector.url().utf8();
+ d->m_fpTrace.writeBlock("url: ", 5);
+ d->m_fpTrace.writeBlock(data, strlen(data));
+ d->m_fpTrace.writeBlock("\n", 1);
+ d->m_fpTrace.writeBlock("request:\n", 9);
+ d->m_fpTrace.writeBlock(request, request.size());
+ d->m_fpTrace.writeBlock("\n", 1);
+ d->m_fpTrace.writeBlock("response:\n", 10);
+ }
+
+ m_job->addMetaData("content-type", "Content-type: application/x-ofx" );
+ connect(m_job,SIGNAL(result(KIO::Job*)),this,SLOT(slotOfxFinished(KIO::Job*)));
+ connect(m_job,SIGNAL(data(KIO::Job*, const QByteArray&)),this,SLOT(slotOfxData(KIO::Job*,const QByteArray&)));
+ connect(m_job,SIGNAL(connected(KIO::Job*)),this,SLOT(slotOfxConnected(KIO::Job*)));
+
+ setStatus(QString("Contacting %1...").arg(m_connector.url()));
+ kProgress1->setTotalSteps(3);
+ kProgress1->setProgress(1);
+}
+
+void KOfxDirectConnectDlg::setStatus(const QString& _status)
+{
+ textLabel1->setText(_status);
+ kdDebug(2) << "STATUS: " << _status << endl;
+}
+
+void KOfxDirectConnectDlg::setDetails(const QString& _details)
+{
+ kdDebug(2) << "DETAILS: " << _details << endl;
+}
+
+void KOfxDirectConnectDlg::slotOfxConnected(KIO::Job*)
+{
+ if ( m_tmpfile )
+ {
+// throw new MYMONEYEXCEPTION(QString("Already connected, using %1.").arg(m_tmpfile->name()));
+ kdDebug(2) << "Already connected, using " << m_tmpfile->name() << endl;
+ delete m_tmpfile; //delete otherwise we mem leak
+ }
+ m_tmpfile = new KTempFile();
+ setStatus("Connection established, retrieving data...");
+ setDetails(QString("Downloading data to %1...").arg(m_tmpfile->name()));
+ kProgress1->advance(1);
+}
+
+void KOfxDirectConnectDlg::slotOfxData(KIO::Job*,const QByteArray& _ba)
+{
+ if ( !m_tmpfile )
+// throw new MYMONEYEXCEPTION("Not currently connected!!");
+ kdDebug(2) << "void ofxdcon::slotOfxData():: Not currently connected!" << endl;
+ *(m_tmpfile->textStream()) << QString(_ba);
+
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock(_ba, _ba.size());
+ }
+
+ setDetails(QString("Got %1 bytes").arg(_ba.size()));
+}
+
+void KOfxDirectConnectDlg::slotOfxFinished(KIO::Job* /* e */)
+{
+ kProgress1->advance(1);
+ setStatus("Completed.");
+
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock("\nCompleted\n\n\n\n", 14);
+ }
+
+ int error = m_job->error();
+
+ if ( m_tmpfile )
+ {
+ m_tmpfile->close();
+ }
+
+ if ( error )
+ {
+ m_job->showErrorDialog();
+ }
+ else if ( m_job->isErrorPage() )
+ {
+ QString details;
+ QFile f( m_tmpfile->name() );
+ if ( f.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &f );
+ QString line;
+ while ( !stream.atEnd() ) {
+ details += stream.readLine(); // line of text excluding '\n'
+ }
+ f.close();
+
+ kdDebug(2) << "The HTTP request failed: " << details << endl;
+ }
+ KMessageBox::detailedSorry( this, i18n("The HTTP request failed."), details, i18n("Failed") );
+ }
+ else if ( m_tmpfile )
+ {
+
+ emit statementReady(m_tmpfile->name());
+
+// TODO (Ace) unlink this file, when I'm sure this is all really working.
+// in the meantime, I'll leave the file around to assist people in debugging.
+// m_tmpfile->unlink();
+ }
+ delete m_tmpfile;
+ m_tmpfile = 0;
+ hide();
+}
+
+void KOfxDirectConnectDlg::reject(void)
+{
+ m_job->kill();
+ if ( m_tmpfile )
+ {
+ m_tmpfile->close();
+ delete m_tmpfile;
+ m_tmpfile = NULL;
+ }
+ QDialog::reject();
+}
+
+#include "kofxdirectconnectdlg.moc"
diff --git a/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h
new file mode 100644
index 0000000..e5d92cd
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ kofxdirectconnectdlg.h
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOFXDIRECTCONNECTDLG_H
+#define KOFXDIRECTCONNECTDLG_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KTempFile;
+class KOfxDirectConnectDlgPrivate;
+
+namespace KIO
+{
+class Job;
+class TransferJob;
+}
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyofxconnector.h"
+#include "kofxdirectconnectdlgdecl.h"
+
+/**
+@author ace jones
+*/
+class KOfxDirectConnectDlg : public KOfxDirectConnectDlgDecl
+{
+Q_OBJECT
+public:
+ KOfxDirectConnectDlg(const MyMoneyAccount&, QWidget *parent = 0, const char *name = 0);
+ ~KOfxDirectConnectDlg();
+
+ void init(void);
+
+signals:
+ /**
+ * This signal is emitted when the statement is downloaded
+ * and stored in file @a fname.
+ */
+ void statementReady(const QString& fname);
+
+protected slots:
+ void slotOfxFinished(KIO::Job*);
+ void slotOfxData(KIO::Job*,const QByteArray&);
+ void slotOfxConnected(KIO::Job*);
+ virtual void reject(void);
+
+protected:
+ void setStatus(const QString& _status);
+ void setDetails(const QString& _details);
+
+ KTempFile* m_tmpfile;
+ MyMoneyOfxConnector m_connector;
+ KIO::TransferJob* m_job;
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif // KOFXDIRECTCONNECTDLG_H
diff --git a/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui
new file mode 100644
index 0000000..3937012
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui
@@ -0,0 +1,109 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KOfxDirectConnectDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KOfxDirectConnectDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>108</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>OFX Direct Connect</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Contacting bank...</string>
+ </property>
+ </widget>
+ <widget class="KProgress">
+ <property name="name">
+ <cstring>kProgress1</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KOfxDirectConnectDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui
new file mode 100644
index 0000000..3ee9b6a
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui
@@ -0,0 +1,488 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KOnlineBankingSetupDecl</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>KOnlineBankingSetupDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>653</width>
+ <height>502</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Online Banking Account Setup</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>FIPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Financial Institution</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>m_listLayout</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Please select your financial institution from the list below...</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_selectionTab</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Automatic</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Financial Institution</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listFi</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Manual</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>m_url</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Org</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>FID</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_bankName</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_fid</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>90</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>LoginPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Enter Login Details</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="2" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>120</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KActiveLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Please enter the username and password you use to log into this bank for online banking. Please note that many banks require a separate signup, and assign a separate PIN or password just for online banking from home.</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="4" column="1">
+ <property name="name">
+ <cstring>m_headerVersionCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Connection Details</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>m_applicationCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel1_6</cstring>
+ </property>
+ <property name="text">
+ <string>Header Version</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editPassword</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editUsername</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Identify as</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ <widget class="QTextBrowser" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_textDetails</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>AccountPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Account</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout29</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Please select the account from your financial institution from the list below which matches this account.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Number</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Bank</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Branch</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listAccount</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>WizardPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>WizardPage</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_labelFinal</cstring>
+ </property>
+ <property name="text">
+ <string>Congratulations! You have successfully set up your bank for online banking via OFX.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+</widget>
+<customwidgets>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="18409">89504e470d0a1a0a0000000d49484452000000b700000164080600000062b3aaaa0000200049444154789ced9d7b7c54d5d5f77f13c630263064429ad8099090385c26354447218fc638c608f5e111e205ac5a354d63c5372a78ad85965b955aad0a563fd2823168a5af201aa23c568b318dc89baad1814a22991226c150833197c1e01081f3feb1b3cf9c3973cedc72cedcb2bf9f0f1f923367ce9c24bfbdceda6bafbd9666efdebd508ba1a1210e0012131335aa7d48002c5fbe9caba9a9c1d1a347237a1f8cf092a0e6c51b1b1b919292a2e647044457d711381c8e48df0623cca82a6e87c38113274e44dc5adaed87d0d8d818e9db60841955c5ddd6b64fcdcb07456f6f6fa46f8111665415f79e3dcd6a5e3e20a8df6fb3d9227d2b8c30a39ab893929238b5ae1d0aa74e1d8ff42d30c28c6ae2eeefef57ebd221110d4f114678514ddcd132818b96fb60841fd5c4dddbdb0babd5aad6e54382fadf8cd1816ae266133846a4514ddc5d5d47d4ba74c8b00137ba504ddc76fb21b52e1d324ea733d2b7c00823aa88db6834468d6f5b5f5fcf7fcd96e04717aa889b8a282727478dcb874c7b7b7ba46f8111465415777676b61a97673002421571777676aa71d911d3d0d010e95b608411ad1a17552b4969686888733a9db2518fe2e2626467677be46dd7d4d4a0bcbc9c097b14a28ab8950ab925252571353535f8e4930f3c96cf2d799ee7b51fd1a1cfe9e2bf2f2ab270d75f7f0bcacbcbd1d2d2a259b76e1d7a7a7ab8fbefbf1766b3996b696989781a2e437d5411f748309bcddc33cf3c83975fdec287130d7a1dcae602f3b380b9c51a4c481607635cb07701db1a81cdefe8b0674f33f6ec69c69a950fe39aeb6fe256ae5c09009a8f3f6e8e9a280e437d5411f7be4f9b827e0f15f5fc1f97f056d892072cb918985b7c12c7fa01db7e60e9cb1c8e7401cd07dcef35e875a89ce7c25d0b34b86bc1492c7d19a87d17e873ba505d5d8deaea6a545454702b57ae645bcd4611aa4c28852e4220b4b5b57153a79c83952b57a2cfe982250f78e949e0f5873568eb070aaac6e2a2bb81db3711d10a854d3fef89ede4bc7f1ce350b304787091e739d5d5d5c8cece465b5b1bb3dea304c52db7d96c0e583c66b399bbedb69bb173e72e00c4023f7e830b8bae021efd2bb0f49db1b8acd085ca792e9c5708cc4c044c99e4bdf62e62c9dbfa892bd2e774a1cfe9c2adf7031fff11587123601f208341c8bdf72cc1fb8d4d5c346c7f63a88be2e20e7432999494c44d9d720e6fe5cbe6021b6e39094083f28d1ce66701b6e74e6242b2f4fb4d996ea1afb8d185bac3c0d23544e47357e870b8c68515577b8bbbcfe9c2b265cbb06eddba107f4246aca0ea3633397a7a7ab8cb8b0bd1e774c1a0d761d3ed40cd12f013c59a25c0a2ab2031719467c154e0708d0b65738980eb0ebbc52fa6a1a121ea760a3194477171fb4b4e6a6b6be3162c58c00bfbdd47891b420946d052d42c214f017fd4d5d58de87318d18fe2e2f6e59624252571e5e5e5004824e4dd475d5ed6d5de055cf19b91ddc38aab8925f7054ba28a7f548d73ebf57afe6bb3d9cc4d9d720e0022ecd71ff68e5753bff9b2c2e0a22d62e8801918d400907e12b024aaf84771cb4d97de0d7a1da8950680db6ebb997745362e018ef57b8a6e6050c34f08e76729732fef36cabb38050505ca7c08236a512d5a72ef03cb4197b93ffae8236ee7ce5dbc8f0d007357e878b1e74c76a1fdc858fefb4557c95b6e6108d03e407c6c397675c8bf969a9a1ac24fc7882554714b4ca65cdc73cf3d68696981d96ce6e6ffb80400f0f80d6e1ffbdd475d58b211683ee01a5e9471f1e7081918d4e0dd460ebb3a807f3479e69088176a84d8bbbcc380428a8b8b43f9d11831842ae2deb4e905de6adf77df7de8739210dda285a918a3cfc7e99e06983289df5d50359617acd06adbbb8047df04fed1345620684fe14ff3516373c946f9d70c7a5dc42bcf32d44771714f9890cc0b67686888abaeae06402218c917fe15aeb6dff1e71eebe73c2c71ce6417ca3742943b22efa28c9d217d7cfbdbde4bf442ee7d6079603f0c23a6517c42b961c373fcd7ab57af0640dc07f3a5772161dc4538ddd3c0bf6edbeff9dee603d2b92300b1b6624e7ee17d9ebd0b78e855ef7385d7b9e79e7b7cfe0c8cf8407171d3acbba4a424aea1a10106bd0e772dd04077ee5a9c3ab6cde3dc8d3eeade5bf2c8a078e949922b22958c257ebfbdcb3d51ad4a97beae70a2cb886f548b733ff3cc330080ca792ea49d771712920d38e5fc9c7f7d605083e603ee509d250f2831133f5a9cb35d3eec3f0b13abc40c0c6ab06423c7475c52b35cc031cf7384135d46fca39ab8df786d2b00e0ae051a9ccafa0900e08c40dcc7fa396cba9df8cddeab896e61d3a80759f8914ea4b277014b3672bc3b73d77417fef784f779c2892e23fe5145dc4949491c8d904c48e6a04fb904003cfc6d61569f2fb635d28c41a91d389eae080054a503530a80e64d9ee7ad5dbb9645484619aa889bee7ef75a694c4c058682db3cbce246fa95b7b0b7bf4d268f54d885c9c0af2e35e2faad473dceaba8a84069692913f62843959457ba4a3976063026cdca1f1fa3cf57ec33b6bf4d76e608b7a4bdf66323167e71144d83eef38a8a2c78eaa9a714fb5c46ec10d67ceec4493f19f13506063528df48844da94a0776ce30e2771f1cf50823161559f0d65bef313f7b94a28a5b3265ca1400240e7d7a6a83fbc3d2170389cb83764d28246bd07345f3f11b5cb8aa9758ec664174c464ca65c21ee5a862b969c61d8d430f1dfe13f9b06403ce3607bfbd8b5aeb5bef87c7c4f15f57a6e2aa5e23aeff9ba7c55eb8703e3efeb899097b94a38ae53e71e284c664cae59a0f1c42dd616041e272b80c3f823ee512244ebd0300f09dcd473adf3003831a3c5bc761f33b633d7ceb9d338c00803f751ec5b30775e813f8d8ebd7afc7ecd9b3352c96cdd0a8d51e7bf7eeddb4180e1fca4b3baf0a89e75c8d847117e1dbef5bc07db840d2451116d8115aea5f5d4a44fd76ea51bcb0151e1347abd58af5ebd7474553574674a09ab8cd6633575656c6d7e833e8c90e9b15574bc7b7eb0e03ff6af22cc760d0eb70d77417ee98e2b6d47f6ff114b5c9948b152b7e8369d3a629226ab3d9ccd96c3616138f03541337656868887bfae927f8da24145aef4f5ce7cfa0d7e1269d0ba959c01d538c783bf5286c3b81ad2ecff3ac562bcacbcb1513b5f07e013071c7019ab56bd7720b162c50fd716e341ab9dada5abcf6dacb3e7b42fee622f27f6f87b7a04da65ccc9f7f35cacbcb55bb5f26eef881df411b0ee1508c4623d7d0d08037ded8ee65d185141559306dda2ce4e7e7a3acac2c2c75fe68b935a59f088cf0a3299b0b4ebc7daba8c882cacabbc3f207a63eae10718d6d35686b6be3a47ebeddbb777300d8727d1c90b0e3f55e7cd95889979e74fbc17bf634a3bcbc1cb7dd760ba776e1c89696164d6262a2c7bf7058e837ded8aef64730224c4242b20149b3fe885beee3b0f7cd8de87859c3576cb2db0ff122efe9e9899bf26346a3911b1818947c4dadae108cf09330f08606df7e70394eecbb1b09495391f23f1fa06609d9fd422db9dd7e080b162cc0f2e5cbb9686ac3172a0e8703a74e1d977ccd66b379b4f763c42e0900c9b3febefd590cee9d07eefd22002416fdde6f814db7bbf72f363434e0fcfc19315fe3bab1b1d167c486111ff8cd2d59741529254c5d953ea70be5e5e5d8bc7973cc0a9cb91ea3039fe2b67791ff2724936e05422b5e5d5d8d871eba9b0ba6d87cb4e0af8638eb7c161f68b7bfedaeff71f20b7799b27f34913267effdd67df2a2ab80827c5a298a44552ebac8828f3f6e8ec90e6146a39113476642e9e7c3884ee4cba0829456706ff3723330a8c1b58fb937e4c6daa6808b2fbe9803888516af44d2d7fafbfb63e6e76148e3d32d592c534e6f423287d71fd678c4c52fbac8a2f4bd4514a57a6932224702e0eef328aeea3477858ef7bbc550810b63e2b13cc964c41f090089805c3b8ff49479e949e28e18f4eee649be045eb3c41d0fafaeae86dc624fb44c3c03ed85c33a2fc43ebc5bb2740db1da0ba6123ffb708d0b9b6e072e2b2402dffeb6fc455e7f58c35bfdc71f5f23794e59599982b71d3afdfdfd019d47cb533062175edc7d4e979780175d458abbdb9e3b0980b6e1f0664232c7d7d5deb3a759d23a363434f0e9a4d1426363a3c7f7d1f27461284302752900f9eaa8139239bfadf3165de5f6d9699d400a15bb584cd1069b44c6170993055bbefa9c2e59ff3a102ae711eb5d5d5ded6105e923beb9f99fa15f5c21fcb512a4b0fc92d82741dc5a435c333b18ce2b747f5d5353e3bee6b04594cbc40b27cc3a8f1ebce2dc6d81cdb77884967e66a2fbebfdfbdda3845a41b6accd0827099b6e27a13fa1ef1d0cdb046e747a8a7bc229ecf3d8d57524d4fb5315619f4c46fca1a585dc570c1ff0d59854ccf6b7491e0ae51fc7dcefcbc9c90140221076fb21056e5579582fcaf8c6cb2d09b4f7faa37f25c52885658a853d6a6ebdf55600d1e7e3fa9a2846dbbd32464650e5d4684f485a135bdc109584125da8a9a9e11392a23dfc2724d0480a23369015b7bd0b681d72a7c1d6b740d0c3c6e5d10d18202e4a9f93085bb8ab5cb88c6d32e52aff130489707bd9f02efb08de0d434db40011e6c6bdbe7b370a21b5ff487f1a5aacf289edf0123600b4b5ede3bfcecc9cace0ad87c6238f3c89828202b4b4b468c4c2a6a59719f18176fbdb6475914e2ca9c50648ed3e807418a31b1a2e4b27bd69060689df4d2bb04a091b40d4ed554c4c4c94ad003b6dda34cddebd7b313434c4b1c4a9d8470380a3452ae76779b7c91362ef228b3cbb3a3cfbaacb093b292989134624d6ae5dab4ab11b5ad8c7e17078ac86fa5a349a30211916cb1c00a40f7c380a0131c28b1620be72edbb402d006c22c216c6bdc5c52a2906bd0e5bfeb20d69696992a210471f94882bd39a83fbf7ef477b7b7bc00b4334ef45f873884bb919f43aaef8f22b70cd358b5839b53820f0a0b688a2220b9e7df6059f75058535ba01e96d5d81303434c4d5d6d662d7ae37218e995bf280c999806982db7d9a99e8bf0da0f484d9fdbadcd388113b68ac562bb7efd32649cb2c8541afc3bd0f2c0fc8bd58be7c3927b4acc1ec4b4c4a4ae26a6a6abc045d369708f9bc42a9e6acd2d41d768b182083a0209f885b780d7b17f0e89b6e978b093cb6f1a8cf4df3ad85beab90e2e2e2a02cef430fddcdd109a541afc3aebfd5fb7d6f5b5b1b575353e355b47e7e1624db62070315f9ae0eb2bb5fd88aa4c44cba1d4f48e6f8368040e84f1b46e451b5f83cdd490e9062f1ebd6ad9315495b5b1bf7e8a3bfe5ad74d95c78097a6ab9efee0cc1e0eeb7e329f2d71f26027ff4afc013dbc9e03adcf915db091f83a8266e71a464d9b26558bc78b19740a4442d27de2b7ee3f68b1f5c44dc8b5d1dc0912eb7df4dad6fa088db6b5bf24819b981410d0aaa4898d3dfc0644427aa743303bcf72a6667677b7c6f341ab9f2f272defda0a2365f7a17be6f7fd6eb7a03831ac10a29b1aa94071709451ddcfcd89409bcfba80b17dd4dbe6f3e40046fca245be76edf445c939e9e1e4e2e2ac4884e54eb202cce29115af1b6b636eefcfc196868688041afc34b4f022fffda8afcf91bf1fd975bbdae458b0089b1e4916ab42b6e0c3ce14b0a5326f81215807b118b2e5c01c0fdf7df1bf2f51991216cedb1a9b8376fdecc959797a3cfe942d95cb2f9f8ba2beec299f31ec1772ddedd85ed5df0a86e05103f78d3edc47d18a9ef4d1166370a375df0f7613f245bb682119da8e69608534b0d7a1d5a5a5a349b376fe6aaabab0190a29a8b16a622f9c2bf2261dc4538de70ae97b0e9a44e789dca792edcb580e4b52809b5d2963cf78079fd1def9f69f1e2c5ca7e3043355413b790591714424ad89a4beaa04db904df7e70b987b0ed5de08b6d8a79623bf0c4766917450c9d6452ce2b74e7c68839f9853b5a029070a0d7fe529b8d893b865055dc4545163cf2c893686c6c045da9140a5b9f72094eecbb1ba77b1af8f70c0c6a3077c558c945255f0b4d5203417cec41000b6e94f62c0af281f7ae02a8b0699c9b11bba8de64d5683472345242abc69e5db0118953efc099c13e4977042022176e5b0b84935f80df4821c492072cad086c45b37ca3b7c5a6d0bef241dd142362a8ee96ac5dbb160011d88a1b0124a62271ea1d008053c7b6490a1b20d18f4097d70192932e16b6250f587271602b9bbe5c21803c8598b0630bd5c5fdc66b24b4576226df9f35e926feb553cecf477c7dcf8d169e167be312ffd114e1660b390c7a1d4d121bf1fd32c287aae21e1a1ae27cf9c967421437cd2b97724184f81336b1f6d2febd90a79fd9a87a576586f284255a22e4fb2fb7e2ccb96b91906c40e2a49fe03bc164520e2a66716a6ad95c9250357686db9fa69b987775485fcb3ba7c4b7b0596660eca2fa84f2b6db6ee1ecf6432401a98608e9ac9cbb9034eb8f3833d887139f5eeb112d1163eff22cfc030497ee4ad9feb6f70e225f18f43a3cfdcc4626ec18c6afb87ffffb47b95ffe7245c87fe0b6b636aebcbc1c0059e2ae59428ed38889b3ff43701f2e909d58868ad0828b7bdbfbc364cac5f6ed3b982b12e3f815f7c5175fccd5d5d5c96e250b04615eb730eb6f4c9a1589937e0200f8ceb624d4cb03f0ccd53ed215f84e7e31cb962dc3ead5ab598a6b1c1090b8e5d2550365686888b35aad1ec7849b10c6ce905f3914527798fc2fdc1a26b7bf3358ac562bd6af5fcfac751ce153dc3427db64cac5962d2f8fe88f2ede4fa92685c9c0c1318189de6ab562f5ead56cb74d1ce2335a4273b2edf643309bcd236aa45a5a5aaa71381c7c7e895218f43a4c3fedc29566604a01d06903fedee27ba9dea0d7e1b68a2558b66c192be710c7f814b7b0769ecd664362a2442e68103cf5d453686bdbc717ea294c065efbb1116fa71e45ea7b806d6260d79952005cf821f083994600c0dba94761db09fcf663f9f7984cb9b8f4d2cb505656c6cf1f5829b5f8c6a7b88575476c361b66cf9e3da20f6b6969d1bcf5d67bdc7df7dd87eaea6a340d0293761c456132f07d36f0dfc3e74d290052df037aaff0febfd346fe6dd400ed7fef95b5d026532ecce619b8fcf22b61b55a992f3d0a09781147a90aa82d2d2d9acaca4a3cf5d4539ccd6643636323eaebeb71f0d326fc960a955ae07699ff795c30997291993919393939c8cece467171315f0b909ec596cd47273ec5ad6683a69696164d6262224a4b4b515a5a0ac05d160d90dea626ac58e56b0228570b9031baf0296e61adbde6e67ff222540b2a7800aa7f1623fe09780f65347422633082c1a7b859f731462c13b0e5a60d9c188c584156dc46a3d1632d5c5c5487c1887664c5cd3a0b30629db015e56130c24dc0969b75db65c41ab2e216d7e766dd7619b106734b18714bc0e266d11246ac11b0cfcdf29e19b1866c6e497bbb570a5e50188d46cee170c0e9747ab5eca3e8f57ade97677d20194a1350caabbf9eed66b399a3a9ab369b6d24cbf65c519105175e78294a4a4a505c5ccc36ea32422620714bf56c379bcd5c6d6d2dde7863bb57b3d291b0674f33f6ec69c6faf5eb01000b17cee77efef33b46b4fb9e313a09bae294d168e4d6af5f8f2dd51b2577c1d0a6a7be76b5fb6b702a64e7ce5dd8b973174ca65c6ec58adfb022398c80f1296e835e87556b1fc3ecd9b33566b3997be6996720dec1eeb76f7ca20163f4f9008004fd8fa0d5ff08e69ccf61fa722b309514e25901cf223a5255a1ecf643282f2f87c994cb6ddaf402dbadcef08b6c6907a3d1c8a5a4a4a0a5a545333434c4dd7efbcf3d3af94a96074e4cc5187d3e1227fd04094953a1cd205d94ce0cf6e1d4b16d18faf2fffa2c9d46a125d4843d22c5b0e2390c7ff82dcab36ddb368efabf80449fc8c4549c35e926249e73352f662078414b216e570d0055e9c05617117d20fde719a317597127252571ab56ade0278b5edd098645ad1baed84a39d5fd2e86be7a53b29764a808db781426033fbf89ec801797721057b592a2a4a4c4e3fbe2e26200404a4a0a1b247186c6e17070e2051b87c30161575fdaee837256ce5d5ea276f67f88847ffd3a642bed0f719f9adf5c444a40bcb015685278071cdd510fb8078330262fde5dcf884e48eb2e1f6cbadded578f49b3e2cc798f409f7209fffa99c13eb8febd52514b2d8758e055e9c0af2e35e2fabf1d555ce0fe58bb762d4a4b4b99c055a4a0dfc18df9e114347f9710d2efd9a7b8c5c24ebae0752f1764f0931b7d961fae3b0cfcab09585cac4c4354290b7ec71423cefb7b2fd2323271cb2db7057caddede5eaf7a2cdf7cd3edb119fad4a9e338b0ff80e4c496766b63911be5989d6de44eecacc1f1e757f3c732fee6c0478ee057af65c52daca54d8bc50b193afc277c675bc287f00af2dde2a5c71e7a550780f45657aad32fe0dd7c75470ea94675fb26a0a2a2429524affafa7ad9955716b9193996b3cf70c79f5f83934d7ff77a8d3319f1c32d9fe39ffbbf08eaf7ab31997239ea5feefbb4097d4e170c7a1d6ccf9dc484640e63d2ac1877e9fb1e6f3ab1ef6ede0db1770117dd4d8e1bf43ae44c76f1658569d3d291f46597636ab93b4c68c90376ce30e2771f1cc556970ef73eb05cf1cf0388a5975bbc329972c1e2efc131277f06f75ded4be87fe37168ecbeeb364e78683df6e704d74d2ee1965b6e434949090a0a0af83fdae337b87841265df0bac71b84c20688b536e88985ee73bad07c007c5ff7f77e0b55844def91d27c8014c3fcd5a546720f2a55ca4a4d4dc5bd0f2c475191c5eb35bbfd10ac562bb66ddbc699cd66d623de07b3b38ddcccdd35dc5717a762e0f165b2c2e64c468cbf733532fee6085ad80090408570f8b01d00112af5b3cfcab9cbc3c71e3afc27c98963e53c4f4b267469d4626eb1e7cf6adb49fe277de6bf50f7b3e72e444545053fa885ac5fbf1e175d64c1d0d01013b808cbd967b86935abb8ee1f67e3c46b7f963d6ffc9dab91b6650f3aef7f4df3f9acb99a50fc6d0048b058e600002f08a145d4ea7fc47fedecff50b2b587bd8bac2452c2216c803c1184fdde9b7e40febf49e7424f7797ea9f9f9d9dcdac7800ccc99fc115f43bb8294f5ecff5dc5624e9530340d2f5bf80e1b1ade8d8b857f3f9acb99a50232442f8dc121ad31e3bc3fd624292bb6558c2bf7e8dd3a2378bfbb41bf43a6cb8e524fc4417c9e78992a7ec03a4970d405a81d0ce6781d27e4407cc0052b380be8f5d7c0e8c41af435a86f76c562ad371c284644c9c98e1714cafd723353555f673e7ce5d88acac1cfcef9b6f7af9e2ebd7afc7ae5d6fe2c9279fe6465b56238d7a7cb5e46200247221666ce195482afb196c29d9aafc6eb400992851842df0e872faa9ee77251767ae7d8cf3f883e64c76e1d93ae90faa1f2ebc1a480f9b071705dfe346ee9a7d4e17fa9c87bc8e0bf36482459cdf9e99391979f9797c517df1e72c58b0000b17cee7b66c7925ee232a96b3cf7027de7c09dd326e07673222f5e77fc0d8e21f071dfd08166d7d7d3d4e9d3aeef32457dbefbc8ed9253a86351ff0df45cc92474448db658b93a3cae67aae86068a94ffab16e28111c840d9b9731752525260d0ebb859171462c28464582c73f895cf585ffe2fe87770276a5f448f4c282fe59a87a02b29c3478ea39a4e00d8afeebc0800b4be76cd9cea7e17da8cb9b24bea429f97323913304d707f7f5e21f95f2eaf7bf33b9ed70bd55fcf994c06c8df5b8865955acce9ededc5d75ffbf6c73ffae853c9e33ddd5d8a744deb73baf878b9789387d56ae56a6a6a6266bbdd9cfc19dcc9c6bfa1f78507d0278a787026239267fd0f92aebe15cddf2510413bc2dba6454b1fb1d4fa0c0cba4578e6c4619c19ec937ca3299384fa02c75bd87357785aed8d410a5bf89428fc1ac00c92676242e875566eb8e19680cf6d6f6ff758e13c78f05ffcd71d1dede8ee7637cc0a848686069c9f3f03abd63ec6cd9e1d7ce82b5cccc99fc10dbefc8ca43f9d74fd2f78410300be8bc00d0ea3a9ababe37a7b7b41bbfc0a97dccfcab90b5afd8f46dc00558cbd0b58b2d1db850926d2225e86df74bb3b53f0e69b1761ecd8f1004854235a0a0ad1c1409f201f7df4a9acf0a3319d7776b6913bbe799d57182fe9fa5f60ec8556d52686a1a2a9ababe300d269aca1a1c15360c369ad4a264549596c8ab03fbc3fca37baf3bc0d7a1dfe75652a167e7154d2e737e875f8efabafc69557cef719f98804b5b5b578e3b5adb2bf0fba132a02b7c64327894251ab1de950028dc994cb016e9f52b8f40e10ebad94b8b7bf0d3cf4aa8e5fc1bc769ef739c2688d1c03831a14548df55a7e9fb4c3b74f6732e562c58adf449dc0dbdbdbf1dc737f94b5e256ab15b5b5b5618fb4d049228d4d53418723d2a104928953e2fced912274430c7a1d36ac7205246239c489535f5e6794b5da620c7a1d9e7e6663d4091c005e78e14fb295040c7a1db6fc655b58aa0014f43bb8de171e80c67e34e6042d44362b70d3ed9e0b3a62e8e28b3fc43bdb1f5ce43e2e8738e2224628ecc264f27f30f9dcd16ac101927d28979c05900cc4c58b172b2e326112936e625ecc0a5a88dfcd0af14a340bdc9f9b525464c15b6fbda7889b42231fa7bf3e8ab1175a635ed04264c5edafca54a86464a4202b2b32fd7584e1397a2f95957747a5c07b7b7bb179f31f25573d01e2a6bcdfd834a2680a8d53c793a08568d6ae5dcb454ba88ce18d2f3f1c006a6a6a58a12219f85020237a89941f1eebb0e2f3314049490956ad7d4c367f66fdfaf5d8bc7933335222f838b792289971170c9999939199f9039fe7fce00799b23ef6942953a2d2ffa6f4f6f67a94dc10b370e17c8c86ccc34019b5d1926090cb09379b6760dcb8248f63d3a79fe7759ed2731aba9a2c859291946886e68b6bb3a6c9ae9232714700a97c70e11347fc74917aa2d4d6d6a2baba5af2faf12a70cbd967b8ef0f7c0257e32e8f1d3de7eced958cf668007006bd0e79f912f9abc34c9c780e0a0a2605740356eb85c1df75186868f824a0f36cb62ff1cd375f49bed6dddd3f22974b09844f115f69b826532e3efeb839a6053e3bdbc80dd9f6e2e4270d3ef75c1a1edb2a69bd351cf719b3dc23c4d93f884f6dad5ec7a506d47bef791e932bf8a304151515a8acac8c2971d3ccc3c17d6ff92df740195b7825dacad73071473badadede8ee766ffbb3d90ea2bf9fec94eaef3f8ee6e683fc6b720b3c426241e005fd0ece9f75f647da963d5e65d798b8e380dadaf75153f39eec624fb42df4d0955161c661a08c2dbc1263264dc5981f1831b6b01400646b093271c711ab576fc49a357f927ccd66b34574e3c3ec6c23e7aaaff59a0cca41457c568e1967e55d08adc91c7c393526eed8a3b5b51d0b173e84d9b32f4065e55c8f49fca597564aba2b9158c5a482f6552e4d0911cbc1c41da308ad2e8c38270000200049444154f4c285f3f152cdafa04f49466b6b3bcce6ebbcce379972b165cbcbaa8b9beeda114f08399311ba8979483cff128c2d2cc5988c4921556e0d0626ee1866dab4ebf9d0645191051f7cb01900f0d39faec32baf6cf73a5f0dd784facf74422814b1366b1a46525f7ba43071c730b5b5efe39a6beee3bf7ff1c535282f5f80d6d6765c5278b364052c25f663d2c59433c7fb71faeba3aab8144ac0c41de3087d6c9329176d6daf0100caca7eed153d59b8703e7ef9cb1551233eb561598131cefdf7dfcc7f6db71f426b6b3b00c06a9de9756ee3fbef85edbea20126ee18a7acec728f5c95575f25f52ee6cdfb2faf73fb9c2e2425258d9a273513771c70d34da5fcd75bb7ee0600cc9c992399ff6db3d9c2765f9126e8deef9120d0a4274a46462a66ce8ccc3ecd4870c30d73f9b0a0dd7e08cefe41e85392252bcfda6c364c9b362d12b719768216b738f70190169f380f424c2079116a6332e5222323c5e35856560ece3dd79d5e9a9d6d4476b61140f40e1a6aa56974a4bee12394955d8e2baeb85052dc8b172f8ec46d861dedb2654fc88a50cd8cb568c06e3f04bbddf358a0834e3830aeb882ac1016144c474aca785c503013fa946445efd51f422b6db31d4459d9e5282898ee759eafaabef18676c386ad91be8798443830e40644519105595939b8fefaff4259d9e5aade8fd04adb6c5f0200a64fcf923cd7683472b152267924c8eec42994313c161f06e9dc44604aa2ef0f2c1c17e09da9c0b15340bbc483a87308f8f790e7b1664105ab8363fc7783f087c9948bc71faf524de40d0d9fe0f2cb6fe73f8bc6bb359af325ce6d18152d05355df9a3679b999cb8831970c26b0807051d0cfecabadd7cf322fce52fcaf7c974f60f6282a188ff9ee33e03209d48a5d44a65b4a3bd2e845d53966460f939cadf4c3878a29bfc1f486d41835e87e9a7dda341f8d42a19479e528b2536cbd301f044b7f7e7d09c0fa505ae4f4986c994cbe79ad0884956568e97b8c52dc1e3156da00524e91ffa0683f41f14009abef5fcbefe5bef734a4456329c6e4aba16d821aa1ce1d3129f76798853f8f573c73caf53984cc47f6e2260d5939f6bc738605b2f70ef979ee7bef2ca769496fe08e5e50b14f9b928b3675fc08bfb535b2bacd60b3d223f94e6e67fa2b4b4d4eb78bce1150aa4be36b552f48fd5e074614a2290a32322aeff36f047b110b128a43e97faee6a0bbfe95bb77515ce312cc9ee9fff0603b9173a509b65c4de34e8f9bd41afc34abd8b37046281af5bf712ae2dbb42d1a84a69e98fbcb201a52226030341fcc16218ed8e1c790b5b388e08a0c109bcdaa7ccc44a8e269981422d22bd1f25a1d6b5e95b69fff9e0181dfa8e85f6f3f6395db877f8e9bf38955c5b38b0edf643f83f776d50d43d9933c7dd14d7663b08abf542a4a48cf73acf5ff7ba78c1235a62d0eb7093ce85e64122a8adaed0c52cec741648efc940294c26d6d4aa276e86926ceb750b5cec3ed57f4b8e853289fc6cb82de1f9a29ae406bd0ebd03ff6f64372d2275c27fa1cfe9c2aa557760f5ea25b29b17f6eedd1bff134a00787ab824c9bf875cbc75217f3069415af248817800c89a0974b492ff01c03245ea1dded769ee24ff770c574438d215d820103efe0b9381073394b3e8563df0ef1e225a29f743cea5f247839358efaa74cf6bf4395dfcc44f29c44beed1b8a23a122c679fe100e0f47f3a71aaa30d0030f4d9870000d73707f8dd3f86c7b642fbf424e272f8b23e06bd0e9715ba780177b4bac598d3e5e2856e99e2295adaee7a72a667ff1b7a0e20ee8be3e25fa7eff7d50aa46910b8aedddbbf0d9574ad3b0a249c1ce7e8dc4f097a9c5af040acb7f069201e2074e2a7147431e7dfffeef57f721411a8687b7c5c43f8283ad5d106ad78a2e3f5a17900e0c23f9a74e87bd7c50bbda814281a1663472bb06737b0e180dbaa67cd24c2a542dd50ed699985d69f5a7b39d1d36bfca349dab253ff76ad5319910344bcfe7e3781b2d5a5c372b8249f30b4268952d0096447473b7f4c1822a40c0d0d71e158c8515ab48172faeba39ed11261f20dc56d39ddc7a9d029657389508b86a34b54ec2f0d8b990e88c999c4fa0bc5dcd10abcf4a2fb730d7a1de9065cea3ecf3285fcbb769e0bcd9de4da52165d28f2cd69d2620a94c5a9eed5567a1da94520611445ce7afb72b5681e8852482db96764a478e5d08c94d9d946ee743719fd279b489aede9af8fe2f4978755156da09cfef23011b7258f0873cf6e97df8e60527f28da0f12efba8f59f22070655cbc6f2d143de016331d1896292e5ef47b76bbadbd41afc3ad3f7311a15790735f7f47f0d9a27bbcce497cf2e7b3429f78168e03d67d455c1fa5284c0e2e741a2c6afad8c2bd9327f679bf3ee607468cf9811189b80450398c4e371ffb3c67e952f285d07a2a41f38161eb2a129fa7e8012afc3d64f063c301f779e469e01ab6e044f4af0b7ac567cd045e9a475c1ea941d93408947c393257a532cd3b72421186507d59ee7053546451e5bacddf256890335b956b87849fd6db5af7235eddd456deddc0b0b595103d756de8c4b4a3d5db6da1d7baacd03df95c3a6cc9a5444e5d957f0f11a1066bc5d3b540fa3880a6290863fde2e5f9c264ff6b01e118005959391e3eb7d412fc68401b48635225e873cabb3c6573496444eccb532c792e7e924a84ef6deda9db52542afd147aee18b1aea1ba293718485469fa6917402377a2e57942e4f3dfcf3d37151f7df4a9c7f7a311edf84be6e1ac8c4c7cdfdd85ef7bbec2d9ff3918f60d0a6ebfd9c55b78711c9d8a7f83c882e74c26adb6b366badc31f69f11f18bfdf1a641b290b22327f8d8389d608a577385c954a1c4c169eeb59258ad17cad60c1c4d688f7f489cd8f197ccc38492324c285980f1875a71b2c38e13fb9ba0fdd73fc22af69cc92eb41fd1a1f9c0f0670e0b54287ab1bf2e14be7082ba74a6b415afecd161b34c68cee7bde9c8e4529887128c9b71ec94f731b942f723212363745a6a31da8c3b57e1fbee233871a019ddcfafc1d02bbf87a6f426a4dd58850925246b4df3d7e7d0fbba748b0aa511fbff6e51bb70a48b08596891dd7177fa1e17efabd3452431349af299393817255d4bde230c078a97e37d895d2a975c0de26d553254b403f5b548cab320fd670f42973b13ae43de1d02d26eacc2b8d92538d961c7407d2d5c0725e2402a417d75297f9d0a5bce5727c82b2a1417255d0b94f4784e24fd596fb95d4d0c75d126e55970e240337a5faf46c69dab786b2d46973b13badc991eaf0b07c2c90e3bbeef3ee2f19e13079a55f5e1fb9cae612b2e7f7d835e074de94d1837bb04c75e7cc26b6056f6e850af730565c13fcf76f169bf80dbef0e2505582dd40a07c612da71b34b907663155c875aa1cbf52ec1e50be1f9bede3bfe502bbefda81edceead210bdda0d7e1d47997e1ac8c4c9c95311963b34cfc803a71a099172d3d2f29bf1063b34c1ef735e5916a7cfdf34b3ceea1cfe9c29d1dc147512a7bd44bff652883b6efcd97f1c365eb8216763050ab8f1bab82f2df855657eafe42b9e7f1cb37a3efe19f7a1c6b1a0436f704b7758e5a6f2038bf3b5c4c9c18a3fb001544fbc365ebc2fa81d47f977211004fcb2be7228d045dee4c4c79ec2fe81409fcb963c16d883876cabd1f13f02d685f1503d4a2ac2c8a5612234444caa9e9726762ca23d5700dbb2b00785743cd2788f0f353afadf07a8254f6e8f0f9b8c05c8d742d71651a86573f85028e06eb4dab6401ca671ec60ada507c6da5e0dd950890766395d71ca0cfe9c2b65ef90dd052289516ab265215c54643dd12edc90e7bc40416295cc38b54dffd703ae0f4748dd63a75589c1ab8f5eeca97de412fb4dee726ba5f63840f2d80902225b1c6407d1d4eec6f025d91952358eb2d55ba410ccd0b1757b562a88b76a0be1667a59d83704f2cc381eb502bfade7c39e8148257fb0217b770534334464d46335aba32196f0cd4d761e895dfe3b81f51d302ed42f1370d125723d0b8b75465292139de35e079b2b2d45f2a3fb0df737957d889219ed1763efc5318f43a8c5fbe396e44fe9ff5cbfdba1fee4dcfd2198474c77a203c9f457c6eba62497d6cbaf19a0e92668901108e7454f1532b33737248d729e87770a73ada30f4d987707d7300ba8979fedf24016d6f1d2801edba91e8a4a69df2d85f42bac168c59fb0dddbd55c78fd1d41590a91b883f18fdb5dca6e458b566c29d91aa46403b3e6f2c7e85e4abafd8c6efe0db6a7bb1264892a166b699c39edc6aab0df8cd20cd4d7490adb739fa68bdfc749f7640a77dd53a4acac1c85e3484d12a9423ec15c474968b908dadd4c2d4817e004f0dbcfa8f0cbd70070ef7ea79b88c3257ece64742fe2c443c4e4c4fe26d9d7da8fe8d0fe2278911709362d4b17120a8e7313fd57908dc40453dce205004a4a4ac2f6f97cf7602a7a19f1fb2bfd102cba897924710a082d4f23daf8be473af15fb8bb9e6e4f13170a1297b508568856bd67e17da982f60c6f78f1a764937f8087db43a1830000ef0201ee721214e11341dbf9f04fa19b3e0bf1103539fb3f0725935f693e382d614177f26ca8766f2ece99ecbfac853fa4fc6e9acb2db50b0790aec2aa24c176828b563cfac7fbda813ffc440000edb4edf1b32b5a2e964d454dad76b36043b152a46b49cd45a1b56e1e241b8b01f95d38525558d5a6a0a020ec9f1909b4c2fce6298ffd25e6adb714c29d3c06bd0e4b97baf8e23f4a32259184ffc4c72289d40664bd5e1f813b093f5a4de94dc80863465e24f02ce4e9f2a86b48ab578909656b588ece5dac5eec73472aaf448d0dc8b182f6c481669cbd7b2bba9d2ee8a6cf42529e2526c382527b3f01e97d96963c60e952cf288912f55bd2b524f1aacfe9e207070d0fca4d2e95acf02a85787512206e494b4b8bc4d9f18516004e9d7719523332412327b1c8c90ee94a8f749fa5413f2c6a41752a61b14d31a16e30d89ce602d2c8d79d43be97dec381d43ca4a5a525eed35d81e10dc200d9cc2bcc6fa63b620c57df1213eecad02bbf973c4e2793744572e91a6259859d1fa47cef7343f495851193c264f7127e241673d45ec08976b4c2dd282eb845adc9c84452c6e4981076e7af2be0125928ea8e1ce922857968a52a4b9e8baf4748e990f068ac21ceb976e4b8fd6d7f0344ed1dea520b3856ab55d5cf8c26b4e32f99e7b5539cfaaf273bec443807f741377d16a63c129ec23c8140b7a8c96d3676977d00005a728d7c474382d445f947930ec2f21085c9a1973d16660856a5bb8f476275325e62dca1a2fdbee72b0cd4d70280c7865d835e87ef7e38dda3604fb4d013c00e7a613e09cd1f918a7137777afba534361d0a3718dcfeba5ce9638adae9aea375ef2445eb3ab88f1772eab515382b83a4438ecd3241339c5475ecc527009015c048a7c60692ce5a3617a09658e8920863dc14255d120af5af4b041d19a4503bdd556aef6438f34a228d960afbecff1c44af8f3269b486482485ed3ad4ea57d8803837db2599e64af34ac479dc55e9236b013825d16db969a42452ab935261402510e67900a2a5f12842dbe77401ce7d92391934ee4d8be2b80eb562a0be4e957a2281d0f7e6cb019f2b5cb8a1a27ee945728c0a7b838467539936b27bccd1b9b3032b05214129d4cc2b71f60f4a860195589d6cfe2e41333bdbc80dd9f6e2e4270d98b2ef2d4e633f8ab1855702706f46185b58ca9f3fe20f0d01af864fc282387497b8701fa241af832b02ab99815a6d71e84fb81ab96195fb8fdddce9bd703352ab0d90f73f98e1fe1a905fc051b3d4f0a736e9452da5f24a3e721c251b174acb81d27208c53eb8ef2d68ec4771fcf9d500c82602ce64846e621ec64c9a8ab372cc382bef42c9dd334ac277101617a1174f2e8565cd2291fb4da33672085bffd1967e7452b954d0208a7667a0f16e8a41af43fda4e00a624ad1f4adbb86f78ee1ad8aebbe922e4ccf719f8decc37cb07efd2bb8f7de3f781defefef0fcb228e94d8e5185b78a52aa2f7688f2d44377d16269494f12142ba939c5acf7085065d875a654bafc9415d12da07937645a33b6fa4baa085d26d410a610d137abdeb0e798702d5688d2de4a73f5d87575ed9ee71cc64cac5962d2f47c4450846ec142afab1175a31e6875382766fbcc44de3dedf771fc1f7dd5d5e6511e8ebd46d01d4dde8e0cf6253a4ba1c93f835785103d2c27e7a527055a6fc71dd2132a9a4853533f77b9f535464c1071f6c56ee4345d01ef0422a2a2a505959191593bf50c40e90ed63ba8979483cff127ee3b09ce8bd1ec2c73f7cc7cbb7155a71c07b712792717071e705ea9258f23c450d102b2e151d5152d880db1df185c5a2de64b2b6f67dc9c9647171b16a9f192c629f7d4efe0cee64e3dffc8a5d633f8a93f6a31e3b6e843e7d5bf91a5ee83e3dccd46b89b37a56c6649cd8df84a1577ecfffd252afade0453d505f87632f3ec1f7d451127f565bd87981f6b814b6e5a62b91cd9dc0860d9eef2d4c0eae6c7128347d2b7d5ccd30e06baf49bb3b0505053871e2846a9f3b12feb9ff8b90c44ed1d88f7a45fc7c8a5bb80a48232919c32ec9407d9d870f4e8bdb841bb13bb267b77bb25836575ed855e9ea0b1b900f03aa99eafabf6fbee975cca0d7e1c4891351e192044228624f9ef53f1edffb8d0d505127e61742d37d0403f5b5e87e7e0dffdaf84be6f1998303f575e8fc7585626e8a5c8e36fd6cd268d5e5d1044a389904a41baf864bd840f8c380adaded922ec9ac0b0a55f9bc701188d893aebed5a3abb05f71f7395d80c80fa73eb894054fbdb64231ff9bd65491bb2fa1ff2c8c6fd3145671b80f507ef2e80fa95457835ea75ac7b1575f7d57f278bc2dbb8bc53e3bdbc8911a2a6e828eeaeaa6cfc25969e778587000bc050748fec7480b6bba0eb5fa4d8ea28206dc6db43b0add39254261172693c51525c27dc170708c67c62100e4e58756862c10de7b4f3a13309a26936a2016361082b85d07f7793557325c7d0b4e76d8f978b46efa2cb2a2b8ae12e39793709770c249d355858b42273becfc64b4e7afcf81dbbd55f61e84bbd9a988697444aa977d557a687ddf47cab153d23b61d48c94c8f5781f0dc5e6c568972e8540108133fe9279d0646402dd5d38beaed2e38f98feb30789986ffe2500e0f8ba4ab89c2ea4ffec413e5dd5a0d74177631506eaebd0fdfc1a64dcb90aae43ad5ebd6ac418f43ab41f019a37b83c26937b767b4f1a0d7a1d56ea5d61754384c8254ca995532297bf3d9a362808d16ed8405244a9253cd21598d0e56af28d5fbe197d6fbe8ca43c0bc6669978e167dcb90a273becbcab9178f32fe13ad48aeee7d740377d167fae3fa89516d6fd13c7ae016aad47be9c3e12c47de22973e6fc4895cf9313f768a95322c6638552ecc31ee922cbd681166ecfb87315df6158d85089ae6ad238396dc9ddfb7a35bf08e4cf620bef11901f80917241a4905a7607d4cb29b9f4d24a49b7a4aeae0e696969a3ce2d91cd2d71471f489c38f128503f5c0d205817465c874f377d9687dfae44b3d2681235259ccbeecefe414c301449be16ae64a96843fb999934181567ad89ab345d56e8b9b19686dba88517be4f8c58bcc255c73e7ee32ef99e66f651fc3d3da251d480fcee9b2bae5067f1a6bee123c9e356ab75540a1b00b4e7b79030d96766d24d80760310c2c7944571652a44eaca48d500912b5926354800399fdf53d885c964af62a4268a81b0b947fab85a2b9372fe76bcc5b7834153954edc92e64192c95699e66e813192a645161fa1dc60fc784a553a299560d5479f95164373baa518e8db037d8af22d85a74dbb1e76fb21afe3369b2da696dd958417b71c25e3a47b2baa8941afc3f4d32ebeee5eb8175e46c2b153c0f93295ca4ca65cb4b5bda6f867caf9db06bd0ebbfe563f2a850d005aa91d22429e3b467e4937e95cfc0a5fd3b79e8207c84a5c30d6980a18204f8c73138990737440ba56b9d2c2e1e4d829e0ce0ef9d7fffbbfe7a8f2b9afd7be2779fc9aeb6f52e5f36205ad78078a7027891b72a07308a8ff8ab82eded6345841c6a680e568fad67fcb3eb5fcedddbb3f973c5e5656a6cae7c50ab2a1403984169712ed933b25a1835ff8e40af4a9a5567c5b6ad70d307a438014ed8ea093d3dcbf44e242287a3f1145b8b140b8ba485d2f79abec5fd837dfbc28e4fbf285dcae9b850be72b2eecd9d946ce555f8b84d474d2b62fcad10aff88feca7f459b98e576b950a496bfc529a8e19a20af58f11355ae2db7ebe69a6b941f4c1f398e6a90331b96b3cf70d39e5fc58d993415e32b974b66e4450341bb2581104c57826027a2b1c81b6f3c85b2b2cb55b9b6944b12ae284941bf83eb7de101e826e621a9ec675167cd55b1c3c159c3f815b641af43f59675aa095bce25095794c49692adc1fdaf21bffd23aeefe19b90057049d7ff024957df1a1525d654b1dc0c9243f2e73f2f576dc70d009495fd1a3b77eef23a1e89859b39f933b8c1979fe1ab4c712623527ffe078c2dfeb1aa55a57cc1c4ad300b17cec7b26565aaf7ba696d6d87d97c9dd771abd58a75ebd645cc6a8a450e0049d7ff02632fb486dd6d61e20e11932917191929b058a62325653cacd60b7141c14c5596d6a590aa28050035353598366d5ac45d82d9d946eef8e67538f1da9ff9639cc9087de92f90b4b03c2c93d051296e2a4c29a858292929e33d76cea86d910341ce6a47b25c9a1c52220748a934b527a11111b72f7101c0c489e7a0a06092eceb62c1c9110d42548368b7da52c8891c206e8b1a9350cdfbef6f524cdcf12aa6682296acb614be44ce998c48b9e6219c5d76ab32555e39eeb351e796c432725bc9a2d96a4be14be48032935026ee18a2b6f67d5c73cd7d5ec763c56a4b21155d113292492813778cd0dada8e4b0a6f965cb469686888f9ba2473f26770dfd5be84fe371e972d7a99f1374750024f50ecee18aab270e143b20952b12e6c809447db9f335bd379ff6b1ac3635bc1998c1eaf732623b3dcf1885c74c4a0d7e170e757719bd66a39fb0c77fcf93538d9f477a46dd9137c670526eee8a5b5b51dbff8c53ad91269a3a51ec99cfc195c28d11326ee28a3b5b51defbcf3ffb063c7fbb2a206622f3a1209b4ebd7bf8279f3fe4bd5041f06116d77772fffbdc371140e079938d96c5fe29b6fbef22966214cd881a1edef3f8e575f7d170505d3554bcd8c17c4b541c4df8bcb071fd87f40d15c759329179b36bd101713c870c0e773db6c0761b379f70a0780ec6c23b2b38d92af499191911a154f0267ffa06cb351b130fbfb8f7bf54a0fd492aa8941afc3ac0b0a51565686f2f2f2b89d3caac1a84c9c8a568a8a2c9838f11c582c7350505080fcfc7c1c3d1a9d5bb8620126ee3042ad30e02e73565c5c8c949494515b154a4d98b803c064f2dd5852aa8c59434303ff75b03eb2d96ce61c0e0713fc08d1fafbc301404f77d788264606bd0e691999fe4ff44346460ab4dac0fa374e98908c891333fc9e979d9ded75acb7b7174ea793fffe9b6fba31304036869e3a751cddddfdfc6b3ddd5d5eef070217b4d168e41c0e071a1b1bd1dcfc4f4c9d6a42414101cacacad0d22253978d11109ab56bd7c695e5160b1300dadb3dab524a0954e91df8e27d8c4949495c6767276c361b9a9bffe911fa5bb8703eaeb966111534b3d60aa175381cfc377abd1ea9a9ea948e127e8e14274f1e4757d7d792af89c5485143944a61b3d9306dda3498cd666eea9473bcee73e1c2f9a8a9a9f11034b3d4caa2adaef6dd0e8f111a8d8d8d98366d1a152e0790cdbbe5e5e54cd061824d2855429863ddd3d3c3b1b05ef8d158ad562ed8c997c3e1f0f2637dd1d575849f0ceefbb4296a5d09a519cd85dfa3016d57d711747501c017fc41357c59bb5dd1cbc504757575282d2d8df46d8c5a985ba2224545163cfef81f99e58e102316b770d54d8a9c9c1cc958b210bd5e1ff146a00e87039d9dd2dda99a9bffc9c7b929c2451a7fd765be7664e0e3dcbe04969d9dcdfe407e181a1ae28d84cd66e363ed0b162c607e7784d0ecddbb37d2f7c060a802db20cc885b98b819710b1337236ed10a274200593696a3b7b717369b2da00b8773b1c664ca4566e6649fe7141414f8cd9b292e2ef6f93acbbb8e2d589c5b61e442a3e21eece281c4f6452a8f2271eebc7c1f8dde25b8e28a91578395daf32887d21b75d5463c408403830e0af614f18f66d5aa3b8633d6a405172d9b7dd5405c6e01201ba5fbfb8f7b9d2bded92e24d21b898b8a2cd06ac763c28464582ca405371d04a3f989c08af2a884d4cefbfefee35e15068483a6bbbb5f72cb9a1258ad5600e4294017ec0a0a0ae27a7304137714237cb2089f287440283518ac562b727272909f9f8fb2b2b2b8598d66e28e03844f095a8f8556b10a65be51515181952b57c6bcc899b847090d0d9ff06ed1bfffdd8b8e8e769f7305835e872d7fd916d3853699b84739b4f0e6da55cf4a5af858ae4be8d5f0495c664c4c3021385f041a61f0d7f92c10c4edf7a4188dd12221be3a37c46aa964b688132252832e2b2b07e79eebb90a2a1e34e16cc41a2c720237e87578bfb129e6e2ea4cdc11a6a8c8c27f2deebf490746389f1ef12470d5c45d980c1c1ca31bf1cae06766e07c05aa1f1426034d83fecf53ebfd4a409f16f40941abef2a2dfe86864f70f9e5b77b1d8fb536255ee2ae4a079a0747f68734e875f83cdb85eb0e8dec3a55e9c0f27330e2eb00c08e1ca0fe5be0b963a1bfffbac037fc7ba0d440f7074d85a0e21f493ffaf5eb5fc1bdf7fec1eb782ced0bf510776132f07c16d0ee0afd0f091021148e0332f78fece63e3303e95a60dd57a18bb23019b8c1002c4e05b6f502f77e19fc35e8200be53ee8400ff5b3957862984cb9983dfb02ac58f193a02cbc5c43d78a8a0a54565646bdc03dc44d4579ec54e0ae4061326019360c25e3801c1d1124109cb80d7a1d6ed2b9706e2260d5bbaf01042e2ae135a624929f458caf6bd1f703e0af21fc79821168e1f0efe4f92cf7fb7fe408de7a77e5076f24aad2a57f469329179f7cb425604bee2b82120b2142cd8e1c705222f0e70a54a50395699e221412ec00b9c140c424c513dd8159afaa74f9d74ac6f9764b0c7a1d36a7913fa250d062e484e66b70520219a474505892c93d178e0bee89419f32720369e1c2f9a8ad7d24b08b01a8a9a9c3cf7eb6caeb782c4c30353b72bc27949d43a13d42473306bd0ed34fbbf8a718e0b6fe14b9c145dd41b90105480f2ae140a09fb7783812e9eb29f3f4d30f60d9b29be53f4c4459d9afb173e72eafe3454516bcf5d67b513bc164a1c028422cd692e127aad4fc45f8b4937bd2f87afab6b4ec08d8ff76f60f223bab54f249b06cd9322c5ebc7874885b890910f5e3439d442a7d3fb1027d7a00ee0122f73b0cc5ff369baf937c2d5a5730f90dc2befcd540a94a071ef45f4fd32fcf1d863ea80000079849444154679147ac123c9f15fa7b0b9347f67b290cf342649fd385a6e130ee73c77c1b07bbfd106e2dff5dc0d79e393307ab56dd21f9da6d3f5d0cb3d91c751e4002e09e848cf48f519936f21baa4a278fd8c523ac815f984ca23fe9dad07fae1b0ca1ff4c55e9c08e5c624d832594f784c2ce9dbb505bfb7ec0e7af5ebd44b23f509fd385db6e0bdc870f179ac264703b86ef379859b97002258c1084120bae4a970ebd051a0293bb174a20911b6148537c8d601691e8bdd0096228f16dfab408e6f718aafb65d0ebe0e8d8ad487830dadc13cd676670f48fd8f4adffc59ba727c987ba80e0c35672e1c44043893404572211ce04c860d9dc237f4ff4a9e50b7f02a5933ba9df4b3021513a3076e406f73e80fc5d80d0a25cc1860757afde88356bfee4753cda96e7355df9ee09e5485602e305e1a40cf06f0da9951587fd02790255a5bb63d952f8fa7b48c5c381d0168a00e0fdf737c9a6fd4a316ddaf5925bdca269f5928502238838364e9f3e7460483d31fc3d390379fa4a6132e5a2adedb580cff7153d696868888a5df78a8adba01f7972d0d39380b5ce915f47897b8905a416725eed0bcdff5eb5ea0eac5ebd24e0f3e5dc13613fa0489260d0eb140903eec8019f97112a85c9244a32d2eb00e41a4f4ff27f9e1c4f4f1a59d4225c110f71e8efde2f438feb3ff3f416b4b6066ef6e5a22776fb21ecdebd3be21e41c2e634f9c958a054a5139faf79848b253718c8ff238d71d389aa551fdafb0d7a1dacfad007d98e1cf0792ab1449fd385471ffdbf41bde7cf7f7e58f2f8d37f5807a3d1185181f313ca6026227261b360f3aee975c4597cc1f88dbeb21201ff910e29bf97de47b0110b1ab9a1d19750f2d077e4049e2846517a1536d8c9a55cee49a42797bcb8fd454a7c85bb2881fe310d7a1d56ea5db20b3581c6860b93fdaf88fa120a4df1f585af9f49188694caef083645d6924cc292c1c6c63f330377762827f0a2220b3ef86073c0e7fbca3d89e4e4921777a8bb5d84a1b358cfe110af64fada3d2395fbcd5f27802790bfa887afbf87701249d709428d92c811acf596dbb963b55ab16eddbac8881b2c1418118402150e0e3a30c4e2a6f9e6be72cd955ca708363408c8c7be23b5b181893b46910a0102cae6e1bff8e21a94972f08f87cb98dc5910a0d3271336409c57acb4d2ed7ae5d8bd2d2d2b00a9c899be19360adb7dcca6524f24e7c8a7ba4a5cc0229633652822def16e942f1b14628d65b6ee532dcd69b15c2f481bfba8900e0701c85c37154f6755f834fcd62f34a12acf5960b0d86db7a3371472152ed4c00efc1263570d478328562bde576cd87736187893b8e11b72e117667100e8c409e20c1c6bd01f9d0a0c3e1084b617b266e860772ad4aee5b764bd065d9e44283e1b2de51296ea96649a1305a6a6b47337225d9c261bdbd8acf537c4da67cb5ad036267a2e48f407b6cfaeaab492bb18a192d032f92d69bc5b9a30ca9f0ab544835968ada47ca7a4795b80d7a1dd23232255fcbc8488156eb3b669e93139a25cccece0ee97d421c0e4750e79f3c791c5d5d5f4bbe76ead4717477f77b1defe9ee0a382d593c48c403443838d47e8ac82deca86dbd5517b79460333327877cbdaeae2323bd259f042320397c0d523172bf8bcccc1f60ec58cfc1acd7eb919aea99272c1c54e201231c2481fe5c62574ce8721514b80748b04f0a29ebad76c66054596e46f088b7790907cb8409c99838d19df02e7c42d141f1cd37dd181820e987d470043bc085ad4fa4e61ffdfdc7b161c356afe34cdc0c55103e5d842e9f7040e8f57a389d4efe89409f044a3cdd00f597e399b81901419f10e2b9cfa953c743ea521c8ea578266e46440847e9b504ffa73018ca52515111969a824cdc8cb0525464095fe214a2d02d319972030a17969494781d73381c686ff7de29dbd575c463d5d46ab506742fa74e1d6739e00a61d0ebf0d9fe2fc2923405001a835ec7cdbaa050f24529f188292e2e0ef8c30a0a0aa2a60268b8181a1a0ad97834363606757e7d7dbdec6b0d0d0da1de46d0d0488c380523dc1b85357bf7ee0dfa4d46a3910b7645ce66b3c1e97406fd59912698c10b0029292951dde14b48525212d7dfef5e0975381ce8ecece4bf170e967d9f36f98d8818f43a145f7e052c963978f7dd9dfc13afa8c882679f7d21ecbf178dd56af5b22ce24738435d0c7a1de49e9e724c98900c8b654e50efd1ebf528282808ea3d42e8c0351a8ddcd2a5551e1b810d7a1d6eab204534b7546f449fd3059329172b56fc2662fd2aa3d2e766442f26532e9e7cf269a4a5a569dadadab8f2f27200eec29f7d4e170c7a1dee7d6039eeb9e79e88baa14cdc8c90a0197d62814783a8294cdc8c9010f69fece9e9e16a6b6bb172e5cab045420281899b1132d1deff9d2de23042a6bcbc1c6d6d6d516b1c7d741b8f4ee4220b393939b29b0e0a0a0aa0d7fbaf441fa938fc4862e14a136cc8b6b3b313d3a64d53f18e4227ac6e495191c523a34cbc482416612cc58c19d147c8e2162e5f0b452a142813272392f0e2163eee858f78a158a3a1fd1a831128dafefefea8884932184a93c084cd885758289011b7307133e216266e46dcc2c4cd885b98b819710b1337236e61e266c42d4cdc8cb885899b11b7307133e216266e46dcc2c4cd885b98b819710b1337236e61e266c42d4cdc8cb885899b11b7307133e216266e46dcf2ff014aec27be8fe3b5c70000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>m_editUsername</tabstop>
+ <tabstop>m_editPassword</tabstop>
+ <tabstop>m_textDetails</tabstop>
+ <tabstop>m_listFi</tabstop>
+ <tabstop>m_listAccount</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp
new file mode 100644
index 0000000..d24f9a4
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp
@@ -0,0 +1,445 @@
+/***************************************************************************
+ konlinebankingsetupwizard.cpp
+ -------------------
+ begin : Sat Jan 7 2006
+ copyright : (C) 2006 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtextbrowser.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qregexp.h>
+#include <qcheckbox.h>
+#include <qtabwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+#include <kapplication.h>
+#include <klistview.h>
+#include <klistviewsearchline.h>
+#include <kcombobox.h>
+#include <kurlrequester.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingsetupwizard.h"
+#include <../ofxpartner.h>
+#include <mymoneyofxconnector.h>
+
+class KOnlineBankingSetupWizard::Private
+{
+public:
+ QFile m_fpTrace;
+ QTextStream m_trace;
+};
+
+KOnlineBankingSetupWizard::KOnlineBankingSetupWizard(QWidget *parent, const char *name):
+ KOnlineBankingSetupDecl(parent,name),
+ d(new Private),
+ m_fDone(false),
+ m_fInit(false),
+ m_appId(0)
+{
+ m_appId = new OfxAppVersion(m_applicationCombo, "");
+ m_headerVersion = new OfxHeaderVersion(m_headerVersionCombo, "");
+
+ // fill the list view with banks
+ KProgressDialog* dlg = new KProgressDialog(this, 0, i18n("Loading banklist"), i18n("Getting list of banks from http://moneycentral.msn.com/\nThis may take some time depending on the available bandwidth."), true);
+ dlg->setAllowCancel(false);
+ // force to show immediately as the call to OfxPartner::BankNames()
+ // does not call the processEvents() loop
+ dlg->setMinimumDuration(0);
+ kapp->processEvents();
+
+ tabLayout->insertWidget(0, new KListViewSearchLineWidget(m_listFi, tab, 0));
+
+ OfxPartner::setDirectory(locateLocal("appdata", ""));
+ QStringList banks = OfxPartner::BankNames();
+ QStringList::const_iterator it_bank = banks.begin();
+ while (it_bank != banks.end())
+ {
+ new KListViewItem( m_listFi, (*it_bank));
+ ++it_bank;
+ }
+ m_fInit = true;
+ delete dlg;
+}
+
+KOnlineBankingSetupWizard::~KOnlineBankingSetupWizard()
+{
+ delete m_appId;
+ delete d;
+}
+
+void KOnlineBankingSetupWizard::next(void)
+{
+ bool ok = true;
+
+ switch (indexOf(currentPage()))
+ {
+ case 0:
+ ok = finishFiPage();
+ break;
+ case 1:
+ ok = finishLoginPage();
+ break;
+ case 2:
+ m_fDone = ok = finishAccountPage();
+ break;
+ }
+
+ if (ok)
+ KOnlineBankingSetupDecl::next();
+
+ setFinishEnabled(currentPage(), m_fDone );
+}
+
+bool KOnlineBankingSetupWizard::finishFiPage(void)
+{
+ bool result = false;
+
+ m_bankInfo.clear();
+ OfxFiServiceInfo info;
+
+ if(m_selectionTab->currentPageIndex() == 0) {
+
+ // Get the fipids for the selected bank
+ QListViewItem* item = m_listFi->currentItem();
+ if ( item )
+ {
+ QString bank = item->text(0);
+ m_textDetails->clear();
+ m_textDetails->append(QString("<p>Details for %1:</p>").arg(bank));
+ QStringList fipids = OfxPartner::FipidForBank(bank);
+ QStringList::const_iterator it_fipid = fipids.begin();
+ while ( it_fipid != fipids.end() )
+ {
+ // For each fipid, get the connection details
+ info = OfxPartner::ServiceInfo(*it_fipid);
+
+ // Print them to the text browser
+ QString message = QString("<p>Fipid: %1<br>").arg(*it_fipid);
+
+ // If the bank supports retrieving statements
+ if ( info.accountlist )
+ {
+ m_bankInfo.push_back(info);
+
+ message += QString("URL: %1<br>Org: %2<br>Fid: %3<br>").arg(info.url,info.org,info.fid);
+ if ( info.statements )
+ message += i18n("Supports online statements<br>");
+ if ( info.investments )
+ message += i18n("Supports investments<br>");
+ if ( info.billpay )
+ message += i18n("Supports bill payment (but not supported by KMyMoney yet)<br>");
+ }
+ else
+ {
+ message += i18n("Does not support online banking</p>");
+ }
+ m_textDetails->append(message);
+
+ ++it_fipid;
+ }
+ result = true;
+ }
+ else
+ // error! No current item
+ KMessageBox::sorry(this,i18n("Please choose a bank."));
+
+ } else { // manual entry of values
+ if(m_fid->text().isEmpty()
+ || m_url->url().isEmpty()
+ || m_bankName->text().isEmpty()) {
+ KMessageBox::sorry(this,i18n("Please fill all fields with values."));
+ }
+
+ m_textDetails->clear();
+ m_textDetails->append(QString("<p>Details for %1:</p>").arg(m_bankName->text()));
+
+ memset(&info, 0, sizeof(OfxFiServiceInfo));
+ strncpy(info.fid, m_fid->text().data(), OFX_FID_LENGTH-1);
+ strncpy(info.org, m_bankName->text().latin1(), OFX_ORG_LENGTH-1);
+ strncpy(info.url, m_url->url().data(), OFX_URL_LENGTH-1);
+ info.accountlist = 1;
+ info.statements = 1;
+ info.billpay = 1;
+ info.investments = 1;
+
+ m_bankInfo.push_back(info);
+
+ QString message;
+ message += QString("URL: %1<br>Org: %2<br>Fid: %3<br>").arg(info.url,info.org,info.fid);
+ if ( info.statements )
+ message += i18n("Supports online statements<br>");
+ if ( info.investments )
+ message += i18n("Supports investments<br>");
+ if ( info.billpay )
+ message += i18n("Supports bill payment (but not supported by KMyMoney yet)<br>");
+ m_textDetails->append(message);
+ result = true;
+ }
+ return result;
+}
+
+bool KOnlineBankingSetupWizard::finishLoginPage(void)
+{
+ bool result = true;
+
+ QString username = m_editUsername->text();
+ QString password = m_editPassword->text();
+
+ m_listAccount->clear();
+
+ // Process an account request for each fipid
+ m_it_info = m_bankInfo.begin();
+ while ( m_it_info != m_bankInfo.end() )
+ {
+ OfxFiLogin fi;
+ memset(&fi,0,sizeof(OfxFiLogin));
+ strncpy(fi.fid,(*m_it_info).fid,OFX_FID_LENGTH-1);
+ strncpy(fi.org,(*m_it_info).org,OFX_ORG_LENGTH-1);
+ strncpy(fi.userid,username.latin1(),OFX_USERID_LENGTH-1);
+ strncpy(fi.userpass,password.latin1(),OFX_USERPASS_LENGTH-1);
+
+#if LIBOFX_IS_VERSION(0,9,0)
+ // pretend we're Quicken 2008
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/
+ QString appId = m_appId->appId();
+ QRegExp exp("(.*):(.*)");
+ if(exp.search(appId) != -1) {
+ strncpy(fi.appid, exp.cap(1).latin1(), OFX_APPID_LENGTH-1);
+ strncpy(fi.appver, exp.cap(2).latin1(), OFX_APPVER_LENGTH-1);
+ } else {
+ strncpy(fi.appid, "QWIN", OFX_APPID_LENGTH-1);
+ strncpy(fi.appver, "1700", OFX_APPVER_LENGTH-1);
+ }
+
+ QString hver = m_headerVersion->headerVersion();
+ strncpy(fi.header_version, hver.latin1(), OFX_HEADERVERSION_LENGTH-1);
+#endif
+
+ // who owns this memory?!?!
+ char* request = libofx_request_accountinfo( &fi );
+
+ KURL filename(QString("%1response.ofx").arg(locateLocal("appdata", "")));
+ QByteArray req;
+ req.setRawData(request, strlen(request));
+ OfxHttpsRequest("POST", (*m_it_info).url, req, QMap<QString, QString>(), filename, true);
+ req.resetRawData(request, strlen(request));
+
+ LibofxContextPtr ctx = libofx_get_new_context();
+ Q_CHECK_PTR(ctx);
+
+ ofx_set_account_cb(ctx, ofxAccountCallback, this);
+ ofx_set_status_cb(ctx, ofxStatusCallback, this);
+ // Add resulting accounts to the account list
+ libofx_proc_file(ctx, filename.path(), AUTODETECT);
+ libofx_free_context(ctx);
+
+ ++m_it_info;
+ }
+
+ if ( ! m_listAccount->childCount() )
+ {
+ KMessageBox::sorry(this,i18n("No suitable accounts were found at this bank."));
+ result = false;
+ }
+ return result;
+}
+
+bool KOnlineBankingSetupWizard::finishAccountPage(void)
+{
+ bool result = true;
+
+ if ( ! m_listAccount->currentItem() )
+ {
+ KMessageBox::sorry(this,i18n("Please choose an account"));
+ result = false;
+ }
+
+ return result;
+}
+
+int KOnlineBankingSetupWizard::ofxAccountCallback(struct OfxAccountData data, void * pv)
+{
+ KOnlineBankingSetupWizard* pthis = reinterpret_cast<KOnlineBankingSetupWizard*>(pv);
+ // Put the account info in the view
+
+ MyMoneyKeyValueContainer kvps;
+
+ if ( data.account_type_valid )
+ {
+ QString type;
+ switch ( data.account_type )
+ {
+ case OfxAccountData::OFX_CHECKING: /**< A standard checking account */
+ type = "CHECKING";
+ break;
+ case OfxAccountData::OFX_SAVINGS: /**< A standard savings account */
+ type = "SAVINGS";
+ break;
+ case OfxAccountData::OFX_MONEYMRKT: /**< A money market account */
+ type = "MONEY MARKET";
+ break;
+ case OfxAccountData::OFX_CREDITLINE: /**< A line of credit */
+ type = "CREDIT LINE";
+ break;
+ case OfxAccountData::OFX_CMA: /**< Cash Management Account */
+ type = "CMA";
+ break;
+ case OfxAccountData::OFX_CREDITCARD: /**< A credit card account */
+ type = "CREDIT CARD";
+ break;
+ case OfxAccountData::OFX_INVESTMENT: /**< An investment account */
+ type = "INVESTMENT";
+ break;
+ default:
+ break;
+ }
+ kvps.setValue("type",type);
+ }
+
+ if ( data.bank_id_valid )
+ kvps.setValue("bankid",data.bank_id);
+
+ if ( data.broker_id_valid )
+ kvps.setValue("bankid",data.broker_id);
+
+ if ( data.branch_id_valid )
+ kvps.setValue("branchid",data.branch_id);
+
+ if ( data.account_number_valid )
+ kvps.setValue("accountid",data.account_number);
+
+ if ( data.account_id_valid )
+ kvps.setValue("uniqueId",data.account_id);
+
+ kvps.setValue("username",pthis->m_editUsername->text());
+ kvps.setValue("password",pthis->m_editPassword->text());
+
+ kvps.setValue("url",(*(pthis->m_it_info)).url);
+ kvps.setValue("fid",(*(pthis->m_it_info)).fid);
+ kvps.setValue("org",(*(pthis->m_it_info)).org);
+ kvps.setValue("fipid","");
+ QListViewItem* item = pthis->m_listFi->currentItem();
+ if ( item )
+ kvps.setValue("bankname",item->text(0));
+
+ // I removed the bankid here, because for some users it
+ // was not possible to setup the automatic account matching
+ // because the bankid was left empty here as well during
+ // the statement download. In case we don't have it, we
+ // simply use it blank. (ipwizard 2009-06-21)
+ if(/* !kvps.value("bankid").isEmpty()
+ && */ !kvps.value("uniqueId").isEmpty()) {
+
+ kvps.setValue("kmmofx-acc-ref", QString("%1-%2").arg(kvps.value("bankid"), kvps.value("uniqueId")));
+ } else {
+ qDebug("Cannot setup kmmofx-acc-ref for '%s'", kvps.value("bankname").data());
+ }
+ kvps.setValue("protocol","OFX");
+
+ new ListViewItem( pthis->m_listAccount, kvps );
+
+ return 0;
+}
+
+int KOnlineBankingSetupWizard::ofxStatusCallback(struct OfxStatusData data, void * pv)
+{
+ KOnlineBankingSetupWizard* pthis = reinterpret_cast<KOnlineBankingSetupWizard*>(pv);
+
+ QString message;
+
+ if(data.code_valid==true)
+ {
+ message += QString("#%1 %2: \"%3\"\n").arg(data.code).arg(data.name,data.description);
+ }
+
+ if(data.server_message_valid==true){
+ message += i18n("Server message: %1\n").arg(data.server_message);
+ }
+
+ if(data.severity_valid==true){
+ switch(data.severity){
+ case OfxStatusData::INFO :
+ break;
+ case OfxStatusData::WARN :
+ KMessageBox::detailedError( pthis, i18n("Your bank returned warnings when signing on"), i18n("WARNING %1").arg(message) );
+ break;
+ case OfxStatusData::ERROR :
+ KMessageBox::detailedError( pthis, i18n("Error signing onto your bank"), i18n("ERROR %1").arg(message) );
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+bool KOnlineBankingSetupWizard::chosenSettings( MyMoneyKeyValueContainer& settings )
+{
+ bool result = false;;
+
+ if ( m_fDone )
+ {
+ QListViewItem* qitem = m_listAccount->currentItem();
+ ListViewItem* item = dynamic_cast<ListViewItem*>(qitem);
+ if ( item )
+ {
+ settings = *item;
+ settings.deletePair("appId");
+ settings.deletePair("kmmofx-headerVersion");
+ QString appId = m_appId->appId();
+ if(!appId.isEmpty())
+ settings.setValue("appId", appId);
+ QString hVer = m_headerVersion->headerVersion();
+ if(!hVer.isEmpty())
+ settings.setValue("kmmofx-headerVersion", hVer);
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+KOnlineBankingSetupWizard::ListViewItem::ListViewItem( QListView* parent, const MyMoneyKeyValueContainer& kvps ):
+ MyMoneyKeyValueContainer( kvps ), QListViewItem( parent )
+{
+ setText( 0, value("accountid") );
+ setText( 1, value("type") );
+ setText( 2, value("bankid") );
+ setText( 3, value("branchid") );
+}
+
+void KOnlineBankingSetupWizard::ListViewItem::x(void) {}
+
+#include "konlinebankingsetupwizard.moc"
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h
new file mode 100644
index 0000000..65a89de
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ konlinebankingsetupwizard.h
+ -------------------
+ begin : Sat Jan 7 2006
+ copyright : (C) 2006 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KONLINEBANKINGSETUPWIZARD_H
+#define KONLINEBANKINGSETUPWIZARD_H
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+#include <libofx/libofx.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qvaluelist.h>
+#include <qlistview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingsetupdecl.h"
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+class OfxAppVersion;
+class OfxHeaderVersion;
+
+/**
+ * @author Ace Jones
+ */
+
+/**
+ * This class implementes a wizard for setting up an existing account
+ * with online banking.
+ *
+ * The user is asked to choose his bank from the supported bank, and
+ * his account.
+ *
+ * Currently works only with OFX Direct Connect, but I imagined that
+ * other protocols could be included here. To accomodate this, we'd
+ * add another page at the start of the wizard to ask which protocol
+ * they wanted.
+ *
+ */
+class KOnlineBankingSetupWizard : public KOnlineBankingSetupDecl
+{
+ Q_OBJECT
+public:
+ class ListViewItem: public MyMoneyKeyValueContainer, public QListViewItem
+ {
+ public:
+ ListViewItem( QListView* parent, const MyMoneyKeyValueContainer& kvps );
+ virtual void x(void);
+ };
+
+ KOnlineBankingSetupWizard(QWidget *parent=0, const char *name=0);
+ ~KOnlineBankingSetupWizard();
+
+ bool chosenSettings( MyMoneyKeyValueContainer& settings );
+
+ bool isInit(void) const { return m_fInit; }
+
+public slots:
+ void next();
+
+protected:
+ bool finishAccountPage(void);
+ bool finishLoginPage(void);
+ bool finishFiPage(void);
+ bool post(const char* request, const char* url,const char* filename);
+
+ static int ofxAccountCallback(struct OfxAccountData data, void * pv);
+ static int ofxStatusCallback(struct OfxStatusData data, void * pv);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ QValueList<OfxFiServiceInfo> m_bankInfo;
+ QValueList<OfxFiServiceInfo>::const_iterator m_it_info;
+ bool m_fDone;
+ bool m_fInit;
+ OfxAppVersion* m_appId;
+ OfxHeaderVersion* m_headerVersion;
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp
new file mode 100644
index 0000000..6e5cef9
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+ konlinebankingstatus.cpp
+ -------------------
+ begin : Wed Apr 16 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+// ----------------------------------------------------------------------------
+// System Includes
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qdatetimeedit.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kled.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingstatus.h"
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <libofx/libofx.h>
+#include "mymoneyofxconnector.h"
+
+KOnlineBankingStatus::KOnlineBankingStatus(const MyMoneyAccount& acc, QWidget *parent, const char *name) :
+ KOnlineBankingStatusDecl(parent,name),
+ m_appId(0)
+{
+ m_ledOnlineStatus->off();
+
+ // Set up online banking settings if applicable
+ MyMoneyKeyValueContainer settings = acc.onlineBankingSettings();
+ m_textOnlineStatus->setText(i18n("Enabled & configured"));
+ m_ledOnlineStatus->on();
+
+ QString account = settings.value("accountid");
+ QString bank = settings.value("bankname");
+ QString bankid = QString("%1 %2").arg(settings.value("bankid")).arg(settings.value("branchid"));
+ if ( bankid.length() > 1 )
+ bank += QString(" (%1)").arg(bankid);
+ m_textBank->setText(bank);
+ m_textOnlineAccount->setText(account);
+
+ m_appId = new OfxAppVersion(m_applicationCombo, settings.value("appId"));
+ m_headerVersion = new OfxHeaderVersion(m_headerVersionCombo, settings.value("kmmofx-headerVersion"));
+
+ int numDays = 60;
+ QString snumDays = settings.value("kmmofx-numRequestDays");
+ if (!snumDays.isEmpty())
+ numDays = snumDays.toInt();
+ m_numdaysSpin->setValue(numDays);
+ m_todayRB->setChecked(settings.value("kmmofx-todayMinus").isEmpty() || settings.value("kmmofx-todayMinus").toInt() != 0);
+ m_lastUpdateRB->setChecked(!settings.value("kmmofx-lastUpdate").isEmpty() && settings.value("kmmofx-lastUpdate").toInt() != 0);
+ m_lastUpdateTXT->setText(acc.value("lastImportedTransactionDate"));
+ m_pickDateRB->setChecked(!settings.value("kmmofx-pickDate").isEmpty() && settings.value("kmmofx-pickDate").toInt() != 0);
+ QString specificDate = settings.value("kmmofx-specificDate");
+ if (!specificDate.isEmpty())
+ m_specificDate->setDate(QDate::fromString(specificDate));
+ else
+ m_specificDate->setDate(QDate::currentDate());
+ m_specificDate->setMaxValue(QDate::currentDate());
+ m_payeeidRB->setChecked(settings.value("kmmofx-preferPayeeid").isEmpty() || settings.value("kmmofx-preferPayeeid").toInt() != 0);
+ m_nameRB->setChecked(!settings.value("kmmofx-preferName").isEmpty() && settings.value("kmmofx-preferName").toInt() != 0);
+}
+
+KOnlineBankingStatus::~KOnlineBankingStatus()
+{
+ delete m_appId;
+}
+
+const QString& KOnlineBankingStatus::appId(void) const
+{
+ if(m_appId)
+ return m_appId->appId();
+ return QString::null;
+}
+
+QString KOnlineBankingStatus::headerVersion(void) const
+{
+ if(m_headerVersion)
+ return m_headerVersion->headerVersion();
+ return QString::null;
+}
+
+#include "konlinebankingstatus.moc"
+
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h
new file mode 100644
index 0000000..bbd62ea
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ konlinebankingstatus.h
+ -------------------
+ begin : Wed Apr 16 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KONLINEBANKINGSTATUS_H
+#define KONLINEBANKINGSTATUS_H
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingstatusdecl.h"
+class MyMoneyAccount;
+class OfxAppVersion;
+class OfxHeaderVersion;
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KOnlineBankingStatus : public KOnlineBankingStatusDecl
+{
+ Q_OBJECT
+public:
+ KOnlineBankingStatus(const MyMoneyAccount& acc, QWidget *parent=0, const char *name=0);
+ ~KOnlineBankingStatus();
+ const QString& appId(void) const;
+ QString headerVersion(void) const;
+private:
+ OfxAppVersion* m_appId;
+ OfxHeaderVersion* m_headerVersion;
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui
new file mode 100644
index 0000000..f76f9e4
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui
@@ -0,0 +1,483 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KOnlineBankingStatusDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KOnlineBankingStatusDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>568</width>
+ <height>529</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Account Details</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_textBank</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>&amp;lt;Not configured&amp;gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>BANK/BROKER:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_textOnlineAccount</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>&amp;lt;Not configured&amp;gt;</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLed">
+ <property name="name">
+ <cstring>m_ledOnlineStatus</cstring>
+ </property>
+ <property name="state">
+ <enum>Off</enum>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_textOnlineStatus</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Unavailable</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>ACCOUNT:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>STATUS:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>OFX Details</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Header Version</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_applicationCombo</cstring>
+ </property>
+ </widget>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>150</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_headerVersionCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Identify as</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="midLineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string>Start date of import</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_todayRB</cstring>
+ </property>
+ <property name="text">
+ <string>To&amp;day minus</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_numdaysSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>180</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>days</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_lastUpdateRB</cstring>
+ </property>
+ <property name="text">
+ <string>Last &amp;update</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_lastUpdateTXT</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pickDateRB</cstring>
+ </property>
+ <property name="text">
+ <string>Pi&amp;ck date</string>
+ </property>
+ </widget>
+ <widget class="QDateEdit">
+ <property name="name">
+ <cstring>m_specificDate</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="order">
+ <enum>YMD</enum>
+ </property>
+ <property name="date">
+ <date>
+ <year>2000</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Name is derived from</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_payeeidRB</cstring>
+ </property>
+ <property name="text">
+ <string>P&amp;AYEEID</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_nameRB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;NAME</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>field if both are present in download</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>50</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_pickDateRB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_specificDate</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_todayRB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_numdaysSpin</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp
new file mode 100644
index 0000000..6e841bb
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp
@@ -0,0 +1,725 @@
+/***************************************************************************
+ mymoneyofxconnector.cpp
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// System Includes
+
+#include <libofx/libofx.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include "mymoneyofxconnector.h"
+
+OfxHeaderVersion::OfxHeaderVersion(KComboBox* combo, const QString& headerVersion) :
+ m_combo(combo)
+{
+ combo->clear();
+ combo->insertItem("102");
+ combo->insertItem("103");
+
+ if(!headerVersion.isEmpty()) {
+ combo->setCurrentItem(headerVersion);
+ } else {
+ combo->setCurrentItem("102");
+ }
+
+#if ! LIBOFX_IS_VERSION(0,9,0)
+ // This feature does not work with libOFX < 0.9 so
+ // we just make disable the button in this case
+ combo->setDisabled(true);
+#endif
+}
+
+QString OfxHeaderVersion::headerVersion(void) const
+{
+ return m_combo->currentText();
+}
+
+OfxAppVersion::OfxAppVersion(KComboBox* combo, const QString& appId) :
+ m_combo(combo)
+{
+// http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/
+// http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/
+
+ // Quicken
+ m_appMap[i18n("Quicken Windows 2003")] = "QWIN:1200";
+ m_appMap[i18n("Quicken Windows 2004")] = "QWIN:1300";
+ m_appMap[i18n("Quicken Windows 2005")] = "QWIN:1400";
+ m_appMap[i18n("Quicken Windows 2006")] = "QWIN:1500";
+ m_appMap[i18n("Quicken Windows 2007")] = "QWIN:1600";
+ m_appMap[i18n("Quicken Windows 2008")] = "QWIN:1700";
+
+ // MS-Money
+ m_appMap[i18n("MS-Money 2003")] = "Money:1100";
+ m_appMap[i18n("MS-Money 2004")] = "Money:1200";
+ m_appMap[i18n("MS-Money 2005")] = "Money:1400";
+ m_appMap[i18n("MS-Money 2006")] = "Money:1500";
+ m_appMap[i18n("MS-Money 2007")] = "Money:1600";
+ m_appMap[i18n("MS-Money Plus")] = "Money:1700";
+
+ // KMyMoney
+ m_appMap["KMyMoney"] = "KMyMoney:1000";
+
+ combo->clear();
+ combo->insertStringList(m_appMap.keys());
+
+ QMap<QString, QString>::const_iterator it_a;
+ for(it_a = m_appMap.begin(); it_a != m_appMap.end(); ++it_a) {
+ if(*it_a == appId)
+ break;
+ }
+
+ if(it_a != m_appMap.end()) {
+ combo->setCurrentItem(it_a.key());
+ } else {
+ combo->setCurrentItem(i18n("Quicken Windows 2008"));
+ }
+
+#if ! LIBOFX_IS_VERSION(0,9,0)
+ // This feature does not work with libOFX < 0.9 so
+ // we just make disable the button in this case
+ combo->setDisabled(true);
+#endif
+}
+
+const QString& OfxAppVersion::appId(void) const
+{
+ static QString defaultAppId("QWIN:1700");
+
+ QString app = m_combo->currentText();
+ if(m_appMap[app] != defaultAppId)
+ return m_appMap[app];
+ return QString::null;
+}
+
+MyMoneyOfxConnector::MyMoneyOfxConnector(const MyMoneyAccount& _account):
+ m_account(_account)
+{
+ m_fiSettings = m_account.onlineBankingSettings();
+}
+
+QString MyMoneyOfxConnector::iban(void) const { return m_fiSettings.value("bankid"); }
+QString MyMoneyOfxConnector::fiorg(void) const { return m_fiSettings.value("org"); }
+QString MyMoneyOfxConnector::fiid(void) const { return m_fiSettings.value("fid"); }
+QString MyMoneyOfxConnector::username(void) const { return m_fiSettings.value("username"); }
+QString MyMoneyOfxConnector::password(void) const { return m_fiSettings.value("password"); }
+QString MyMoneyOfxConnector::accountnum(void) const { return m_fiSettings.value("accountid"); }
+QString MyMoneyOfxConnector::url(void) const { return m_fiSettings.value("url"); }
+
+QDate MyMoneyOfxConnector::statementStartDate(void) const {
+ if ((m_fiSettings.value("kmmofx-todayMinus").toInt() != 0) && !m_fiSettings.value("kmmofx-numRequestDays").isEmpty())
+ {
+ return QDate::currentDate().addDays(-m_fiSettings.value("kmmofx-numRequestDays").toInt());
+ }
+ else if ((m_fiSettings.value("kmmofx-lastUpdate").toInt() != 0) && !m_account.value("lastImportedTransactionDate").isEmpty())
+ {
+ return QDate::fromString(m_account.value("lastImportedTransactionDate"), Qt::ISODate);
+ }
+ else if ((m_fiSettings.value("kmmofx-pickDate").toInt() != 0) && !m_fiSettings.value("kmmofx-specificDate").isEmpty())
+ {
+ return QDate::fromString(m_fiSettings.value("kmmofx-specificDate"));
+ }
+ return QDate::currentDate().addMonths(-2);
+}
+
+#if LIBOFX_IS_VERSION(0,9,0)
+OfxAccountData::AccountType MyMoneyOfxConnector::accounttype(void) const
+{
+ OfxAccountData::AccountType result = OfxAccountData::OFX_CHECKING;
+
+ QString type = m_account.onlineBankingSettings()["type"];
+ if(type == "CHECKING")
+ result = OfxAccountData::OFX_CHECKING;
+ else if(type == "SAVINGS")
+ result = OfxAccountData::OFX_SAVINGS;
+ else if(type == "MONEY MARKET")
+ result = OfxAccountData::OFX_MONEYMRKT;
+ else if(type == "CREDIT LINE")
+ result = OfxAccountData::OFX_CREDITLINE;
+ else if(type == "CMA")
+ result = OfxAccountData::OFX_CMA;
+ else if(type == "CREDIT CARD")
+ result = OfxAccountData::OFX_CREDITCARD;
+ else if(type == "INVESTMENT")
+ result = OfxAccountData::OFX_INVESTMENT;
+ else {
+ switch( m_account.accountType()) {
+ case MyMoneyAccount::Investment:
+ result = OfxAccountData::OFX_INVESTMENT;
+ break;
+ case MyMoneyAccount::CreditCard:
+ result = OfxAccountData::OFX_CREDITCARD;
+ break;
+ case MyMoneyAccount::Savings:
+ result = OfxAccountData::OFX_SAVINGS;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // This is a bit of a personalized hack. Sometimes we may want to override the
+ // ofx type for an account. For now, I will stash it in the notes!
+
+ QRegExp rexp("OFXTYPE:([A-Z]*)");
+ if ( rexp.search(m_account.description()) != -1 )
+ {
+ QString override = rexp.cap(1);
+ kdDebug(2) << "MyMoneyOfxConnector::accounttype() overriding to " << result << endl;
+
+ if ( override == "BANK" )
+ result = OfxAccountData::OFX_CHECKING;
+ else if ( override == "CC" )
+ result = OfxAccountData::OFX_CREDITCARD;
+ else if ( override == "INV" )
+ result = OfxAccountData::OFX_INVESTMENT;
+ else if ( override == "MONEYMARKET")
+ result = OfxAccountData::OFX_MONEYMRKT;
+ }
+
+ return result;
+}
+#else
+AccountType MyMoneyOfxConnector::accounttype(void) const
+{
+ AccountType result = OFX_BANK_ACCOUNT;
+
+ switch( m_account.accountType() )
+ {
+ case MyMoneyAccount::Investment:
+ result = OFX_INVEST_ACCOUNT;
+ break;
+ case MyMoneyAccount::CreditCard:
+ result = OFX_CREDITCARD_ACCOUNT;
+ break;
+ default:
+ break;
+ }
+
+ // This is a bit of a personalized hack. Sometimes we may want to override the
+ // ofx type for an account. For now, I will stash it in the notes!
+
+ QRegExp rexp("OFXTYPE:([A-Z]*)");
+ if ( rexp.search(m_account.description()) != -1 )
+ {
+ QString override = rexp.cap(1);
+ kdDebug(2) << "MyMoneyOfxConnector::accounttype() overriding to " << result << endl;
+
+ if ( override == "BANK" )
+ result = OFX_BANK_ACCOUNT;
+ else if ( override == "CC" )
+ result = OFX_CREDITCARD_ACCOUNT;
+ else if ( override == "INV" )
+ result = OFX_INVEST_ACCOUNT;
+#if 0 // money market is not supported by 0.8.x
+ else if ( override == "MONEYMARKET")
+ result = OFX_MONEYMRKT;
+#endif
+ }
+
+ return result;
+}
+#endif
+
+void MyMoneyOfxConnector::initRequest(OfxFiLogin* fi) const
+{
+ memset(fi,0,sizeof(OfxFiLogin));
+ strncpy(fi->fid, fiid().latin1(), OFX_FID_LENGTH-1);
+ strncpy(fi->org, fiorg().latin1(), OFX_ORG_LENGTH-1);
+ strncpy(fi->userid, username().latin1(), OFX_USERID_LENGTH-1);
+ strncpy(fi->userpass, password().latin1(), OFX_USERPASS_LENGTH-1);
+
+#if LIBOFX_IS_VERSION(0,9,0)
+ // If we don't know better, we pretend to be Quicken 2008
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/
+ QString appId = m_account.onlineBankingSettings().value("appId");
+ QRegExp exp("(.*):(.*)");
+ if(exp.search(appId) != -1) {
+ strncpy(fi->appid, exp.cap(1).latin1(), OFX_APPID_LENGTH-1);
+ strncpy(fi->appver, exp.cap(2).latin1(), OFX_APPVER_LENGTH-1);
+ } else {
+ strncpy(fi->appid, "QWIN", OFX_APPID_LENGTH-1);
+ strncpy(fi->appver, "1700", OFX_APPVER_LENGTH-1);
+ }
+
+ QString headerVersion = m_account.onlineBankingSettings().value("kmmofx-headerVersion");
+ if(!headerVersion.isEmpty()) {
+ strncpy(fi->header_version, headerVersion.latin1(), OFX_HEADERVERSION_LENGTH-1);
+ }
+#endif
+}
+
+const QByteArray MyMoneyOfxConnector::statementRequest(void) const
+{
+ OfxFiLogin fi;
+ initRequest(&fi);
+
+#if LIBOFX_IS_VERSION(0,9,0)
+ OfxAccountData account;
+ memset(&account,0,sizeof(OfxAccountData));
+
+ if(iban().latin1() != 0) {
+ strncpy(account.bank_id,iban().latin1(),OFX_BANKID_LENGTH-1);
+ strncpy(account.broker_id,iban().latin1(),OFX_BROKERID_LENGTH-1);
+ }
+ strncpy(account.account_number,accountnum().latin1(),OFX_ACCTID_LENGTH-1);
+ account.account_type = accounttype();
+#else
+ OfxAccountInfo account;
+ memset(&account,0,sizeof(OfxAccountInfo));
+
+ if(iban().latin1() != 0) {
+ strncpy(account.bankid,iban().latin1(),OFX_BANKID_LENGTH-1);
+ strncpy(account.brokerid,iban().latin1(),OFX_BROKERID_LENGTH-1);
+ }
+ strncpy(account.accountid,accountnum().latin1(),OFX_ACCOUNT_ID_LENGTH-1);
+ account.type = accounttype();
+#endif
+
+ char* szrequest = libofx_request_statement( &fi, &account, QDateTime(statementStartDate()).toTime_t() );
+ QString request = szrequest;
+ // remove the trailing zero
+ QByteArray result = request.utf8();
+ result.truncate(result.size()-1);
+ free(szrequest);
+
+ QString msg(result);
+ return result;
+}
+
+#if 0
+// this code is not used anymore. The logic is now
+// contained in KOnlineBankingSetupWizard::finishLoginPage(void)
+const QByteArray MyMoneyOfxConnector::accountInfoRequest(void) const
+{
+ OfxFiLogin fi;
+ initRequest(&fi);
+
+ char* szrequest = libofx_request_accountinfo( &fi );
+ QString request = szrequest;
+ // remove the trailing zero
+ QByteArray result = request.utf8();
+ result.truncate(result.size()-1);
+ free(szrequest);
+
+ return result;
+}
+#endif
+
+#if 0
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::message(const QString& _msgType, const QString& _trnType, const Tag& _request)
+{
+ return Tag(_msgType+"MSGSRQV1")
+ .subtag(Tag(_trnType+"TRNRQ")
+ .element("TRNUID",uuid())
+ .element("CLTCOOKIE","1")
+ .subtag(_request));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::investmentRequest(void) const
+{
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ return message("INVSTMT","INVSTMT",Tag("INVSTMTRQ")
+ .subtag(Tag("INVACCTFROM").element("BROKERID", fiorg()).element("ACCTID", accountnum()))
+ .subtag(Tag("INCTRAN").element("DTSTART",dtstart_string).element("INCLUDE","Y"))
+ .element("INCOO","Y")
+ .subtag(Tag("INCPOS").element("DTASOF", dtnow_string).element("INCLUDE","Y"))
+ .element("INCBAL","Y"));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::bankStatementRequest(const QDate& _dtstart) const
+{
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ return message("BANK","STMT",Tag("STMTRQ")
+ .subtag(Tag("BANKACCTFROM").element("BANKID", iban()).element("ACCTID", accountnum()).element("ACCTTYPE", "CHECKING"))
+ .subtag(Tag("INCTRAN").element("DTSTART",dtstart_string).element("INCLUDE","Y")));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::creditCardRequest(const QDate& _dtstart) const
+{
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ return message("CREDITCARD","CCSTMT",Tag("CCSTMTRQ")
+ .subtag(Tag("CCACCTFROM").element("ACCTID",accountnum()))
+ .subtag(Tag("INCTRAN").element("DTSTART",dtstart_string).element("INCLUDE","Y")));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::signOn(void) const
+{
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ Tag fi("FI");
+ fi.element("ORG",fiorg());
+ if ( !fiid().isEmpty() )
+ fi.element("FID",fiid());
+
+ return Tag("SIGNONMSGSRQV1")
+ .subtag(Tag("SONRQ")
+ .element("DTCLIENT",dtnow_string)
+ .element("USERID",username())
+ .element("USERPASS",password())
+ .element("LANGUAGE","ENG")
+ .subtag(fi)
+ .element("APPID","QWIN")
+ .element("APPVER","1100"));
+}
+
+QString MyMoneyOfxConnector::header(void)
+{
+ return QString("OFXHEADER:100\r\n"
+ "DATA:OFXSGML\r\n"
+ "VERSION:102\r\n"
+ "SECURITY:NONE\r\n"
+ "ENCODING:USASCII\r\n"
+ "CHARSET:1252\r\n"
+ "COMPRESSION:NONE\r\n"
+ "OLDFILEUID:NONE\r\n"
+ "NEWFILEUID:%1\r\n"
+ "\r\n").arg(uuid());
+}
+
+QString MyMoneyOfxConnector::uuid(void)
+{
+ static int id = 1;
+ return QDateTime::currentDateTime().toString("yyyyMMdd-hhmmsszzz-") + QString::number(id++);
+}
+
+//
+// Methods to provide RESPONSES to OFX requests. This has no real use in
+// KMyMoney, but it's included for the purposes of unit testing. This way, I
+// can create a MyMoneyAccount, write it to an OFX file, import that OFX file,
+// and check that everything made it through the importer.
+//
+// It's also a far-off dream to write an OFX server using KMyMoney as a
+// backend. It really should not be that hard, and it would fill a void in
+// the open source software community.
+//
+
+const QByteArray MyMoneyOfxConnector::statementResponse(const QDate& _dtstart) const
+{
+ QString request;
+
+ if ( accounttype()=="CC" )
+ request = header() + Tag("OFX").subtag(signOnResponse()).subtag(creditCardStatementResponse(_dtstart));
+ else if ( accounttype()=="INV" )
+ request = header() + Tag("OFX").subtag(signOnResponse()).data(investmentStatementResponse(_dtstart));
+ else
+ request = header() + Tag("OFX").subtag(signOnResponse()).subtag(bankStatementResponse(_dtstart));
+
+ // remove the trailing zero
+ QByteArray result = request.utf8();
+ result.truncate(result.size()-1);
+
+ return result;
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::signOnResponse(void) const
+{
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ Tag sonrs("SONRS");
+ sonrs
+ .subtag(Tag("STATUS")
+ .element("CODE","0")
+ .element("SEVERITY","INFO")
+ .element("MESSAGE","The operation succeeded.")
+ )
+ .element("DTSERVER",dtnow_string)
+ .element("LANGUAGE","ENG");
+
+ Tag fi("FI");
+ if ( !fiorg().isEmpty() )
+ fi.element("ORG",fiorg());
+ if ( !fiid().isEmpty() )
+ fi.element("FID",fiid());
+
+ if ( !fi.isEmpty() )
+ sonrs.subtag(fi);
+
+ return Tag("SIGNONMSGSRSV1").subtag(sonrs);
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::messageResponse(const QString& _msgType, const QString& _trnType, const Tag& _response)
+{
+ return Tag(_msgType+"MSGSRSV1")
+ .subtag(Tag(_trnType+"TRNRS")
+ .element("TRNUID",uuid())
+ .subtag(Tag("STATUS").element("CODE","0").element("SEVERITY","INFO"))
+ .element("CLTCOOKIE","1")
+ .subtag(_response));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::bankStatementResponse(const QDate& _dtstart) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ QString transactionlist;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(_dtstart,QDate::currentDate());
+ filter.addAccount(m_account.id());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ transactionlist += transaction( *it_transaction );
+ ++it_transaction;
+ }
+
+ return messageResponse("BANK","STMT",Tag("STMTRS")
+ .element("CURDEF","USD")
+ .subtag(Tag("BANKACCTFROM").element("BANKID", iban()).element("ACCTID", accountnum()).element("ACCTTYPE", "CHECKING"))
+ .subtag(Tag("BANKTRANLIST").element("DTSTART",dtstart_string).element("DTEND",dtnow_string).data(transactionlist))
+ .subtag(Tag("LEDGERBAL").element("BALAMT",file->balance(m_account.id()).formatMoney(QString(),2)).element("DTASOF",dtnow_string )));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::creditCardStatementResponse(const QDate& _dtstart) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ QString transactionlist;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(_dtstart,QDate::currentDate());
+ filter.addAccount(m_account.id());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ transactionlist += transaction( *it_transaction );
+ ++it_transaction;
+ }
+
+ return messageResponse("CREDITCARD","CCSTMT",Tag("CCSTMTRS")
+ .element("CURDEF","USD")
+ .subtag(Tag("CCACCTFROM").element("ACCTID", accountnum()))
+ .subtag(Tag("BANKTRANLIST").element("DTSTART",dtstart_string).element("DTEND",dtnow_string).data(transactionlist))
+ .subtag(Tag("LEDGERBAL").element("BALAMT",file->balance(m_account.id()).formatMoney(QString(),2)).element("DTASOF",dtnow_string )));
+}
+
+QString MyMoneyOfxConnector::investmentStatementResponse(const QDate& _dtstart) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ QString transactionlist;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(_dtstart,QDate::currentDate());
+ filter.addAccount(m_account.id());
+ filter.addAccount(m_account.accountList());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ transactionlist += investmentTransaction( *it_transaction );
+ ++it_transaction;
+ }
+
+ Tag securitylist("SECLIST");
+ QCStringList accountids = m_account.accountList();
+ QCStringList::const_iterator it_accountid = accountids.begin();
+ while ( it_accountid != accountids.end() )
+ {
+ MyMoneySecurity equity = file->security(file->account(*it_accountid).currencyId());
+
+ securitylist.subtag(Tag("STOCKINFO")
+ .subtag(Tag("SECINFO")
+ .subtag(Tag("SECID")
+ .element("UNIQUEID",equity.id())
+ .element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("SECNAME",equity.name())
+ .element("TICKER",equity.tradingSymbol())
+ .element("FIID",equity.id())));
+
+ ++it_accountid;
+ }
+
+ return messageResponse("INVSTMT","INVSTMT",Tag("INVSTMTRS")
+ .element("DTASOF", dtstart_string)
+ .element("CURDEF","USD")
+ .subtag(Tag("INVACCTFROM").element("BROKERID", fiorg()).element("ACCTID", accountnum()))
+ .subtag(Tag("INVTRANLIST").element("DTSTART",dtstart_string).element("DTEND",dtnow_string).data(transactionlist))
+ )
+ + Tag("SECLISTMSGSRSV1").subtag(securitylist);
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::transaction(const MyMoneyTransaction& _t) const
+{
+ // This method creates a transaction tag using ONLY the elements that importer uses
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Use this version for bank/cc transactions
+ MyMoneySplit s = _t.splitByAccount( m_account.id(), true );
+
+ //TODO (Ace) Write "investmentTransaction()"...
+ //Use this version for inv transactions
+ //MyMoneySplit s = _t.splitByAccount( m_account.accountList(), true );
+
+ Tag result ("STMTTRN");
+
+ result
+ // This is a temporary hack. I don't use the trntype field in importing at all,
+ // but libofx requires it to be there in order to import the file.
+ .element("TRNTYPE","DEBIT")
+ .element("DTPOSTED",_t.postDate().toString(Qt::ISODate).remove(QRegExp("[^0-9]")))
+ .element("TRNAMT",s.value().formatMoney(QString(),2));
+
+ if ( ! _t.bankID().isEmpty() )
+ result.element("FITID",_t.bankID());
+ else
+ result.element("FITID",_t.id());
+
+ if ( ! s.number().isEmpty() )
+ result.element("CHECKNUM",s.number());
+
+ if ( ! s.payeeId().isEmpty() )
+ result.element("NAME",file->payee(s.payeeId()).name());
+
+ if ( ! _t.memo().isEmpty() )
+ result.element("MEMO",_t.memo());
+
+ return result;
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::investmentTransaction(const MyMoneyTransaction& _t) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Use this version for inv transactions
+ MyMoneySplit s = _t.splitByAccount( m_account.accountList(), true );
+
+ QCString stockid = file->account(s.accountId()).currencyId();
+
+ Tag invtran("INVTRAN");
+ invtran.element("FITID",_t.id()).element("DTTRADE",_t.postDate().toString(Qt::ISODate).remove(QRegExp("[^0-9]")));
+ if ( !_t.memo().isEmpty() )
+ invtran.element("MEMO",_t.memo());
+
+ if ( s.action() == MyMoneySplit::ActionBuyShares )
+ {
+ if ( s.shares().isNegative() )
+ {
+ return Tag("SELLSTOCK")
+ .subtag(Tag("INVSELL")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("UNITS",QString(((s.shares())).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("UNITPRICE",QString((s.value()/s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.]")))
+ .element("TOTAL",QString((-s.value()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("SUBACCTFUND","CASH"))
+ .element("SELLTYPE","SELL");
+ }
+ else
+ {
+ return Tag("BUYSTOCK")
+ .subtag(Tag("INVBUY")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("UNITS",QString((s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("UNITPRICE",QString((s.value()/s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.]")))
+ .element("TOTAL",QString((-(s.value())).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("SUBACCTFUND","CASH"))
+ .element("BUYTYPE","BUY");
+ }
+ }
+ else if ( s.action() == MyMoneySplit::ActionReinvestDividend )
+ {
+ // Should the TOTAL tag really be negative for a REINVEST? That's very strange, but
+ // it's what they look like coming from my bank, and I can't find any information to refute it.
+
+ return Tag("REINVEST")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("INCOMETYPE","DIV")
+ .element("TOTAL",QString((-s.value()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("UNITS",QString((s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("UNITPRICE",QString((s.value()/s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.]")));
+ }
+ else if ( s.action() == MyMoneySplit::ActionDividend )
+ {
+ // find the split with the category, which has the actual amount of the dividend
+ QValueList<MyMoneySplit> splits = _t.splits();
+ QValueList<MyMoneySplit>::const_iterator it_split = splits.begin();
+ bool found = false;
+ while( it_split != splits.end() )
+ {
+ QCString accid = (*it_split).accountId();
+ MyMoneyAccount acc = file->account(accid);
+ if ( acc.accountType() == MyMoneyAccount::Income || acc.accountType() == MyMoneyAccount::Expense )
+ {
+ found = true;
+ break;
+ }
+ ++it_split;
+ }
+
+ if ( found )
+ return Tag("INCOME")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("INCOMETYPE","DIV")
+ .element("TOTAL",QString((-(*it_split).value()).formatMoney(QString(),2)).remove(QRegExp("[^0-9\\.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("SUBACCTFUND","CASH");
+ else
+ return Tag("ERROR").element("DETAILS","Unable to determine the amount of this income transaction.");
+ }
+
+ //FIXME: Do something useful with these errors
+ return Tag("ERROR").element("DETAILS","This transaction contains an unsupported action type");
+}
+#endif
diff --git a/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h
new file mode 100644
index 0000000..1091b15
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ mymoneyofxconnector.cpp
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYOFXCONNECTOR_H
+#define MYMONEYOFXCONNECTOR_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+#include <libofx/libofx.h>
+
+// if OFX has a major version number defined, we'll take it
+// if not, we assume 0.8.3. 0.8.3 was the last version w/o version number info
+#ifdef LIBOFX_MAJOR_VERSION
+ #define LIBOFX_VERSION KDE_MAKE_VERSION(LIBOFX_MAJOR_VERSION, LIBOFX_MINOR_VERSION, LIBOFX_MICRO_VERSION)
+#else
+ #define LIBOFX_VERSION KDE_MAKE_VERSION(0,8,3)
+#endif
+#define LIBOFX_IS_VERSION(a,b,c) (LIBOFX_VERSION >= KDE_MAKE_VERSION(a,b,c))
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QDate;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+class KComboBox;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+
+class MyMoneyAccount;
+class MyMoneyInstitution;
+class MyMoneyTransaction;
+
+/**
+ * @author Thomas Baumgart
+ */
+class OfxAppVersion
+{
+public:
+ OfxAppVersion(KComboBox* combo, const QString& appId);
+ /**
+ * This method returns the currently selected application id
+ * as a colon separated value consisting of the application
+ * and version (eg. "QWIN:1700"). If current value is the
+ * default, an empty string is returned.
+ */
+ const QString& appId(void) const;
+
+private:
+ QMap<QString, QString> m_appMap;
+ KComboBox* m_combo;
+};
+
+/**
+ * @author Thomas Baumgart
+ */
+class OfxHeaderVersion
+{
+public:
+ OfxHeaderVersion(KComboBox* combo, const QString& headerVersion);
+ QString headerVersion(void) const;
+
+private:
+ KComboBox* m_combo;
+};
+
+/**
+@author ace jones
+*/
+class MyMoneyOfxConnector
+{
+public:
+ MyMoneyOfxConnector(const MyMoneyAccount& _account);
+ QString url(void) const;
+
+ /**
+ * Constructs the request for a statement. The first date
+ * for which transactions will be requested is determined
+ * by statementStartDate()
+ */
+ const QByteArray statementRequest(void) const;
+ const QByteArray statementResponse(const QDate& _dtstart) const;
+
+private:
+ void initRequest(OfxFiLogin* fi) const;
+ QDate statementStartDate(void) const;
+ QString iban(void) const;
+ QString fiorg(void) const;
+ QString fiid(void) const;
+ QString username(void) const;
+ QString password(void) const;
+ QString accountnum(void) const;
+#if LIBOFX_IS_VERSION(0,9,0)
+ OfxAccountData::AccountType accounttype(void) const;
+#else
+ AccountType accounttype(void) const;
+#endif
+
+private:
+ const MyMoneyAccount& m_account;
+ MyMoneyKeyValueContainer m_fiSettings;
+};
+
+#endif // OFXCONNECTOR_H
diff --git a/kmymoney2/plugins/ofximport/kmm_ofximport.desktop b/kmymoney2/plugins/ofximport/kmm_ofximport.desktop
new file mode 100644
index 0000000..32ff003
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/kmm_ofximport.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Name=KMyMoney OFX
+Comment=Add OFX importing to KMyMoney
+ServiceTypes=KMyMoneyPlugin
+Type=Service
+Icon=connect_creating
+X-KDE-Library=kmm_ofximport
+X-KDE-PluginInfo-Name=KMyMoney OFX
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
+X-KDE-PluginInfo-Author=Ace Jones,Thomas Baumgart
+X-KDE-PluginInfo-Email=acejones@users.sourceforge.net,ipwizard@users.sourceforge.net
diff --git a/kmymoney2/plugins/ofximport/kmm_ofximport.rc b/kmymoney2/plugins/ofximport/kmm_ofximport.rc
new file mode 100644
index 0000000..7254470
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/kmm_ofximport.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kmymoneyplugin-ofximporter" version="2">
+ <MenuBar>
+ <Menu name="file">
+ <Menu name="import" append="import_merge">
+ <Action name="file_import_ofx" />
+ </Menu>
+ </Menu>
+ </MenuBar>
+</kpartgui>
diff --git a/kmymoney2/plugins/ofximport/ofximporterplugin.cpp b/kmymoney2/plugins/ofximport/ofximporterplugin.cpp
new file mode 100644
index 0000000..21a6466
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofximporterplugin.cpp
@@ -0,0 +1,688 @@
+/***************************************************************************
+ ofxiimporterplugin.cpp
+ -------------------
+ begin : Sat Jan 01 2005
+ copyright : (C) 2005 by Ace Jones
+ email : Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qdatetimeedit.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kfile.h>
+#include <kurl.h>
+#include <kaction.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ofximporterplugin.h"
+#include "konlinebankingstatus.h"
+#include "konlinebankingsetupwizard.h"
+#include "kofxdirectconnectdlg.h"
+
+K_EXPORT_COMPONENT_FACTORY( kmm_ofximport,
+ KGenericFactory<OfxImporterPlugin>( "kmm_ofximport" ) )
+
+OfxImporterPlugin::OfxImporterPlugin(QObject *parent, const char *name, const QStringList&) :
+ KMyMoneyPlugin::Plugin( parent, name ),
+ KMyMoneyPlugin::ImporterPlugin(),
+ m_valid( false )
+{
+ setInstance(KGenericFactory<OfxImporterPlugin>::instance());
+ setXMLFile("kmm_ofximport.rc");
+ createActions();
+}
+
+OfxImporterPlugin::~OfxImporterPlugin()
+{
+}
+
+void OfxImporterPlugin::createActions(void)
+{
+ new KAction(i18n("OFX..."), "", 0, this, SLOT(slotImportFile()), actionCollection(), "file_import_ofx");
+}
+
+void OfxImporterPlugin::slotImportFile(void)
+{
+ KURL url = importInterface()->selectFile(i18n("OFX import file selection"),
+ "",
+ "*.ofx *.qfx *.ofc|OFX files (*.ofx, *.qfx, *.ofc)\n*.*|All files (*.*)",
+ static_cast<KFile::Mode>(KFile::File | KFile::ExistingOnly));
+ if(url.isValid()) {
+ if ( isMyFormat(url.path()) ) {
+ slotImportFile(url.path());
+ } else {
+ KMessageBox::error( 0, i18n("Unable to import %1 using the OFX importer plugin. This file is not the correct format.").arg(url.prettyURL(0, KURL::StripFileProtocol)), i18n("Incorrect format"));
+ }
+
+ }
+}
+
+QString OfxImporterPlugin::formatName(void) const
+{
+ return "OFX";
+}
+
+QString OfxImporterPlugin::formatFilenameFilter(void) const
+{
+ return "*.ofx *.qfx *.ofc";
+}
+
+
+bool OfxImporterPlugin::isMyFormat( const QString& filename ) const
+{
+ // filename is considered an Ofx file if it contains
+ // the tag "<OFX>" or "<OFC>" in the first 20 lines
+ // which contain some data.
+ bool result = false;
+
+ QFile f( filename );
+ if ( f.open( IO_ReadOnly ) )
+ {
+ QTextStream ts( &f );
+
+ int lineCount = 20;
+ while ( !ts.atEnd() && !result && lineCount != 0)
+ {
+ // get a line of data and remove all unnecessary whitepace chars
+ QString line = ts.readLine().simplifyWhiteSpace();
+ if ( line.contains("<OFX>",false)
+ || line.contains("<OFC>",false) )
+ result = true;
+ // count only lines that contains some non white space chars
+ if(!line.isEmpty())
+ lineCount--;
+ }
+ f.close();
+ }
+
+ return result;
+}
+
+bool OfxImporterPlugin::import( const QString& filename )
+{
+ m_fatalerror = i18n("Unable to parse file");
+ m_valid = false;
+ m_errors.clear();
+ m_warnings.clear();
+ m_infos.clear();
+
+ m_statementlist.clear();
+ m_securitylist.clear();
+
+ QCString filename_deep( filename.utf8() );
+
+ LibofxContextPtr ctx = libofx_get_new_context();
+ Q_CHECK_PTR(ctx);
+
+ ofx_set_transaction_cb(ctx, ofxTransactionCallback, this);
+ ofx_set_statement_cb(ctx, ofxStatementCallback, this);
+ ofx_set_account_cb(ctx, ofxAccountCallback, this);
+ ofx_set_security_cb(ctx, ofxSecurityCallback, this);
+ ofx_set_status_cb(ctx, ofxStatusCallback, this);
+ libofx_proc_file(ctx, filename_deep, AUTODETECT);
+ libofx_free_context(ctx);
+
+ if ( m_valid )
+ {
+ m_fatalerror = QString();
+ m_valid = storeStatements(m_statementlist);
+ }
+ return m_valid;
+}
+
+QString OfxImporterPlugin::lastError(void) const
+{
+ if(m_errors.count() == 0)
+ return m_fatalerror;
+ return m_errors.join("<p>");
+}
+
+/* __________________________________________________________________________
+ * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ *
+ * Static callbacks for LibOFX
+ *
+ * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+ */
+
+int OfxImporterPlugin::ofxTransactionCallback(struct OfxTransactionData data, void * pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ MyMoneyStatement& s = pofx->back();
+
+ MyMoneyStatement::Transaction t;
+
+ if(data.date_posted_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_posted, Qt::UTC);
+ t.m_datePosted = dt.date();
+ }
+ else if(data.date_initiated_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_initiated, Qt::UTC);
+ t.m_datePosted = dt.date();
+ }
+
+ if(data.amount_valid==true)
+ {
+ t.m_amount = MyMoneyMoney(data.amount, 1000);
+ // if this is an investment statement, reverse the sign. not sure
+ // why this is needed, so I suppose it's a bit of a hack for the moment.
+ if (data.invtransactiontype_valid==true)
+ t.m_amount = -t.m_amount;
+ }
+
+ if(data.check_number_valid==true)
+ {
+ t.m_strNumber = data.check_number;
+ }
+
+ if(data.fi_id_valid==true)
+ {
+ t.m_strBankID = QString("ID ") + data.fi_id;
+ }
+ else if(data.reference_number_valid==true)
+ {
+ t.m_strBankID = QString("REF ") + data.reference_number;
+ }
+ // Decide whether to import NAME or PAYEEID if both are present in the download
+ if (pofx->m_preferName) {
+ if(data.name_valid==true)
+ {
+ t.m_strPayee = data.name;
+ }
+ else if(data.payee_id_valid==true)
+ {
+ t.m_strPayee = data.payee_id;
+ }
+ }
+ else {
+ if(data.payee_id_valid==true)
+ {
+ t.m_strPayee = data.payee_id;
+ }
+ else if(data.name_valid==true)
+ {
+ t.m_strPayee = data.name;
+ }
+ }
+ if(data.memo_valid==true){
+ t.m_strMemo = data.memo;
+ }
+
+ // If the payee or memo fields are blank, set them to
+ // the other one which is NOT blank. (acejones)
+ if ( t.m_strPayee.isEmpty() )
+ {
+ // But we only create a payee for non-investment transactions (ipwizard)
+ if ( ! t.m_strMemo.isEmpty() && data.invtransactiontype_valid == false)
+ t.m_strPayee = t.m_strMemo;
+ }
+ else
+ {
+ if ( t.m_strMemo.isEmpty() )
+ t.m_strMemo = t.m_strPayee;
+ }
+
+ if(data.security_data_valid==true)
+ {
+ struct OfxSecurityData* secdata = data.security_data_ptr;
+
+ if(secdata->ticker_valid==true){
+ t.m_strSymbol = secdata->ticker;
+ }
+
+ if(secdata->secname_valid==true){
+ t.m_strSecurity = secdata->secname;
+ }
+ }
+
+ t.m_shares = MyMoneyMoney();
+ if(data.units_valid==true)
+ {
+ t.m_shares = MyMoneyMoney(data.units, 100000).reduce();
+ }
+
+ t.m_price = MyMoneyMoney();
+ if(data.unitprice_valid == true)
+ {
+ t.m_price = MyMoneyMoney(data.unitprice, 100000).reduce();
+ }
+
+ t.m_fees = MyMoneyMoney();
+ if(data.fees_valid==true)
+ {
+ t.m_fees += MyMoneyMoney(data.fees, 1000).reduce();
+ }
+
+ if(data.commission_valid==true)
+ {
+ t.m_fees += MyMoneyMoney(data.commission, 1000).reduce();
+ }
+
+ bool unhandledtype = false;
+ QString type;
+
+ if(data.invtransactiontype_valid==true)
+ {
+ switch (data.invtransactiontype)
+ {
+ case OFX_BUYDEBT:
+ case OFX_BUYMF:
+ case OFX_BUYOPT:
+ case OFX_BUYOTHER:
+ case OFX_BUYSTOCK:
+ t.m_eAction = MyMoneyStatement::Transaction::eaBuy;
+ break;
+ case OFX_REINVEST:
+ t.m_eAction = MyMoneyStatement::Transaction::eaReinvestDividend;
+ break;
+ case OFX_SELLDEBT:
+ case OFX_SELLMF:
+ case OFX_SELLOPT:
+ case OFX_SELLOTHER:
+ case OFX_SELLSTOCK:
+ t.m_eAction = MyMoneyStatement::Transaction::eaSell;
+ break;
+ case OFX_INCOME:
+ t.m_eAction = MyMoneyStatement::Transaction::eaCashDividend;
+ // NOTE: With CashDividend, the amount of the dividend should
+ // be in data.amount. Since I've never seen an OFX file with
+ // cash dividends, this is an assumption on my part. (acejones)
+ break;
+
+ //
+ // These types are all not handled. We will generate a warning for them.
+ //
+ case OFX_CLOSUREOPT:
+ unhandledtype = true;
+ type = "CLOSUREOPT (Close a position for an option)";
+ break;
+ case OFX_INVEXPENSE:
+ unhandledtype = true;
+ type = "INVEXPENSE (Misc investment expense that is associated with a specific security)";
+ break;
+ case OFX_JRNLFUND:
+ unhandledtype = true;
+ type = "JRNLFUND (Journaling cash holdings between subaccounts within the same investment account)";
+ break;
+ case OFX_MARGININTEREST:
+ unhandledtype = true;
+ type = "MARGININTEREST (Margin interest expense)";
+ break;
+ case OFX_RETOFCAP:
+ unhandledtype = true;
+ type = "RETOFCAP (Return of capital)";
+ break;
+ case OFX_SPLIT:
+ unhandledtype = true;
+ type = "SPLIT (Stock or mutial fund split)";
+ break;
+ case OFX_TRANSFER:
+ unhandledtype = true;
+ type = "TRANSFER (Transfer holdings in and out of the investment account)";
+ break;
+ default:
+ unhandledtype = true;
+ type = QString("UNKNOWN %1").arg(data.invtransactiontype);
+ break;
+ }
+ }
+ else
+ t.m_eAction = MyMoneyStatement::Transaction::eaNone;
+
+ // In the case of investment transactions, the 'total' is supposed to the total amount
+ // of the transaction. units * unitprice +/- commission. Easy, right? Sadly, it seems
+ // some ofx creators do not follow this in all circumstances. Therefore, we have to double-
+ // check the total here and adjust it if it's wrong.
+
+#if 0
+ // Even more sadly, this logic is BROKEN. It consistently results in bogus total
+ // values, because of rounding errors in the price. A more through solution would
+ // be to test if the comission alone is causing a discrepency, and adjust in that case.
+
+ if(data.invtransactiontype_valid==true && data.unitprice_valid)
+ {
+ double proper_total = t.m_dShares * data.unitprice + t.m_moneyFees;
+ if ( proper_total != t.m_moneyAmount )
+ {
+ pofx->addWarning(QString("Transaction %1 has an incorrect total of %2. Using calculated total of %3 instead.").arg(t.m_strBankID).arg(t.m_moneyAmount).arg(proper_total));
+ t.m_moneyAmount = proper_total;
+ }
+ }
+#endif
+
+ if ( unhandledtype )
+ pofx->addWarning(QString("Transaction %1 has an unsupported type (%2).").arg(t.m_strBankID,type));
+ else
+ s.m_listTransactions += t;
+
+// kdDebug(2) << __func__ << "return 0 " << endl;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxStatementCallback(struct OfxStatementData data, void* pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ MyMoneyStatement& s = pofx->back();
+
+ pofx->setValid();
+
+ if(data.currency_valid==true)
+ {
+ s.m_strCurrency = data.currency;
+ }
+ if(data.account_id_valid==true)
+ {
+ s.m_strAccountNumber = data.account_id;
+ }
+
+ if(data.date_start_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_start, Qt::UTC);
+ s.m_dateBegin = dt.date();
+ }
+
+ if(data.date_end_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_end, Qt::UTC);
+ s.m_dateEnd = dt.date();
+ }
+
+ if(data.ledger_balance_valid==true)
+ {
+ s.m_closingBalance = MyMoneyMoney(data.ledger_balance);
+ }
+
+// kdDebug(2) << __func__ << " return 0" << endl;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxAccountCallback(struct OfxAccountData data, void * pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ pofx->addnew();
+ MyMoneyStatement& s = pofx->back();
+
+ // Having any account at all makes an ofx statement valid
+ pofx->m_valid = true;
+
+ if(data.account_id_valid==true)
+ {
+ s.m_strAccountName = data.account_name;
+ s.m_strAccountNumber = data.account_id;
+ }
+ if(data.bank_id_valid == true)
+ {
+ s.m_strRoutingNumber = data.bank_id;
+ }
+ if(data.broker_id_valid == true)
+ {
+ s.m_strRoutingNumber = data.broker_id;
+ }
+ if(data.currency_valid==true)
+ {
+ s.m_strCurrency = data.currency;
+ }
+
+ if(data.account_type_valid==true)
+ {
+ switch(data.account_type)
+ {
+ case OfxAccountData::OFX_CHECKING : s.m_eType = MyMoneyStatement::etCheckings;
+ break;
+ case OfxAccountData::OFX_SAVINGS : s.m_eType = MyMoneyStatement::etSavings;
+ break;
+ case OfxAccountData::OFX_MONEYMRKT : s.m_eType = MyMoneyStatement::etInvestment;
+ break;
+ case OfxAccountData::OFX_CREDITLINE : s.m_eType = MyMoneyStatement::etCreditCard;
+ break;
+ case OfxAccountData::OFX_CMA : s.m_eType = MyMoneyStatement::etCreditCard;
+ break;
+ case OfxAccountData::OFX_CREDITCARD : s.m_eType = MyMoneyStatement::etCreditCard;
+ break;
+ case OfxAccountData::OFX_INVESTMENT : s.m_eType = MyMoneyStatement::etInvestment;
+ break;
+ }
+ }
+
+ // ask KMyMoney for an account id
+ s.m_accountId = pofx->account("kmmofx-acc-ref", QString("%1-%2").arg(s.m_strRoutingNumber, s.m_strAccountNumber)).id();
+
+ // copy over the securities
+ s.m_listSecurities = pofx->m_securitylist;
+
+// kdDebug(2) << __func__ << " return 0" << endl;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxSecurityCallback(struct OfxSecurityData data, void* pv)
+{
+ // kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ MyMoneyStatement::Security sec;
+
+ if(data.unique_id_valid==true){
+ sec.m_strId = data.unique_id;
+ }
+ if(data.secname_valid==true){
+ sec.m_strName = data.secname;
+ }
+ if(data.ticker_valid==true){
+ sec.m_strSymbol = data.ticker;
+ }
+
+ pofx->m_securitylist += sec;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxStatusCallback(struct OfxStatusData data, void * pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ QString message;
+
+ // if we got this far, we know we were able to parse the file.
+ // so if it fails after here it can only because there were no actual
+ // accounts in the file!
+ pofx->m_fatalerror = "No accounts found.";
+
+ if(data.ofx_element_name_valid==true)
+ message.prepend(QString("%1: ").arg(data.ofx_element_name));
+
+ if(data.code_valid==true)
+ message += QString("%1 (Code %2): %3").arg(data.name).arg(data.code).arg(data.description);
+
+ if(data.server_message_valid==true)
+ message += QString(" (%1)").arg(data.server_message);
+
+ if(data.severity_valid==true){
+ switch(data.severity){
+ case OfxStatusData::INFO:
+ pofx->addInfo( message );
+ break;
+ case OfxStatusData::ERROR:
+ pofx->addError( message );
+ break;
+ case OfxStatusData::WARN:
+ pofx->addWarning( message );
+ break;
+ default:
+ pofx->addWarning( message );
+ pofx->addWarning( "Previous message was an unknown type. 'WARNING' was assumed.");
+ break;
+ }
+ }
+
+// kdDebug(2) << __func__ << " return 0 " << endl;
+
+ return 0;
+}
+
+bool OfxImporterPlugin::importStatement(const MyMoneyStatement& s)
+{
+ qDebug("OfxImporterPlugin::importStatement start");
+ return statementInterface()->import(s);
+}
+
+const MyMoneyAccount& OfxImporterPlugin::account(const QString& key, const QString& value) const
+{
+ return statementInterface()->account(key, value);
+}
+
+void OfxImporterPlugin::protocols(QStringList& protocolList) const
+{
+ protocolList.clear();
+ protocolList << "OFX";
+}
+
+QWidget* OfxImporterPlugin::accountConfigTab(const MyMoneyAccount& acc, QString& name)
+{
+ name = i18n("Online settings");
+ m_statusDlg = new KOnlineBankingStatus(acc, 0, 0);
+ return m_statusDlg;
+}
+
+MyMoneyKeyValueContainer OfxImporterPlugin::onlineBankingSettings(const MyMoneyKeyValueContainer& current)
+{
+ MyMoneyKeyValueContainer kvp(current);
+ // keep the provider name in sync with the one found in kmm_ofximport.desktop
+ kvp["provider"] = "KMyMoney OFX";
+ if(m_statusDlg) {
+ kvp.deletePair("appId");
+ kvp.deletePair("kmmofx-headerVersion");
+ if(!m_statusDlg->appId().isEmpty())
+ kvp.setValue("appId", m_statusDlg->appId());
+ kvp.setValue("kmmofx-headerVersion", m_statusDlg->headerVersion());
+ kvp.setValue("kmmofx-numRequestDays", QString::number(m_statusDlg->m_numdaysSpin->value()));
+ kvp.setValue("kmmofx-todayMinus", QString::number(m_statusDlg->m_todayRB->isChecked()));
+ kvp.setValue("kmmofx-lastUpdate", QString::number(m_statusDlg->m_lastUpdateRB->isChecked()));
+ kvp.setValue("kmmofx-pickDate", QString::number(m_statusDlg->m_pickDateRB->isChecked()));
+ kvp.setValue("kmmofx-specificDate", m_statusDlg->m_specificDate->date().toString());
+ kvp.setValue("kmmofx-preferPayeeid", QString::number(m_statusDlg->m_payeeidRB->isChecked()));
+ kvp.setValue("kmmofx-preferName", QString::number(m_statusDlg->m_nameRB->isChecked()));
+ }
+ return kvp;
+}
+
+bool OfxImporterPlugin::mapAccount(const MyMoneyAccount& acc, MyMoneyKeyValueContainer& settings)
+{
+ Q_UNUSED(acc);
+
+ bool rc = false;
+ KOnlineBankingSetupWizard wiz(0, "onlinebankingsetup");
+ if(wiz.isInit()) {
+ if(wiz.exec() == QDialog::Accepted) {
+ rc = wiz.chosenSettings( settings );
+ }
+ }
+
+ return rc;
+}
+
+bool OfxImporterPlugin::updateAccount(const MyMoneyAccount& acc, bool moreAccounts)
+{
+ Q_UNUSED(moreAccounts);
+
+ try {
+ if(!acc.id().isEmpty()) {
+ // Save the value of preferName to be used by ofxTransactionCallback
+ m_preferName = acc.onlineBankingSettings().value("kmmofx-preferName").toInt() != 0;
+ KOfxDirectConnectDlg dlg(acc);
+
+ connect(&dlg, SIGNAL(statementReady(const QString&)),
+ this, SLOT(slotImportFile(const QString&)));
+
+ dlg.init();
+ dlg.exec();
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(0 ,i18n("Error connecting to bank: %1").arg(e->what()));
+ delete e;
+ }
+
+ return false;
+}
+
+void OfxImporterPlugin::slotImportFile(const QString& url)
+{
+
+ if(!import(url)) {
+ KMessageBox::error( 0, QString("<qt>%1</qt>").arg(i18n("Unable to import %1 using the OFX importer plugin. The plugin returned the following error:<p>%2").arg(url, lastError())), i18n("Importing error"));
+ }
+}
+
+bool OfxImporterPlugin::storeStatements(QValueList<MyMoneyStatement>& statements)
+{
+ bool hasstatements = (statements.count() > 0);
+ bool ok = true;
+ bool abort = false;
+
+ // FIXME Deal with warnings/errors coming back from plugins
+ /*if ( ofx.errors().count() )
+ {
+ if ( KMessageBox::warningContinueCancelList(this,i18n("The following errors were returned from your bank"),ofx.errors(),i18n("OFX Errors")) == KMessageBox::Cancel )
+ abort = true;
+ }
+
+ if ( ofx.warnings().count() )
+ {
+ if ( KMessageBox::warningContinueCancelList(this,i18n("The following warnings were returned from your bank"),ofx.warnings(),i18n("OFX Warnings"),KStdGuiItem::cont(),"ofxwarnings") == KMessageBox::Cancel )
+ abort = true;
+ }*/
+
+ qDebug("OfxImporterPlugin::storeStatements() with %d statements called", static_cast<int>(statements.count()));
+ QValueList<MyMoneyStatement>::const_iterator it_s = statements.begin();
+ while ( it_s != statements.end() && !abort ) {
+ ok = ok && importStatement((*it_s));
+ ++it_s;
+ }
+
+ if ( hasstatements && !ok ) {
+ KMessageBox::error( 0, i18n("Importing process terminated unexpectedly."), i18n("Failed to import all statements."));
+ }
+
+ return ( !hasstatements || ok );
+}
+
+#include "ofximporterplugin.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/ofximporterplugin.h b/kmymoney2/plugins/ofximport/ofximporterplugin.h
new file mode 100644
index 0000000..b665439
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofximporterplugin.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ ofxiimporterplugin.h
+ -------------------
+ begin : Sat Jan 01 2005
+ copyright : (C) 2005 by Ace Jones
+ email : Ace Jones <acejones@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef OFXIMPORTERPLUGIN_H
+#define OFXIMPORTERPLUGIN_H
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+#include <libofx/libofx.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../kmymoneyplugin.h"
+class KOnlineBankingStatus;
+
+/**
+@author Ace Jones
+*/
+class OfxImporterPlugin : public KMyMoneyPlugin::Plugin, public KMyMoneyPlugin::ImporterPlugin, public KMyMoneyPlugin::OnlinePlugin
+{
+Q_OBJECT
+public:
+ OfxImporterPlugin(QObject *parent = 0, const char *name = 0, const QStringList& = QStringList());
+
+ ~OfxImporterPlugin();
+
+ /**
+ * This method returns the english-language name of the format
+ * this plugin imports, e.g. "OFX"
+ *
+ * @return QString Name of the format
+ */
+ virtual QString formatName(void) const;
+
+ /**
+ * This method returns the filename filter suitable for passing to
+ * KFileDialog::setFilter(), e.g. "*.ofx *.qfx" which describes how
+ * files of this format are likely to be named in the file system
+ *
+ * @return QString Filename filter string
+ */
+ virtual QString formatFilenameFilter(void) const;
+
+ /**
+ * This method returns whether this plugin is able to import
+ * a particular file.
+ *
+ * @param filename Fully-qualified pathname to a file
+ *
+ * @return bool Whether the indicated file is importable by this plugin
+ */
+ virtual bool isMyFormat( const QString& filename ) const;
+
+ /**
+ * Import a file
+ *
+ * @param filename File to import
+ *
+ * @return bool Whether the import was successful.
+ */
+ virtual bool import( const QString& filename );
+
+ /**
+ * Returns the error result of the last import
+ *
+ * @return QString English-language name of the error encountered in the
+ * last import, or QString() if it was successful.
+ *
+ */
+ virtual QString lastError(void) const;
+
+ QWidget* accountConfigTab(const MyMoneyAccount& acc, QString& name);
+
+ MyMoneyKeyValueContainer onlineBankingSettings(const MyMoneyKeyValueContainer& current);
+
+ const MyMoneyAccount& account(const QString& key, const QString& value) const;
+
+ void protocols(QStringList& protocolList) const;
+
+ bool mapAccount(const MyMoneyAccount& acc, MyMoneyKeyValueContainer& settings);
+ bool updateAccount(const MyMoneyAccount& acc, bool moreAccounts);
+
+protected slots:
+ void slotImportFile(void);
+ void slotImportFile(const QString& url);
+
+protected:
+ void createActions(void);
+ void addnew(void) { m_statementlist.push_back(MyMoneyStatement()); }
+ MyMoneyStatement& back(void) { return m_statementlist.back(); }
+ bool isValid(void) const { return m_valid; }
+ void setValid(void) { m_valid = true; }
+ void addInfo(const QString& _msg ) { m_infos+=_msg; }
+ void addWarning(const QString& _msg ) { m_warnings+=_msg; }
+ void addError(const QString& _msg ) { m_errors+=_msg; }
+ const QStringList& infos(void) const { return m_infos; }
+ const QStringList& warnings(void) const { return m_warnings; }
+ const QStringList& errors(void) const { return m_errors; }
+ bool storeStatements(QValueList<MyMoneyStatement>& statements);
+ bool importStatement(const MyMoneyStatement& s);
+
+
+ static int ofxTransactionCallback( struct OfxTransactionData, void* );
+ static int ofxStatementCallback( struct OfxStatementData, void* );
+ static int ofxAccountCallback( struct OfxAccountData, void* );
+ static int ofxStatusCallback( struct OfxStatusData, void* );
+ static int ofxSecurityCallback( struct OfxSecurityData, void* );
+
+private:
+ bool m_valid;
+ bool m_preferName;
+ QValueList<MyMoneyStatement> m_statementlist;
+ QValueList<MyMoneyStatement::Security> m_securitylist;
+ QString m_fatalerror;
+ QStringList m_infos;
+ QStringList m_warnings;
+ QStringList m_errors;
+ KOnlineBankingStatus* m_statusDlg;
+};
+
+#endif
diff --git a/kmymoney2/plugins/ofximport/ofxpartner.cpp b/kmymoney2/plugins/ofximport/ofxpartner.cpp
new file mode 100644
index 0000000..d36fbb2
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofxpartner.cpp
@@ -0,0 +1,429 @@
+/***************************************************************************
+ ofxpartner.cpp
+ ----------
+ begin : Fri Jan 23 2009
+ copyright : (C) 2009 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+#include <qeventloop.h>
+#include <qfileinfo.h>
+#include <qvaluelist.h>
+#include <qapplication.h>
+#include <qdom.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+#include <kio/job.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ofxpartner.h"
+
+namespace OfxPartner
+{
+bool post(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename);
+bool get(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename);
+
+const QString kBankFilename = "ofx-bank-index.xml";
+const QString kCcFilename = "ofx-cc-index.xml";
+const QString kInvFilename = "ofx-inv-index.xml";
+
+#define VER "9"
+
+static QString directory;
+
+void setDirectory(const QString& dir)
+{
+ directory = dir;
+}
+
+bool needReload(const QFileInfo& i)
+{
+ return ((!i.isReadable())
+ || (i.lastModified().addDays(7) < QDateTime::currentDateTime())
+ || (i.size() < 1024));
+}
+
+void ValidateIndexCache(void)
+{
+ // TODO (Ace) Check whether these files exist and are recent enough before getting them again
+
+ struct stat filestats;
+ KURL fname;
+
+ QMap<QString, QString> attr;
+ attr["content-type"] = "application/x-www-form-urlencoded";
+ attr["accept"] = "*/*";
+
+ fname = directory + kBankFilename;
+ QFileInfo i(fname.path());
+ if(needReload(i))
+ post("T=1&S=*&R=1&O=0&TEST=0", attr, KURL("http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=" VER), fname);
+
+ fname = directory + kCcFilename;
+ i = QFileInfo(fname.path());
+ if(needReload(i))
+ post("T=2&S=*&R=1&O=0&TEST=0", attr, KURL("http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=" VER) ,fname);
+
+ fname = directory + kInvFilename;
+ i = QFileInfo(fname.path());
+ if(needReload(i))
+ post("T=3&S=*&R=1&O=0&TEST=0", attr, KURL("http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=" VER), fname);
+}
+
+static void ParseFile(QMap<QString, QString>& result, const QString& fileName, const QString& bankName)
+{
+ QFile f(fileName);
+ if(f.open(IO_ReadOnly)) {
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::Unicode);
+ QString msg;
+ int errl, errc;
+ QDomDocument doc;
+ if(doc.setContent(stream.read(), &msg, &errl, &errc)) {
+ QDomNodeList olist = doc.elementsByTagName("prov");
+ for(int i = 0; i < olist.count(); ++i) {
+ QDomNode onode = olist.item(i);
+ if(onode.isElement()) {
+ bool collectGuid = false;
+ QDomElement elo = onode.toElement();
+ QDomNodeList ilist = onode.childNodes();
+ for(int j = 0; j < ilist.count(); ++j) {
+ QDomNode inode = ilist.item(j);
+ QDomElement el = inode.toElement();
+ if(el.tagName() == "name") {
+ if(bankName.isEmpty())
+ result[el.text()] = QString();
+ else if(el.text() == bankName) {
+ collectGuid = true;
+ }
+ }
+ if(el.tagName() == "guid" && collectGuid) {
+ result[el.text()] = QString();
+ }
+ }
+ }
+ }
+ }
+ f.close();
+ }
+}
+
+QValueList<QString> BankNames(void)
+{
+ QMap<QString, QString> result;
+
+ // Make sure the index files are up to date
+ ValidateIndexCache();
+
+ ParseFile(result, directory + kBankFilename, QString());
+ ParseFile(result, directory + kCcFilename, QString());
+ ParseFile(result, directory + kInvFilename, QString());
+
+ // Add Innovision
+ result["Innovision"] = QString();
+
+ return result.keys();
+}
+
+QValueList<QString> FipidForBank(const QString& bank)
+{
+ QMap<QString, QString> result;
+
+ ParseFile(result, directory + kBankFilename, bank);
+ ParseFile(result, directory + kCcFilename, bank);
+ ParseFile(result, directory + kInvFilename, bank);
+
+ // the fipid for Innovision is 1.
+ if ( bank == "Innovision" )
+ result["1"] = QString();
+
+ return result.keys();
+}
+
+QString extractNodeText(QDomElement& node, const QString& name)
+{
+ QString res;
+ QRegExp exp("([^/]+)/?([^/].*)?");
+ if(exp.search(name) != -1) {
+ QDomNodeList olist = node.elementsByTagName(exp.cap(1));
+ if(olist.count()) {
+ QDomNode onode = olist.item(0);
+ if(onode.isElement()) {
+ QDomElement elo = onode.toElement();
+ if(exp.cap(2).isEmpty()) {
+ res = elo.text();
+ } else {
+ res = extractNodeText(elo, exp.cap(2));
+ }
+ }
+ }
+ }
+ return res;
+}
+
+QString extractNodeText(QDomDocument& doc, const QString& name)
+{
+ QString res;
+ QRegExp exp("([^/]+)/?([^/].*)?");
+ if(exp.search(name) != -1) {
+ QDomNodeList olist = doc.elementsByTagName(exp.cap(1));
+ if(olist.count()) {
+ QDomNode onode = olist.item(0);
+ if(onode.isElement()) {
+ QDomElement elo = onode.toElement();
+ if(exp.cap(2).isEmpty()) {
+ res = elo.text();
+ } else {
+ res = extractNodeText(elo, exp.cap(2));
+ }
+ }
+ }
+ }
+ return res;
+}
+
+OfxFiServiceInfo ServiceInfo(const QString& fipid)
+{
+ OfxFiServiceInfo result;
+ memset(&result, 0, sizeof(OfxFiServiceInfo));
+
+ // Hard-coded values for Innovision test server
+ if ( fipid == "1" )
+ {
+ strncpy(result.fid,"00000",OFX_FID_LENGTH-1);
+ strncpy(result.org,"ReferenceFI",OFX_ORG_LENGTH-1);
+ strncpy(result.url,"http://ofx.innovision.com",OFX_URL_LENGTH-1);
+ result.accountlist = 1;
+ result.statements = 1;
+ result.billpay = 1;
+ result.investments = 1;
+
+ return result;
+ }
+
+ QMap<QString, QString> attr;
+ attr["content-type"] = "application/x-www-form-urlencoded";
+ attr["accept"] = "*/*";
+
+ KURL guidFile(QString("%1fipid-%2.xml").arg(directory).arg(fipid));
+
+ // Apparently at some point in time, for VER=6 msn returned an online URL
+ // to a static error page (http://moneycentral.msn.com/cust404.htm).
+ // Increasing to VER=9 solved the problem. This may happen again in the
+ // future.
+ QFileInfo i(guidFile.path());
+ if(!i.isReadable() || i.lastModified().addDays(7) < QDateTime::currentDateTime())
+ get("", attr, KURL(QString("http://moneycentral.msn.com/money/2005/mnynet/service/olsvcupd/OnlSvcBrandInfo.aspx?MSNGUID=&GUID=%1&SKU=3&VER=" VER).arg(fipid)), guidFile);
+
+ QFile f(guidFile.path());
+ if(f.open(IO_ReadOnly)) {
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::Unicode);
+ QString msg;
+ int errl, errc;
+ QDomDocument doc;
+ if(doc.setContent(stream.read(), &msg, &errl, &errc)) {
+ QString fid = extractNodeText(doc, "ProviderSettings/FID");
+ QString org = extractNodeText(doc, "ProviderSettings/Org");
+ QString url = extractNodeText(doc, "ProviderSettings/ProviderURL");
+ strncpy(result.fid, fid.latin1(), OFX_FID_LENGTH-1);
+ strncpy(result.org, org.latin1(), OFX_ORG_LENGTH-1);
+ strncpy(result.url, url.latin1(), OFX_URL_LENGTH-1);
+ result.accountlist = (extractNodeText(doc, "ProviderSettings/AcctListAvail") == "1");
+ result.statements = (extractNodeText(doc, "BankingCapabilities/Bank") == "1");
+ result.billpay= (extractNodeText(doc, "BillPayCapabilities/Pay") == "1");
+ result.investments= (extractNodeText(doc, "InvestmentCapabilities/BrkStmt") == "1");
+ }
+ }
+
+ return result;
+}
+
+bool get(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename)
+{
+ QByteArray req(0);
+ OfxHttpRequest job("GET", url, req, attr, filename, true);
+
+ return job.error() == QHttp::NoError;
+}
+
+bool post(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename)
+{
+ QByteArray req;
+ req.fill(0, request.length()+1);
+ req.duplicate(request.ascii(), request.length());
+
+ OfxHttpRequest job("POST", url, req, attr, filename, true);
+ return job.error() == QHttp::NoError;
+}
+
+} // namespace OfxPartner
+
+class OfxHttpsRequest::Private
+{
+public:
+ QFile m_fpTrace;
+};
+
+OfxHttpsRequest::OfxHttpsRequest(const QString& type, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo) :
+ d(new Private),
+ m_dst(dst)
+{
+ QDir homeDir(QDir::home());
+ if(homeDir.exists("ofxlog.txt")) {
+ d->m_fpTrace.setName(QString("%1/ofxlog.txt").arg(QDir::homeDirPath()));
+ d->m_fpTrace.open(IO_WriteOnly | IO_Append);
+ }
+
+ m_job = KIO::http_post(url, postData, showProgressInfo);
+ m_job->addMetaData("content-type", "Content-type: application/x-ofx" );
+
+ if(d->m_fpTrace.isOpen()) {
+ QTextStream ts(&d->m_fpTrace);
+ ts << "url: " << url.prettyURL() << "\n";
+ ts << "request:\n" << QString(postData) << "\n" << "response:\n";
+ }
+
+ connect(m_job,SIGNAL(result(KIO::Job*)),this,SLOT(slotOfxFinished(KIO::Job*)));
+ connect(m_job,SIGNAL(data(KIO::Job*, const QByteArray&)),this,SLOT(slotOfxData(KIO::Job*,const QByteArray&)));
+ connect(m_job,SIGNAL(connected(KIO::Job*)),this,SLOT(slotOfxConnected(KIO::Job*)));
+
+ qApp->enter_loop();
+}
+
+OfxHttpsRequest::~OfxHttpsRequest()
+{
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.close();
+ }
+}
+
+void OfxHttpsRequest::slotOfxConnected(KIO::Job*)
+{
+ m_file.setName(m_dst.path());
+ m_file.open(IO_WriteOnly);
+}
+
+void OfxHttpsRequest::slotOfxData(KIO::Job*,const QByteArray& _ba)
+{
+ if(m_file.isOpen()) {
+ QTextStream ts(&m_file);
+ ts << QString(_ba);
+
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock(_ba, _ba.size());
+ }
+
+
+ }
+}
+
+void OfxHttpsRequest::slotOfxFinished(KIO::Job* /* e */)
+{
+ if(m_file.isOpen()) {
+ m_file.close();
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock("\nCompleted\n\n\n\n", 14);
+ }
+ }
+
+ int error = m_job->error();
+ if ( error ) {
+ m_job->showErrorDialog();
+ unlink(m_dst.path());
+
+ } else if ( m_job->isErrorPage() ) {
+ QString details;
+ QFile f( m_dst.path() );
+ if ( f.open( IO_ReadOnly ) ) {
+ QTextStream stream( &f );
+ QString line;
+ while ( !stream.atEnd() ) {
+ details += stream.readLine(); // line of text excluding '\n'
+ }
+ f.close();
+ }
+ KMessageBox::detailedSorry( 0, i18n("The HTTP request failed."), details, i18n("Failed") );
+ unlink(m_dst.path());
+ }
+
+ qApp->exit_loop();
+}
+
+
+
+OfxHttpRequest::OfxHttpRequest(const QString& type, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo)
+{
+ QFile f(dst.path());
+ m_error = QHttp::NoError;
+ QString errorMsg;
+ if(f.open(IO_WriteOnly)) {
+ m_job = new QHttp(url.host());
+ QHttpRequestHeader header(type, url.encodedPathAndQuery());
+ header.setValue("Host", url.host());
+ QMap<QString, QString>::const_iterator it;
+ for(it = metaData.begin(); it != metaData.end(); ++it) {
+ header.setValue(it.key(), *it);
+ }
+
+ m_job->request(header, postData, &f);
+
+ connect(m_job, SIGNAL(requestFinished(int, bool)),
+ this, SLOT(slotOfxFinished(int, bool)));
+
+ qApp->enter_loop();
+
+ if(m_error != QHttp::NoError)
+ errorMsg = m_job->errorString();
+
+ delete m_job;
+ } else {
+ m_error = QHttp::Aborted;
+ errorMsg = i18n("Cannot open file %1 for writing").arg(dst.path());
+ }
+
+ if(m_error != QHttp::NoError) {
+ KMessageBox::error(0, errorMsg, i18n("OFX setup error"));
+ unlink(dst.path());
+ }
+}
+
+void OfxHttpRequest::slotOfxFinished(int, bool rc)
+{
+ if(rc) {
+ m_error = m_job->error();
+ }
+ qApp->exit_loop();
+}
+
+#include "ofxpartner.moc"
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/ofxpartner.h b/kmymoney2/plugins/ofximport/ofxpartner.h
new file mode 100644
index 0000000..e624282
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofxpartner.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ ofxpartner.h
+ ----------
+ begin : Fri Jan 23 2009
+ copyright : (C) 2009 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef OFXPARTNER_H
+#define OFXPARTNER_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+
+#include <qobject.h>
+#include <qhttp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kurl.h>
+namespace KIO
+{
+ class Job;
+ class TransferJob;
+}
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <libofx/libofx.h>
+
+namespace OfxPartner
+{
+ /**
+ * setup the directory where the files will be stored.
+ * @a dir must end with a '/' and must exist. Call this
+ * before any other of the functions of OfxPartner. The
+ * default will be to store the files in the current
+ * directory.
+ */
+ void setDirectory(const QString& dir);
+
+ void ValidateIndexCache(void);
+ OfxFiServiceInfo ServiceInfo(const QString& fipid);
+ QValueList<QString> BankNames(void);
+ QValueList<QString> FipidForBank(const QString& bank);
+
+}
+
+class OfxHttpRequest : public QObject
+{
+ Q_OBJECT
+public:
+ OfxHttpRequest(const QString& method, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo=true);
+ virtual ~OfxHttpRequest() {}
+
+ QHttp::Error error(void) const { return m_error; }
+
+protected slots:
+ void slotOfxFinished(int, bool);
+
+private:
+ QHttp* m_job;
+ KURL m_dst;
+ QHttp::Error m_error;
+
+};
+
+class OfxHttpsRequest : public QObject
+{
+Q_OBJECT
+public:
+ OfxHttpsRequest(const QString& method, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo=true);
+ virtual ~OfxHttpsRequest();
+
+ QHttp::Error error(void) const { return m_error; }
+
+protected slots:
+ void slotOfxFinished(KIO::Job*);
+ void slotOfxData(KIO::Job*,const QByteArray&);
+ void slotOfxConnected(KIO::Job*);
+
+private:
+ class Private;
+ Private* d;
+ KURL m_dst;
+ QFile m_file;
+ QHttp::Error m_error;
+ KIO::TransferJob* m_job;
+};
+#endif // OFXPARTNER_H
diff --git a/kmymoney2/plugins/pluginloader.cpp b/kmymoney2/plugins/pluginloader.cpp
new file mode 100644
index 0000000..0201337
--- /dev/null
+++ b/kmymoney2/plugins/pluginloader.cpp
@@ -0,0 +1,163 @@
+/***************************************************************************
+ pluginloader.cpp
+ -------------------
+ begin : Thu Feb 12 2009
+ copyright : (C) 2009 Cristian Onet
+ email : onet.cristian@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kconfig.h>
+#include <kpluginselector.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyplugin.h"
+#include "pluginloader.h"
+
+namespace KMyMoneyPlugin {
+
+//---------------------------------------------------------------------
+//
+// PluginLoader
+//
+//---------------------------------------------------------------------
+static PluginLoader* s_instance = 0;
+
+typedef QMap<QString, Plugin*> PluginsMap;
+
+struct PluginLoader::Private
+{
+ QObject* m_parent;
+ KPluginInfo::List m_pluginList;
+ KPluginSelector* m_pluginSelector;
+ PluginsMap m_loadedPlugins;
+};
+
+PluginLoader::PluginLoader(QObject* parent)
+{
+ Q_ASSERT( s_instance == 0 );
+ s_instance = this;
+
+ d = new Private;
+
+ d->m_parent = parent;
+
+ KTrader::OfferList offers = KTrader::self()->query("KMyMoneyPlugin");
+ d->m_pluginList = KPluginInfo::fromServices(offers);
+
+ d->m_pluginSelector = new KPluginSelector(NULL);
+ d->m_pluginSelector->setShowEmptyConfigPage(false);
+ d->m_pluginSelector->addPlugins(d->m_pluginList);
+ d->m_pluginSelector->load();
+
+ connect(d->m_pluginSelector, SIGNAL(changed(bool)), this, SLOT(changed()));
+ connect(d->m_pluginSelector, SIGNAL(configCommitted(const QCString &)), this, SLOT(changedConfigOfPlugin(const QCString &)));
+}
+
+PluginLoader::~PluginLoader()
+{
+ delete d;
+}
+
+void PluginLoader::loadPlugins()
+{
+ for( KPluginInfo::List::Iterator it = d->m_pluginList.begin(); it != d->m_pluginList.end(); ++it )
+ loadPlugin( *it );
+}
+
+void PluginLoader::loadPlugin(KPluginInfo* info)
+{
+ if (info->isPluginEnabled()) {
+ Plugin* plugin = getPluginFromInfo(info);
+
+ if (!plugin) {
+ // the plugin is enabled but it is not loaded
+ KService::Ptr service = info->service();
+ int error = 0;
+ Plugin* plugin = KParts::ComponentFactory
+ ::createInstanceFromService<Plugin>(service, d->m_parent, info->name().utf8(), QStringList(), &error);
+ if (plugin) {
+ kdDebug() << "KMyMoneyPlugin::PluginLoader: Loaded plugin " << plugin->name() << endl;
+ d->m_loadedPlugins.insert(info->name(), plugin);
+ emit PluginLoader::instance()->plug(info);
+ }
+ else {
+ kdWarning() << "KMyMoneyPlugin::PluginLoader:: createInstanceFromService returned 0 for "
+ << info->name()
+ << " with error number "
+ << error << endl;
+ if (error == KParts::ComponentFactory::ErrNoLibrary)
+ kdWarning() << "KLibLoader says: "
+ << KLibLoader::self()->lastErrorMessage() << endl;
+ }
+ }
+ }
+ else {
+ if (getPluginFromInfo(info) != NULL) {
+ // everybody interested should say goodbye to the plugin
+ emit PluginLoader::instance()->unplug(info);
+ d->m_loadedPlugins.erase(info->name());
+ }
+ }
+}
+
+void PluginLoader::changed()
+{
+ loadPlugins();
+}
+
+void PluginLoader::changedConfigOfPlugin(const QCString & name)
+{
+ PluginsMap::iterator itPlugin = d->m_loadedPlugins.find(QString(name));
+ if (itPlugin != d->m_loadedPlugins.end())
+ configChanged(*itPlugin);
+}
+
+Plugin* PluginLoader::getPluginFromInfo(KPluginInfo* info)
+{
+ PluginsMap::iterator itPlugin = d->m_loadedPlugins.find(info->name());
+ if (itPlugin != d->m_loadedPlugins.end())
+ return *itPlugin;
+ else
+ return NULL;
+}
+
+PluginLoader* PluginLoader::instance()
+{
+ Q_ASSERT( s_instance != 0);
+ return s_instance;
+}
+
+KPluginSelector* PluginLoader::pluginSelectorWidget()
+{
+ return d->m_pluginSelector;
+}
+
+} // namespace
+
+#include "pluginloader.moc"
diff --git a/kmymoney2/plugins/pluginloader.h b/kmymoney2/plugins/pluginloader.h
new file mode 100644
index 0000000..4d0c500
--- /dev/null
+++ b/kmymoney2/plugins/pluginloader.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ pluginloader.h
+ -------------------
+ begin : Thu Feb 12 2009
+ copyright : (C) 2009 Cristian Onet
+ email : onet.cristian@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PLUGINLOADER_H
+#define PLUGINLOADER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qscrollview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kplugininfo.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+class KPluginSelector;
+
+namespace KMyMoneyPlugin
+{
+ class Plugin;
+
+ class KMYMONEY_EXPORT PluginLoader : public QObject
+ {
+ Q_OBJECT
+ public:
+ PluginLoader(QObject* parent);
+ virtual ~PluginLoader();
+ static PluginLoader* instance();
+
+ void loadPlugins();
+ Plugin* getPluginFromInfo(KPluginInfo*);
+ KPluginSelector* pluginSelectorWidget();
+
+ private:
+ void loadPlugin(KPluginInfo*);
+
+ signals:
+ void plug(KPluginInfo*);
+ void unplug(KPluginInfo*);
+ void configChanged(Plugin*); // consfiguration of the plugin has changed not the enabled/disabled state
+
+ private slots:
+ void changed();
+ void changedConfigOfPlugin( const QCString & );
+
+ private:
+ struct Private;
+ Private* d;
+ };
+}
+
+#endif /* PLUGINLOADER_H */
diff --git a/kmymoney2/plugins/statementinterface.cpp b/kmymoney2/plugins/statementinterface.cpp
new file mode 100644
index 0000000..753db2e
--- /dev/null
+++ b/kmymoney2/plugins/statementinterface.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ statementinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "statementinterface.h"
+
+KMyMoneyPlugin::StatementInterface::StatementInterface(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+#include "statementinterface.moc"
diff --git a/kmymoney2/plugins/statementinterface.h b/kmymoney2/plugins/statementinterface.h
new file mode 100644
index 0000000..a3a31d1
--- /dev/null
+++ b/kmymoney2/plugins/statementinterface.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ statementinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef STATEMENTINTERFACE_H
+#define STATEMENTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneystatement.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/export.h>
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This abstract class represents the interface to import statements
+ * into the KMyMoney application
+ */
+class KMYMONEY_EXPORT StatementInterface : public QObject {
+ Q_OBJECT
+
+public:
+ StatementInterface(QObject* parent, const char* name = 0);
+ ~StatementInterface() {}
+
+ /**
+ * This method imports a MyMoneyStatement into the engine
+ */
+ virtual bool import(const MyMoneyStatement& s) = 0;
+
+ /**
+ * This method returns the account for a given @a key - @a value pair.
+ * If the account is not found in the list of accounts, MyMoneyAccount()
+ * is returned.
+ */
+ virtual const MyMoneyAccount& account(const QString& key, const QString& value) const = 0;
+
+ /**
+ */
+ virtual void setAccountOnlineParameters(const MyMoneyAccount& acc, const MyMoneyKeyValueContainer& kvps) const = 0;
+
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/viewinterface.cpp b/kmymoney2/plugins/viewinterface.cpp
new file mode 100644
index 0000000..4db12f1
--- /dev/null
+++ b/kmymoney2/plugins/viewinterface.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ viewinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "viewinterface.h"
+
+KMyMoneyPlugin::ViewInterface::ViewInterface(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+#include "viewinterface.moc"
diff --git a/kmymoney2/plugins/viewinterface.h b/kmymoney2/plugins/viewinterface.h
new file mode 100644
index 0000000..d7c7424
--- /dev/null
+++ b/kmymoney2/plugins/viewinterface.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ viewinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef VIEWINTERFACE_H
+#define VIEWINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qpixmap.h>
+class QFrame;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KPopupMenu;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/export.h>
+class KMyMoneyViewBase;
+namespace KMyMoneyRegister {
+ class SelectedTransactions;
+};
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This abstract class represents the ViewInterface to
+ * add new view pages to the JanusWidget of KMyMoney. It
+ * also gives access to the account context menu.
+ */
+class KMYMONEY_EXPORT ViewInterface : public QObject {
+ Q_OBJECT
+
+public:
+ ViewInterface(QObject* parent, const char* name = 0);
+ ~ViewInterface() {}
+
+ /**
+ * This method creates a new page in the application.
+ * See KJanusWidget::addPage() for details.
+ */
+ virtual KMyMoneyViewBase* addPage(const QString& item, const QString& icon) = 0;
+
+ /**
+ * This method adds a widget to the layout of the view
+ * created with addPage()
+ *
+ * @param view pointer to view widget
+ * @param w widget to be added to @p page
+ */
+ virtual void addWidget(KMyMoneyViewBase* view, QWidget* w) = 0;
+
+signals:
+ /**
+ * This signal is emitted when a new account has been selected by
+ * the GUI. If no account is selected or the selection is removed,
+ * @a account is identical to MyMoneyAccount(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void accountSelected(const MyMoneyAccount& acc);
+
+ /**
+ * This signal is emitted when a transaction/list of transactions has been selected by
+ * the GUI. If no transaction is selected or the selection is removed,
+ * @p transactions is identical to an empty QValueList. This signal is used
+ * by plugins to get information about changes.
+ */
+ void transactionsSelected(const KMyMoneyRegister::SelectedTransactions& transactions);
+
+ /**
+ * This signal is emitted when a new institution has been selected by
+ * the GUI. If no institution is selected or the selection is removed,
+ * @a institution is identical to MyMoneyInstitution(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void institutionSelected(const MyMoneyInstitution& institution);
+
+ /**
+ * This signal is emitted when an account has been successfully reconciled
+ * and all transactions are updated in the engine. It can be used by plugins
+ * to create reconciliation reports.
+ *
+ * @param account the account data
+ * @param date the reconciliation date as provided through the dialog
+ * @param startingBalance the starting balance as provided through the dialog
+ * @param endingBalance the ending balance as provided through the dialog
+ * @param transactionList reference to QValueList of QPair containing all
+ * transaction/split pairs processed by the reconciliation.
+ */
+ void accountReconciled(const MyMoneyAccount& account, const QDate& date, const MyMoneyMoney& startingBalance, const MyMoneyMoney& endingBalance, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& transactionList);
+
+
+ void viewStateChanged(bool);
+ void kmmFilePlugin(unsigned int);
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/reports/Makefile.am b/kmymoney2/reports/Makefile.am
new file mode 100644
index 0000000..d6d050f
--- /dev/null
+++ b/kmymoney2/reports/Makefile.am
@@ -0,0 +1,16 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I.. -I$(top_srcdir) -I. -I$(top_srcdir)/libkdchart
+
+noinst_LIBRARIES = libreports.a
+libreports_a_METASOURCES = AUTO
+
+libreports_a_SOURCES = pivotgrid.cpp pivottable.cpp listtable.cpp querytable.cpp objectinfotable.cpp reportaccount.cpp kreportchartview.cpp
+
+noinst_HEADERS = kreportchartview.h kreportsviewtest.h pivotgrid.h pivottable.h pivottabletest.h pivotgridtest.h listtable.h querytable.h querytabletest.h objectinfotable.h reportaccount.h reportdebug.h reportstestcommon.h kreportchartview.h reporttable.h
+
+if CPPUNIT
+check_LIBRARIES = libreportstest.a
+
+libreportstest_a_SOURCES = reportstestcommon.cpp pivottabletest.cpp pivotgridtest.cpp querytabletest.cpp
+endif
diff --git a/kmymoney2/reports/kreportchartview.cpp b/kmymoney2/reports/kreportchartview.cpp
new file mode 100644
index 0000000..21b08fa
--- /dev/null
+++ b/kmymoney2/reports/kreportchartview.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+ kreportchartview.cpp
+ -------------------
+ begin : Sun Aug 14 2005
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+#ifdef HAVE_KDCHART
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kreportchartview.h"
+#include <KDChartDataRegion.h>
+
+using namespace reports;
+
+KReportChartView::KReportChartView( QWidget* parent, const char* name ): KDChartWidget(parent,name)
+{
+ // ********************************************************************
+ // Set KMyMoney's Chart Parameter Defaults
+ // ********************************************************************
+ this->setPaletteBackgroundColor( Qt::white );
+
+ KDChartParams* _params = new KDChartParams();
+ _params->setChartType( KDChartParams::Line );
+ _params->setAxisLabelStringParams( KDChartAxisParams::AxisPosBottom,&m_abscissaNames,0);
+ _params->setDataSubduedColors();
+
+ /**
+ // use line marker, but only circles.
+ _params->setLineMarker( true );
+ _params->setLineMarkerSize( QSize(8,8) );
+ _params->setLineMarkerStyle( 0, KDChartParams::LineMarkerCircle );
+ _params->setLineMarkerStyle( 1, KDChartParams::LineMarkerCircle );
+ _params->setLineMarkerStyle( 2, KDChartParams::LineMarkerCircle );
+ **/
+
+ // initialize parameters
+ this->setParams(_params);
+
+ // initialize data
+ KDChartTableData* _data = new KDChartTableData();
+ this->setData(_data);
+
+ // ********************************************************************
+ // Some Examplatory Chart Table Data
+ // ********************************************************************
+
+ /**
+ // 1st series
+ this->data()->setCell( 0, 0, 17.5 );
+ this->data()->setCell( 0, 1, 125 ); // highest value
+ this->data()->setCell( 0, 2, 6.67 ); // lowest value
+ this->data()->setCell( 0, 3, 33.333 );
+ this->data()->setCell( 0, 4, 30 );
+ // 2nd series
+ this->data()->setCell( 1, 0, 40 );
+ this->data()->setCell( 1, 1, 40 );
+ this->data()->setCell( 1, 2, 45.5 );
+ this->data()->setCell( 1, 3, 45 );
+ this->data()->setCell( 1, 4, 35 );
+ // 3rd series
+ this->data()->setCell( 2, 0, 25 );
+ // missing value: setCell( 2, 1, 25 );
+ this->data()->setCell( 2, 2, 30 );
+ this->data()->setCell( 2, 3, 45 );
+ this->data()->setCell( 2, 4, 40 );
+ **/
+
+ // ********************************************************************
+ // Tooltip Setup
+ // ********************************************************************
+ label = new QLabel( this );
+ label->hide();
+ // mouse tracking on will force the mouseMoveEvent() method to be called from Qt
+ label->setMouseTracking( true );
+ label->setFrameStyle( QFrame::PopupPanel | QFrame::Raised );
+ label->setAlignment( AlignRight );
+ label->setAutoResize( true );
+}
+
+/**
+ * This function implements mouseMoveEvents
+ */
+void KReportChartView::mouseMoveEvent( QMouseEvent* event )
+{
+ QPoint translate, pos; // some movement helpers
+ uint dataset; // the current dataset (eg. category)
+ uint datasets; // the total number of datasets
+ double value; // the value of the region
+ double pivot_sum; // the sum over all categories in the current pivot point
+
+ // the data region in which the cursor was last time
+ static uint previous;
+
+ // if mouse tracking is disabled, don't show any tooltip
+ if ( !this->hasMouseTracking() )
+ return ;
+
+ // find the data region below the current mouse location
+ // ..by going through every data region and checking whether it
+ // contains the mouse pointer
+ KDChartDataRegion* current = 0;
+ QPtrListIterator < KDChartDataRegion > it( *(this->dataRegions()) );
+ while ( ( current = it.current() ) ) {
+ ++it;
+ if ( current->contains( event->pos() ) )
+ {
+ // we found the data region that contains the mouse
+ value = this->data()->cellVal(current->row, current->col).toDouble();
+
+ // get the dataset that the region corresponds to
+ if ( this->getAccountSeries() )
+ {
+ dataset = current->row;
+ datasets= this->data()->rows();
+ pivot_sum = value * 100.0 / this->data()->colSum(current->col);
+ }
+ else
+ {
+ dataset = current->col;
+ datasets= this->data()->cols();
+ pivot_sum = value * 100.0 / this->data()->rowSum(current->row);
+ }
+
+ // if we entered a new data region or the label was invisible
+ if ( !label->isVisible() || previous != dataset )
+ {
+ // if there is more than one dataset, show percentage
+ if(datasets > 1)
+ {
+ // set the tooltip text
+ label->setText(QString("<h2>%1</h2><strong>%2</strong><br>(%3\%)")
+ .arg(this->params()->legendText( dataset ))
+ .arg(value, 0, 'f', 2)
+ .arg(pivot_sum, 0, 'f', 2)
+ );
+ }
+ else // if there is only one dataset, don't show percentage
+ {
+ // set the tooltip text
+ label->setText(QString("<h2>%1</h2><strong>%2</strong>")
+ .arg(this->params()->legendText( dataset ))
+ .arg(value, 0, 'f', 2)
+ );
+ }
+
+ previous = dataset;
+ }
+
+ translate.setX( -10 - label->width());
+ translate.setY( 20);
+
+ // display the label near the cursor
+ pos = event->pos() + translate;
+
+ // but don't let the label leave the visible area
+ if( pos.x() < 0 )
+ pos.setX(0);
+ if( pos.y() < 0 )
+ pos.setY(0);
+ if( pos.x() + label->width() > this->width() )
+ pos.setX( this->width() - label->width() );
+ if( pos.y() + label->height() > this->height() )
+ pos.setY( this->height() - label->height() );
+
+ // now set the label position and show the label
+ label->move( pos );
+ label->show();
+
+ // In a more abstract class, we would emit a dateMouseMove event:
+ //emit this->dataMouseMove( event->pos(), current->row, current->col );
+
+ return ;
+ }
+ }
+ // if the cursor was not found in any data region, hide the label
+ label->hide();
+}
+
+void KReportChartView::setProperty(int row, int col, int id)
+{
+#ifdef HAVE_KDCHART_SETPROP
+ this->data()->setProp(row, col, id);
+#else
+ this->data()->cell(row, col).setPropertySet(id);
+#endif
+}
+
+#endif
diff --git a/kmymoney2/reports/kreportchartview.h b/kmymoney2/reports/kreportchartview.h
new file mode 100644
index 0000000..a1bf786
--- /dev/null
+++ b/kmymoney2/reports/kreportchartview.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ kreportchartview.h
+ -------------------
+ begin : Sat May 22 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KREPORTCHARTVIEW_H
+#define KREPORTCHARTVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+#ifdef HAVE_KDCHART
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// Some STL headers in GCC4.3 contain operator new. Memory checker mangles these
+#ifdef _CHECK_MEMORY
+ #undef new
+#endif
+
+#include <qlabel.h>
+#include <KDChartWidget.h>
+#include <KDChartTable.h>
+#include <KDChartParams.h>
+#include <KDChartAxisParams.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#ifdef _CHECK_MEMORY
+ #include <kmymoney/mymoneyutils.h>
+#endif
+
+namespace reports {
+
+class KReportChartView: public KDChartWidget
+{
+public:
+ KReportChartView( QWidget* parent, const char* name );
+ ~KReportChartView() {}
+ static bool implemented(void) { return true; }
+ void setNewData( const KDChartTableData& newdata ) { this->setData(new KDChartTableData(newdata)); }
+ QStringList& abscissaNames(void) { return m_abscissaNames; }
+ void refreshLabels(void) { this->params()->setAxisLabelStringParams( KDChartAxisParams::AxisPosBottom,&m_abscissaNames,0); }
+ void setProperty(int row, int col, int id);
+// void setCircularLabels(void) { this->params()->setAxisLabelStringParams( KDChartAxisParams::AxisPosCircular,&m_abscissaNames,0); }
+
+ void setAccountSeries(bool accountSeries) {_accountSeries = accountSeries; }
+ bool getAccountSeries(void) {return _accountSeries; }
+
+protected:
+ virtual void mouseMoveEvent( QMouseEvent* event );
+
+private:
+ QStringList m_abscissaNames;
+ bool _accountSeries;
+
+ // label to display when hovering on a data region
+ QLabel *label;
+};
+
+} // end namespace reports
+
+#else
+
+namespace reports {
+
+class KReportChartView : public QWidget
+{
+public:
+ KReportChartView( QWidget* parent, const char* name ): QWidget(parent,name) {}
+ ~KReportChartView() {}
+ static bool implemented(void) { return false; }
+};
+
+} // end namespace reports
+
+#endif
+
+#endif // KREPORTCHARTVIEW_H
diff --git a/kmymoney2/reports/kreportsviewtest.h b/kmymoney2/reports/kreportsviewtest.h
new file mode 100644
index 0000000..70660c4
--- /dev/null
+++ b/kmymoney2/reports/kreportsviewtest.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ mymoneyaccounttest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.jones@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KREPORTSVIEWTEST_H__
+#define __KREPORTSVIEWTEST_H__
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+class KReportsViewTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(KReportsViewTest);
+ CPPUNIT_TEST(testNetWorthSingle);
+ CPPUNIT_TEST(testNetWorthOfsetting);
+ CPPUNIT_TEST(testNetWorthOpeningPrior);
+ CPPUNIT_TEST(testNetWorthDateFilter);
+ CPPUNIT_TEST(testSpendingEmpty);
+ CPPUNIT_TEST(testSingleTransaction);
+ CPPUNIT_TEST(testSubAccount);
+ CPPUNIT_TEST(testFilterIEvsIE);
+ CPPUNIT_TEST(testFilterALvsAL);
+ CPPUNIT_TEST(testFilterALvsIE);
+ CPPUNIT_TEST(testFilterAllvsIE);
+ CPPUNIT_TEST(testFilterBasics);
+ CPPUNIT_TEST(testMultipleCurrencies);
+ CPPUNIT_TEST(testAdvancedFilter);
+ CPPUNIT_TEST(testColumnType);
+ CPPUNIT_TEST(testXMLWrite);
+ CPPUNIT_TEST(testQueryBasics);
+ CPPUNIT_TEST(testCashFlowAnalysis);
+ CPPUNIT_TEST(testAccountQuery);
+ CPPUNIT_TEST(testInvestment);
+#ifdef USE_OFX_DIRECTCONNECT
+ CPPUNIT_TEST(testOfxImport);
+#endif
+ CPPUNIT_TEST(testWebQuotes);
+ CPPUNIT_TEST(testDateFormat);
+ CPPUNIT_TEST(testHasReferenceTo);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ MyMoneyAccount *m;
+
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyFile* file;
+
+public:
+ KReportsViewTest();
+ void setUp ();
+ void tearDown ();
+ void testNetWorthSingle();
+ void testNetWorthOfsetting();
+ void testNetWorthOpeningPrior();
+ void testNetWorthDateFilter();
+ void testSpendingEmpty();
+ void testSingleTransaction();
+ void testSubAccount();
+ void testFilterIEvsIE();
+ void testFilterALvsAL();
+ void testFilterALvsIE();
+ void testFilterAllvsIE();
+ void testFilterBasics();
+ void testMultipleCurrencies();
+ void testAdvancedFilter();
+ void testColumnType();
+ void testXMLWrite();
+ void testQueryBasics();
+ void testCashFlowAnalysis();
+ void testAccountQuery();
+ void testOfxImport();
+ void testInvestment();
+ void testWebQuotes();
+ void testDateFormat();
+ void testHasReferenceTo();
+};
+
+#endif
diff --git a/kmymoney2/reports/listtable.cpp b/kmymoney2/reports/listtable.cpp
new file mode 100644
index 0000000..797b392
--- /dev/null
+++ b/kmymoney2/reports/listtable.cpp
@@ -0,0 +1,633 @@
+/***************************************************************************
+ listtable.cpp
+ -------------------
+ begin : Sat 28 jun 2008
+ copyright : (C) 2004-2005 by Ace Jones
+ 2008 by Alvaro Soliverez
+ email : acejones@users.sourceforge.net
+ asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qvaluelist.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// This is just needed for i18n(). Once I figure out how to handle i18n
+// without using this macro directly, I'll be freed of KDE dependency.
+
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneyexception.h"
+#include "../kmymoneyutils.h"
+#include "../kmymoneyglobalsettings.h"
+#include "reportdebug.h"
+#include "listtable.h"
+
+namespace reports {
+
+ QStringList ListTable::TableRow::m_sortCriteria;
+
+ // ****************************************************************************
+ //
+ // Group Iterator
+ //
+ // ****************************************************************************
+
+ class GroupIterator
+ {
+ public:
+ GroupIterator ( const QString& _group, const QString& _subtotal, unsigned _depth ) : m_depth ( _depth ), m_groupField ( _group ), m_subtotalField ( _subtotal ) {}
+ GroupIterator ( void ) {}
+ void update ( const ListTable::TableRow& _row )
+ {
+ m_previousGroup = m_currentGroup;
+ m_currentGroup = _row[m_groupField];
+ if ( isSubtotal() )
+ {
+ m_previousSubtotal = m_currentSubtotal;
+ m_currentSubtotal = MyMoneyMoney();
+ }
+ m_currentSubtotal += _row[m_subtotalField];
+ }
+
+ bool isNewHeader ( void ) const { return ( m_currentGroup != m_previousGroup ); }
+ bool isSubtotal ( void ) const { return ( m_currentGroup != m_previousGroup ) && ( !m_previousGroup.isEmpty() ); }
+ const MyMoneyMoney& subtotal ( void ) const { return m_previousSubtotal; }
+ const MyMoneyMoney& currenttotal ( void ) const { return m_currentSubtotal; }
+ unsigned depth ( void ) const { return m_depth; }
+ const QString& name ( void ) const { return m_currentGroup; }
+ const QString& oldName ( void ) const { return m_previousGroup; }
+ const QString& groupField ( void ) const { return m_groupField; }
+ const QString& subtotalField ( void ) const { return m_subtotalField; }
+ // ***DV*** HACK make the currentGroup test different but look the same
+ void force ( void ) { m_currentGroup += " "; }
+ private:
+ MyMoneyMoney m_currentSubtotal;
+ MyMoneyMoney m_previousSubtotal;
+ unsigned m_depth;
+ QString m_currentGroup;
+ QString m_previousGroup;
+ QString m_groupField;
+ QString m_subtotalField;
+ };
+
+// ****************************************************************************
+//
+// ListTable implementation
+//
+// ****************************************************************************
+
+ bool ListTable::TableRow::operator< ( const TableRow& _compare ) const
+ {
+ bool result = false;
+
+ QStringList::const_iterator it_criterion = m_sortCriteria.begin();
+ while ( it_criterion != m_sortCriteria.end() )
+ {
+ if ( this->operator[] ( *it_criterion ) < _compare[ *it_criterion ] )
+ {
+ result = true;
+ break;
+ }
+ else if ( this->operator[] ( *it_criterion ) > _compare[ *it_criterion ] )
+ break;
+
+ ++it_criterion;
+ }
+ return result;
+ }
+
+// needed for KDE < 3.2 implementation of qHeapSort
+ bool ListTable::TableRow::operator<= ( const TableRow& _compare ) const
+ {
+ return ( ! ( _compare < *this ) );
+ }
+
+ bool ListTable::TableRow::operator== ( const TableRow& _compare ) const
+ {
+ return ( ! ( *this < _compare ) && ! ( _compare < *this ) );
+ }
+
+ bool ListTable::TableRow::operator> ( const TableRow& _compare ) const
+ {
+ return ( _compare < *this );
+ }
+
+ /**
+ * TODO
+ *
+ * - Collapse 2- & 3- groups when they are identical
+ * - Way more test cases (especially splits & transfers)
+ * - Option to collapse splits
+ * - Option to exclude transfers
+ *
+ */
+
+ ListTable::ListTable ( const MyMoneyReport& _report ) : m_config ( _report )
+ {
+ }
+
+ void ListTable::render ( QString& result, QString& csv ) const
+ {
+ MyMoneyMoney grandtotal;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ result = "";
+ csv = "";
+ result += QString ( "<h2 class=\"report\">%1</h2>\n" ).arg ( m_config.name() );
+ csv += "\"Report: " + m_config.name() + "\"\n";
+ //actual dates of the report
+ result += QString("<div class=\"subtitle\">");
+ if(!m_config.fromDate().isNull()) {
+ result += i18n("Report date range", "%1 through %2").arg(KGlobal::locale()->formatDate(m_config.fromDate(), true)).arg(KGlobal::locale()->formatDate(m_config.toDate(), true));
+ result += QString("</div>\n");
+ result += QString("<div class=\"gap\">&nbsp;</div>\n");
+
+ csv += i18n("Report date range", "%1 through %2").arg(KGlobal::locale()->formatDate(m_config.fromDate(), true)).arg(KGlobal::locale()->formatDate(m_config.toDate(), true));
+ csv += QString("\n");
+ }
+
+
+ result += QString ( "<div class=\"subtitle\">" );
+ if ( m_config.isConvertCurrency() )
+ {
+ result += i18n ( "All currencies converted to %1" ).arg ( file->baseCurrency().name() );
+ csv += i18n ( "All currencies converted to %1\n" ).arg ( file->baseCurrency().name() );
+ }
+ else
+ {
+ result += i18n ( "All values shown in %1 unless otherwise noted" ).arg ( file->baseCurrency().name() );
+ csv += i18n ( "All values shown in %1 unless otherwise noted\n" ).arg ( file->baseCurrency().name() );
+ }
+ result += QString ( "</div>\n" );
+ result += QString ( "<div class=\"gap\">&nbsp;</div>\n" );
+
+ // retrieve the configuration parameters from the report definition.
+ // the things that we care about for query reports are:
+ // how to group the rows, what columns to display, and what field
+ // to subtotal on
+ QStringList groups = QStringList::split ( ",", m_group );
+ QStringList columns = QStringList::split ( ",", m_columns );
+ columns += m_subtotal;
+ QStringList postcolumns = QStringList::split ( ",", m_postcolumns );
+ columns += postcolumns;
+
+ //
+ // Table header
+ //
+ QMap<QString, QString> i18nHeaders;
+ i18nHeaders["postdate"] = i18n ( "Date" );
+ i18nHeaders["value"] = i18n ( "Amount" );
+ i18nHeaders["number"] = i18n ( "Num" );
+ i18nHeaders["payee"] = i18n ( "Payee" );
+ i18nHeaders["category"] = i18n ( "Category" );
+ i18nHeaders["account"] = i18n ( "Account" );
+ i18nHeaders["memo"] = i18n ( "Memo" );
+ i18nHeaders["topcategory"] = i18n ( "Top Category" );
+ i18nHeaders["categorytype"] = i18n ( "Category Type" );
+ i18nHeaders["month"] = i18n ( "Month" );
+ i18nHeaders["week"] = i18n ( "Week" );
+ i18nHeaders["reconcileflag"] = i18n ( "Reconciled" );
+ i18nHeaders["action"] = i18n ( "Action" );
+ i18nHeaders["shares"] = i18n ( "Shares" );
+ i18nHeaders["price"] = i18n ( "Price" );
+ i18nHeaders["latestprice"] = i18n ( "Price" );
+ i18nHeaders["netinvvalue"] = i18n ( "Net Value" );
+ i18nHeaders["buys"] = i18n ( "Buys" );
+ i18nHeaders["sells"] = i18n ( "Sells" );
+ i18nHeaders["reinvestincome"] = i18n ( "Dividends Reinvested" );
+ i18nHeaders["cashincome"] = i18n ( "Dividends Paid Out" );
+ i18nHeaders["startingbal"] = i18n ( "Starting Balance" );
+ i18nHeaders["endingbal"] = i18n ( "Ending Balance" );
+ i18nHeaders["return"] = i18n ( "Annualized Return" );
+ i18nHeaders["returninvestment"] = i18n ( "Return On Investment" );
+ i18nHeaders["fees"] = i18n ( "Fees" );
+ i18nHeaders["interest"] = i18n ( "Interest" );
+ i18nHeaders["payment"] = i18n ( "Payment" );
+ i18nHeaders["balance"] = i18n ( "Balance" );
+ i18nHeaders["type"] = i18n ( "Type" );
+ i18nHeaders["name"] = i18n ( "Name" );
+ i18nHeaders["nextduedate"] = i18n ( "Next Due Date" );
+ i18nHeaders["occurence"] = i18n ( "Occurence" );
+ i18nHeaders["paymenttype"] = i18n ( "Payment Method" );
+ i18nHeaders["institution"] = i18n ( "Institution" );
+ i18nHeaders["description"] = i18n ( "Description" );
+ i18nHeaders["openingdate"] = i18n ( "Opening Date" );
+ i18nHeaders["currencyname"] = i18n ( "Currency" );
+ i18nHeaders["balancewarning"] = i18n ( "Balance Early Warning" );
+ i18nHeaders["maxbalancelimit"] = i18n ( "Balance Max Limit" );
+ i18nHeaders["creditwarning"] = i18n ( "Credit Early Warning" );
+ i18nHeaders["maxcreditlimit"] = i18n ( "Credit Max Limit" );
+ i18nHeaders["tax"] = i18n ( "Tax" );
+ i18nHeaders["favorite"] = i18n ( "Preferred" );
+ i18nHeaders["loanamount"] = i18n ( "Loan Amount" );
+ i18nHeaders["interestrate"] = i18n ( "Interest Rate" );
+ i18nHeaders["nextinterestchange"] = i18n ( "Next Interest Change" );
+ i18nHeaders["periodicpayment"] = i18n ( "Periodic Payment" );
+ i18nHeaders["finalpayment"] = i18n ( "Final Payment" );
+ i18nHeaders["currentbalance"] = i18n ( "Current Balance" );
+
+ // the list of columns which represent money, so we can display them correctly
+ QStringList moneyColumns = QStringList::split ( ",", "value,shares,price,latestprice,netinvvalue,buys,sells,cashincome,reinvestincome,startingbal,fees,interest,payment,balance,balancewarning,maxbalancelimit,creditwarning,maxcreditlimit,loanamount,periodicpayment,finalpayment,currentbalance" );
+
+ // the list of columns which represent shares, which is like money except the
+ // transaction currency will not be displayed
+ QStringList sharesColumns = QStringList::split ( ",", "shares" );
+
+ // the list of columns which represent a percentage, so we can display them correctly
+ QStringList percentColumns = QStringList::split ( ",", "return,returninvestment,interestrate" );
+
+ // the list of columns which represent dates, so we can display them correctly
+ QStringList dateColumns = QStringList::split ( ",", "postdate,entrydate,nextduedate,openingdate,nextinterestchange" );
+
+ result += "<table class=\"report\">\n<thead><tr class=\"itemheader\">";
+
+ QStringList::const_iterator it_column = columns.begin();
+ while ( it_column != columns.end() )
+ {
+ QString i18nName = i18nHeaders[*it_column];
+ if ( i18nName.isEmpty() )
+ i18nName = *it_column;
+ result += "<th>" + i18nName + "</th>";
+ csv += i18nName + ",";
+ ++it_column;
+ }
+
+ result += "</tr></thead>\n";
+ csv = csv.left ( csv.length() - 1 );
+ csv += "\n";
+
+ //
+ // Set up group iterators
+ //
+ // There is one active iterator for each level of grouping.
+ // As we step through the rows
+ // we update the group iterators each time based on the row data. If
+ // the group iterator changes and it had a previous value, we print a
+ // subtotal. Whether or not it had a previous value, we print a group
+ // header. The group iterator keeps track of a subtotal also.
+
+ int depth = 1;
+ QValueList<GroupIterator> groupIteratorList;
+ QStringList::const_iterator it_grouplevel = groups.begin();
+ while ( it_grouplevel != groups.end() )
+ {
+ groupIteratorList += GroupIterator ( ( *it_grouplevel ), m_subtotal, depth++ );
+ ++it_grouplevel;
+ }
+
+ //
+ // Rows
+ //
+
+ bool row_odd = true;
+
+ // ***DV***
+ MyMoneyMoney startingBalance;
+ for ( QValueList<TableRow>::const_iterator it_row = m_rows.begin();
+ it_row != m_rows.end();
+ ++it_row ) {
+
+ // the standard fraction is the fraction of an non-cash account in the base currency
+ // this could be overridden using the "fraction" element of a row for each row.
+ // Currently (2008-02-21) this override is not used at all (ipwizard)
+ int fraction = file->baseCurrency().smallestAccountFraction();
+ if ( ( *it_row ).find ( "fraction" ) != ( *it_row ).end() )
+ fraction = ( *it_row ) ["fraction"].toInt();
+
+ //
+ // Process Groups
+ //
+
+ // ***DV*** HACK to force a subtotal and header, since this render doesn't
+ // always detect a group change for different accounts with the same name
+ // (as occurs with the same stock purchased from different investment accts)
+ if ( it_row != m_rows.begin() )
+ if ( ( ( * it_row ) ["rank"] == "-2" ) && ( ( * it_row ) ["id"] == "A" ) )
+ ( groupIteratorList.last() ).force();
+
+ // There's a subtle bug here. If an earlier group gets a new group,
+ // then we need to force all the downstream groups to get one too.
+
+ // Update the group iterators with the current row value
+ QValueList<GroupIterator>::iterator it_group = groupIteratorList.begin();
+ while ( it_group != groupIteratorList.end() )
+ {
+ ( *it_group ).update ( *it_row );
+ ++it_group;
+ }
+
+ // Do subtotals backwards
+ if ( m_config.isConvertCurrency() )
+ {
+ it_group = groupIteratorList.fromLast();
+ while ( it_group != groupIteratorList.end() )
+ {
+ if ( ( *it_group ).isSubtotal() )
+ {
+ if ( ( *it_group ).depth() == 1 )
+ grandtotal += ( *it_group ).subtotal();
+ grandtotal = grandtotal.convert(fraction);
+
+ QString subtotal_html = ( *it_group ).subtotal().formatMoney ( fraction );
+ QString subtotal_csv = ( *it_group ).subtotal().formatMoney ( fraction, false );
+
+ // ***DV*** HACK fix the side-effiect from .force() method above
+ QString oldName = QString ( ( *it_group ).oldName() ).stripWhiteSpace();
+
+ result +=
+ "<tr class=\"sectionfooter\">"
+ "<td class=\"left" + QString::number ( ( ( *it_group ).depth() - 1 ) ) + "\" "
+ "colspan=\"" +
+ QString::number ( columns.count() - 1 - postcolumns.count() ) + "\">" +
+ i18n ( "Total" ) + " " + oldName + "</td>"
+ "<td>" + subtotal_html + "</td></tr>\n";
+
+ csv +=
+ "\"" + i18n ( "Total" ) + " " + oldName + "\",\"" + subtotal_csv + "\"\n";
+ }
+ --it_group;
+ }
+ }
+
+ // And headers forwards
+ it_group = groupIteratorList.begin();
+ while ( it_group != groupIteratorList.end() )
+ {
+ if ( ( *it_group ).isNewHeader() )
+ {
+ row_odd = true;
+ result += "<tr class=\"sectionheader\">"
+ "<td class=\"left" + QString::number ( ( ( *it_group ).depth() - 1 ) ) + "\" "
+ "colspan=\"" + QString::number ( columns.count() ) + "\">" +
+ ( *it_group ).name() + "</td></tr>\n";
+ csv += "\"" + ( *it_group ).name() + "\"\n";
+ }
+ ++it_group;
+ }
+
+ //
+ // Columns
+ //
+
+ // skip the opening and closing balance row,
+ // if the balance column is not shown
+ if ( ( columns.contains ( "balance" ) == 0 ) && ( ( *it_row ) ["rank"] == "-2" ) )
+ continue;
+
+ bool need_label = true;
+
+ // ***DV***
+ if ( ( * it_row ) ["rank"] == "0" ) row_odd = ! row_odd;
+
+ if ( ( * it_row ) ["rank"] == "-2" )
+ result += QString ( "<tr class=\"item%1\">" ).arg ( ( * it_row ) ["id"] );
+ else
+ if ( ( * it_row ) ["rank"] == "1" )
+ result += QString ( "<tr class=\"%1\">" ).arg ( row_odd ? "item1" : "item0" );
+ else
+ result += QString ( "<tr class=\"%1\">" ).arg ( row_odd ? "row-odd " : "row-even" );
+
+ QStringList::const_iterator it_column = columns.begin();
+ while ( it_column != columns.end() )
+ {
+ QString data = ( *it_row ) [*it_column];
+
+ // ***DV***
+ if ( ( * it_row ) ["rank"] == "1" ) {
+ if ( * it_column == "value" )
+ data = ( * it_row ) ["split"];
+ else if ( *it_column == "postdate"
+ || *it_column == "number"
+ || *it_column == "payee"
+ || *it_column == "action"
+ || *it_column == "shares"
+ || *it_column == "price"
+ || *it_column == "nextduedate"
+ || *it_column == "balance"
+ || *it_column == "account"
+ || *it_column == "name" )
+ data = "";
+ }
+
+ // ***DV***
+ if ( ( * it_row ) ["rank"] == "-2" ) {
+ if ( *it_column == "balance" ) {
+ data = ( * it_row ) ["balance"];
+ if ( ( * it_row ) ["id"] == "A" ) // opening balance?
+ startingBalance = MyMoneyMoney ( data );
+ }
+
+ if ( need_label ) {
+ if ( ( * it_column == "payee" ) ||
+ ( * it_column == "category" ) ||
+ ( * it_column == "memo" ) ) {
+ if ( ( * it_row ) ["shares"] != "" ) {
+ data = ( ( * it_row ) ["id"] == "A" )
+ ? i18n ( "Initial Market Value" )
+ : i18n ( "Ending Market Value" );
+ } else {
+ data = ( ( * it_row ) ["id"] == "A" )
+ ? i18n ( "Opening Balance" )
+ : i18n ( "Closing Balance" );
+ }
+ need_label = false;
+ }
+ }
+ }
+
+ // The 'balance' column is calculated at render-time
+ // but not printed on split lines
+ else if ( *it_column == "balance" && ( * it_row ) ["rank"] == "0" )
+ {
+ // Take the balance off the deepest group iterator
+ data = ( groupIteratorList.back().currenttotal() + startingBalance ).toString();
+ }
+
+ // Figure out how to render the value in this column, depending on
+ // what its properties are.
+ //
+ // TODO: This and the i18n headings are handled
+ // as a set of parallel vectors. Would be much better to make a single
+ // vector of a properties class.
+ if ( sharesColumns.contains ( *it_column ) )
+ {
+ if ( data.isEmpty() ) {
+ result += QString ( "<td></td>" );
+ csv += "\"\",";
+ }
+ else {
+ result += QString ( "<td>%1</td>" ).arg ( MyMoneyMoney ( data ).formatMoney ( "", 3 ) );
+ csv += "\"" + MyMoneyMoney ( data ).formatMoney ( "", 3, false ) + "\",";
+ }
+ }
+ else if ( moneyColumns.contains ( *it_column ) )
+ {
+ if ( data.isEmpty() ) {
+ result += QString ( "<td%1></td>" )
+ .arg ( ( *it_column == "value" ) ? " class=\"value\"" : "" );
+ csv += "\"\",";
+ } else if ( MyMoneyMoney( data ) == MyMoneyMoney::autoCalc ) {
+ result += QString ( "<td%1>%2</td>" )
+ .arg ( ( *it_column == "value" ) ? " class=\"value\"" : "" )
+ .arg (i18n("Calculated"));
+ csv += "\""+ i18n("Calculated") +"\",";
+ } else if ( *it_column == "price" ) {
+ result += QString ( "<td>%2</td>" )
+ .arg ( MyMoneyMoney ( data ).formatMoney ( MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()) ) );
+ csv += "\"" + ( *it_row ) ["currency"] + " " + MyMoneyMoney ( data ).formatMoney ( MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()), false ) + "\",";
+ } else {
+ result += QString ( "<td%1>%2&nbsp;%3</td>" )
+ .arg ( ( *it_column == "value" ) ? " class=\"value\"" : "" )
+ .arg ( ( *it_row ) ["currency"] )
+ .arg ( MyMoneyMoney ( data ).formatMoney ( fraction ) );
+ csv += "\"" + ( *it_row ) ["currency"] + " " + MyMoneyMoney ( data ).formatMoney ( fraction, false ) + "\",";
+ }
+ }
+ else if ( percentColumns.contains ( *it_column ) )
+ {
+ data = ( MyMoneyMoney ( data ) * MyMoneyMoney ( 100, 1 ) ).formatMoney ( fraction );
+ result += QString ( "<td>%1%</td>" ).arg ( data );
+ csv += data + "%,";
+ }
+ else if ( dateColumns.contains ( *it_column ) )
+ {
+ // do this before we possibly change data
+ csv += "\"" + data + "\",";
+
+ // if we have a locale() then use its date formatter
+ if ( KGlobal::locale() && ! data.isEmpty() ) {
+ QDate qd = QDate::fromString ( data, Qt::ISODate );
+ data = KGlobal::locale()->formatDate ( qd, true );
+ }
+ result += QString ( "<td class=\"left\">%1</td>" ).arg ( data );
+ }
+ else
+ {
+ result += QString ( "<td class=\"left\">%1</td>" ).arg ( data );
+ csv += "\"" + data + "\",";
+ }
+ ++it_column;
+ }
+
+ result += "</tr>\n";
+ csv = csv.left ( csv.length() - 1 ); // remove final comma
+ csv += "\n";
+ }
+
+ //
+ // Final group totals
+ //
+
+ // Do subtotals backwards
+ if ( m_config.isConvertCurrency() )
+ {
+ int fraction = file->baseCurrency().smallestAccountFraction();
+ QValueList<GroupIterator>::iterator it_group = groupIteratorList.fromLast();
+ while ( it_group != groupIteratorList.end() )
+ {
+ ( *it_group ).update ( TableRow() );
+
+ if ( ( *it_group ).depth() == 1 ) {
+ grandtotal += ( *it_group ).subtotal();
+ grandtotal = grandtotal.convert(fraction);
+ }
+
+
+ QString subtotal_html = ( *it_group ).subtotal().formatMoney ( fraction );
+ QString subtotal_csv = ( *it_group ).subtotal().formatMoney ( fraction, false );
+
+ result += "<tr class=\"sectionfooter\">"
+ "<td class=\"left" + QString::number ( ( *it_group ).depth() - 1 ) + "\" "
+ "colspan=\"" + QString::number ( columns.count() - 1 - postcolumns.count() ) + "\">" +
+ i18n ( "Total" ) + " " + ( *it_group ).oldName() + "</td>"
+ "<td>" + subtotal_html + "</td></tr>\n";
+ csv += "\"" + i18n ( "Total" ) + " " + ( *it_group ).oldName() + "\",\"" + subtotal_csv + "\"\n";
+ --it_group;
+ }
+
+ //
+ // Grand total
+ //
+
+ QString grandtotal_html = grandtotal.formatMoney ( fraction );
+ QString grandtotal_csv = grandtotal.formatMoney ( fraction, false );
+
+ result += "<tr class=\"sectionfooter\">"
+ "<td class=\"left0\" "
+ "colspan=\"" + QString::number ( columns.count() - 1 - postcolumns.count() ) + "\">" +
+ i18n ( "Grand Total" ) + "</td>"
+ "<td>" + grandtotal_html + "</td></tr>\n";
+ csv += "\"" + i18n ( "Grand Total" ) + "\",\"" + grandtotal_csv + "\"\n";
+ }
+ result += "</table>\n";
+ }
+
+ QString ListTable::renderHTML ( void ) const
+ {
+ QString html, csv;
+ render ( html, csv );
+ return html;
+ }
+
+ QString ListTable::renderCSV ( void ) const
+ {
+ QString html, csv;
+ render ( html, csv );
+ return csv;
+ }
+
+ void ListTable::dump ( const QString& file, const QString& context ) const
+ {
+ QFile g ( file );
+ g.open ( IO_WriteOnly );
+
+ if ( ! context.isEmpty() )
+ QTextStream ( &g ) << context.arg ( renderHTML() );
+ else
+ QTextStream ( &g ) << renderHTML();
+ g.close();
+ }
+
+ void ListTable::includeInvestmentSubAccounts()
+ {
+ // if we're not in expert mode, we need to make sure
+ // that all stock accounts for the selected investment
+ // account are also selected
+ QStringList accountList;
+ if(m_config.accounts(accountList)) {
+ if(!KMyMoneyGlobalSettings::expertMode()) {
+ QStringList::const_iterator it_a, it_b;
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
+ if(!accountList.contains(*it_b)) {
+ m_config.addAccount(*it_b);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/kmymoney2/reports/listtable.h b/kmymoney2/reports/listtable.h
new file mode 100644
index 0000000..5ffa64d
--- /dev/null
+++ b/kmymoney2/reports/listtable.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+ listtable.h
+ -------------------
+ begin : Sat 28 jun 2008
+ copyright : (C) 2004-2005 by Ace Jones
+ 2008 by Alvaro Soliverez
+ email : acejones@users.sourceforge.net
+ asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef LISTTABLE_H
+#define LISTTABLE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneyreport.h"
+#include "reporttable.h"
+
+namespace reports {
+
+ class ReportAccount;
+
+ /**
+ * Calculates a query of information about the transaction database.
+ *
+ * This is a middle-layer class, between the implementing classes and the engine. The
+ * MyMoneyReport class holds only the CONFIGURATION parameters. This
+ * class has some common methods used by querytable and objectinfo classes
+ *
+ * @author Alvaro Soliverez
+ *
+ * @short
+ **/
+
+ class ListTable : public ReportTable
+ {
+ public:
+ ListTable ( const MyMoneyReport& );
+ QString renderHTML ( void ) const;
+ QString renderCSV ( void ) const;
+ void drawChart ( KReportChartView& ) const {}
+ void dump ( const QString& file, const QString& context = QString() ) const;
+ void init ( void );
+
+ public:
+ /**
+ * Contains a single row in the table.
+ *
+ * Each column is a key/value pair, both strings. This class is just
+ * a QMap with the added ability to specify which columns you'd like to
+ * use as a sort key when you qHeapSort a list of these TableRows
+ */
+ class TableRow: public QMap<QString, QString>
+ {
+ public:
+ bool operator< ( const TableRow& ) const;
+ bool operator<= ( const TableRow& ) const;
+ bool operator> ( const TableRow& ) const;
+ bool operator== ( const TableRow& ) const;
+
+ static void setSortCriteria ( const QString& _criteria ) { m_sortCriteria = QStringList::split ( ",", _criteria ); }
+ private:
+ static QStringList m_sortCriteria;
+ };
+
+ QValueList<TableRow> rows() {return m_rows;};
+
+ protected:
+ void render ( QString&, QString& ) const;
+
+ /**
+ * If not in expert mode, include all subaccounts for each selected
+ * investment account
+ */
+ void includeInvestmentSubAccounts(void);
+
+ QValueList<TableRow> m_rows;
+
+ QString m_group;
+ /**
+ * Comma-separated list of columns to place BEFORE the subtotal column
+ */
+ QString m_columns;
+ /**
+ * Name of the subtotal column
+ */
+ QString m_subtotal;
+ /**
+ * Comma-separated list of columns to place AFTER the subtotal column
+ */
+ QString m_postcolumns;
+ QString m_summarize;
+ QString m_propagate;
+
+ MyMoneyReport m_config;
+
+
+ };
+
+}
+
+#endif
+
diff --git a/kmymoney2/reports/objectinfotable.cpp b/kmymoney2/reports/objectinfotable.cpp
new file mode 100644
index 0000000..649f6c2
--- /dev/null
+++ b/kmymoney2/reports/objectinfotable.cpp
@@ -0,0 +1,368 @@
+/***************************************************************************
+ objectinfotable.cpp
+ -------------------
+ begin : Sat 28 jun 2008
+ copyright : (C) 2004-2005 by Ace Jones
+ 2008 by Alvaro Soliverez
+ email : acejones@users.sourceforge.net
+ asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qvaluelist.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// This is just needed for i18n(). Once I figure out how to handle i18n
+// without using this macro directly, I'll be freed of KDE dependency.
+
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneyexception.h"
+#include "../kmymoneyutils.h"
+#include "reportaccount.h"
+#include "reportdebug.h"
+#include "objectinfotable.h"
+
+namespace reports {
+
+// ****************************************************************************
+//
+// ObjectInfoTable implementation
+//
+// ****************************************************************************
+
+/**
+ * TODO
+ *
+ * - Collapse 2- & 3- groups when they are identical
+ * - Way more test cases (especially splits & transfers)
+ * - Option to collapse splits
+ * - Option to exclude transfers
+ *
+ */
+
+ObjectInfoTable::ObjectInfoTable(const MyMoneyReport& _report): ListTable(_report)
+{
+ // seperated into its own method to allow debugging (setting breakpoints
+ // directly in ctors somehow does not work for me (ipwizard))
+ // TODO: remove the init() method and move the code back to the ctor
+ init();
+}
+
+void ObjectInfoTable::init ( void )
+{
+ switch ( m_config.rowType() )
+ {
+ case MyMoneyReport::eSchedule:
+ constructScheduleTable();
+ m_columns = "nextduedate,name";
+ break;
+ case MyMoneyReport::eAccountInfo:
+ constructAccountTable();
+ m_columns = "institution,type,name";
+ break;
+ case MyMoneyReport::eAccountLoanInfo:
+ constructAccountLoanTable();
+ m_columns = "institution,type,name";
+ break;
+ default:
+ break;
+ }
+
+ // Sort the data to match the report definition
+ m_subtotal="value";
+
+ switch ( m_config.rowType() )
+ {
+ case MyMoneyReport::eSchedule:
+ m_group = "type";
+ m_subtotal="value";
+ break;
+ case MyMoneyReport::eAccountInfo:
+ case MyMoneyReport::eAccountLoanInfo:
+ m_group = "topcategory,institution";
+ m_subtotal="currentbalance";
+ break;
+ default:
+ throw new MYMONEYEXCEPTION ( "ObjectInfoTable::ObjectInfoTable(): unhandled row type" );
+ }
+
+ QString sort = m_group + "," + m_columns + ",id,rank";
+
+ switch ( m_config.rowType() ) {
+ case MyMoneyReport::eSchedule:
+ if ( m_config.detailLevel() == MyMoneyReport::eDetailAll ) {
+ m_columns="name,payee,paymenttype,occurence,nextduedate,category";
+ } else {
+ m_columns="name,payee,paymenttype,occurence,nextduedate";
+ }
+ break;
+ case MyMoneyReport::eAccountInfo:
+ m_columns="type,name,number,description,openingdate,currencyname,balancewarning,maxbalancelimit,creditwarning,maxcreditlimit,tax,favorite";
+ break;
+ case MyMoneyReport::eAccountLoanInfo:
+ m_columns="type,name,number,description,openingdate,currencyname,payee,loanamount,interestrate,nextinterestchange,periodicpayment,finalpayment,favorite";
+ break;
+ default:
+ m_columns = "";
+ }
+
+ TableRow::setSortCriteria ( sort );
+ qHeapSort ( m_rows );
+}
+
+void ObjectInfoTable::constructScheduleTable ( void )
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneySchedule> schedules;
+
+ schedules = file->scheduleList ( "", MyMoneySchedule::TYPE_ANY, MyMoneySchedule::OCCUR_ANY, MyMoneySchedule::STYPE_ANY, m_config.fromDate(), m_config.toDate() );
+
+ QValueList<MyMoneySchedule>::const_iterator it_schedule = schedules.begin();
+ while ( it_schedule != schedules.end() )
+ {
+ MyMoneySchedule schedule = *it_schedule;
+
+ ReportAccount account = schedule.account();
+
+ if ( m_config.includes ( account ) ) {
+ //get fraction for account
+ int fraction = account.fraction();
+
+ //use base currency fraction if not initialized
+ if ( fraction == -1 )
+ fraction = MyMoneyFile::instance()->baseCurrency().smallestAccountFraction();
+
+ TableRow scheduleRow;
+
+ //convert to base currency if needed
+ MyMoneyMoney xr = MyMoneyMoney(1,1);
+ if (m_config.isConvertCurrency() && account.isForeignCurrency()) {
+ xr = account.baseCurrencyPrice(QDate::currentDate()).reduce();
+ }
+
+ // help for sort and render functions
+ scheduleRow["rank"] = "0";
+
+ //schedule data
+ scheduleRow["id"] = schedule.id();
+ scheduleRow["name"] = schedule.name();
+ scheduleRow["nextduedate"] = schedule.nextDueDate().toString ( Qt::ISODate );
+ scheduleRow["type"] = KMyMoneyUtils::scheduleTypeToString ( schedule.type() );
+ scheduleRow["occurence"] = i18n( schedule.occurenceToString() );
+ scheduleRow["paymenttype"] = KMyMoneyUtils::paymentMethodToString ( schedule.paymentType() );
+
+ //scheduleRow["category"] = account.name();
+
+ //to get the payee we must look into the splits of the transaction
+ MyMoneyTransaction transaction = schedule.transaction();
+ MyMoneySplit split = transaction.splitByAccount ( account.id(), true );
+ scheduleRow["value"] = (split.value() * xr).toString();
+ MyMoneyPayee payee = file->payee ( split.payeeId() );
+ scheduleRow["payee"] = payee.name();
+ m_rows += scheduleRow;
+
+ //the text matches the main split
+ bool transaction_text = m_config.match(&split);
+
+ if ( m_config.detailLevel() == MyMoneyReport::eDetailAll )
+ {
+ //get the information for all splits
+ QValueList<MyMoneySplit> splits = transaction.splits();
+ QValueList<MyMoneySplit>::const_iterator split_it = splits.begin();
+ for ( ;split_it != splits.end(); split_it++ )
+ {
+ TableRow splitRow;
+ ReportAccount splitAcc = ( *split_it ).accountId();
+
+ splitRow["rank"] = "1";
+ splitRow["id"] = schedule.id();
+ splitRow["name"] = schedule.name();
+ splitRow["type"] = KMyMoneyUtils::scheduleTypeToString ( schedule.type() );
+ splitRow["nextduedate"] = schedule.nextDueDate().toString ( Qt::ISODate );
+
+ if ( ( *split_it ).value() == MyMoneyMoney::autoCalc ) {
+ splitRow["split"] = MyMoneyMoney::autoCalc.toString();
+ } else if ( ! splitAcc.isIncomeExpense() ) {
+ splitRow["split"] = ( *split_it ).value().toString();
+ } else {
+ splitRow["split"] = ( - ( *split_it ).value() ).toString();
+ }
+
+ //if it is an assett account, mark it as a transfer
+ if ( ! splitAcc.isIncomeExpense() ) {
+ splitRow["category"] = ( ( * split_it ).value().isNegative() )
+ ? i18n ( "Transfer from %1" ).arg ( splitAcc.fullName() )
+ : i18n ( "Transfer to %1" ).arg ( splitAcc.fullName() );
+ } else {
+ splitRow ["category"] = splitAcc.fullName();
+ }
+
+ //add the split only if it matches the text or it matches the main split
+ if(m_config.match( &(*split_it) )
+ || transaction_text )
+ m_rows += splitRow;
+ }
+ }
+ }
+ ++it_schedule;
+ }
+}
+
+void ObjectInfoTable::constructAccountTable ( void )
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //make sure we have all subaccounts of investment accounts
+ includeInvestmentSubAccounts();
+
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+ while ( it_account != accounts.end() )
+ {
+ TableRow accountRow;
+ ReportAccount account = *it_account;
+
+ if(m_config.includes(account)
+ && account.accountType() != MyMoneyAccount::Stock
+ && !account.isClosed())
+ {
+ MyMoneyMoney value;
+ accountRow["rank"] = "0";
+ accountRow["topcategory"] = KMyMoneyUtils::accountTypeToString(account.accountGroup());
+ accountRow["institution"] = (file->institution(account.institutionId())).name();
+ accountRow["type"] = KMyMoneyUtils::accountTypeToString(account.accountType());
+ accountRow["name"] = account.name();
+ accountRow["number"] = account.number();
+ accountRow["description"] = account.description();
+ accountRow["openingdate"] = account.openingDate().toString( Qt::ISODate );
+ //accountRow["currency"] = (file->currency(account.currencyId())).tradingSymbol();
+ accountRow["currencyname"] = (file->currency(account.currencyId())).name();
+ accountRow["balancewarning"] = account.value("minBalanceEarly");
+ accountRow["maxbalancelimit"] = account.value("minBalanceAbsolute");
+ accountRow["creditwarning"] = account.value("maxCreditEarly");
+ accountRow["maxcreditlimit"] = account.value("maxCreditAbsolute");
+ accountRow["tax"] = account.value("Tax");
+ accountRow["favorite"] = account.value("PreferredAccount");
+
+ //investment accounts show the balances of all its subaccounts
+ if(account.accountType() == MyMoneyAccount::Investment) {
+ value = investmentBalance(account);
+ } else {
+ value = file->balance(account.id());
+ }
+
+ //convert to base currency if needed
+ if (m_config.isConvertCurrency() && account.isForeignCurrency()) {
+ MyMoneyMoney xr = account.baseCurrencyPrice(QDate::currentDate()).reduce();
+ value = value * xr;
+ }
+ accountRow["currentbalance"] = value.toString();
+
+ m_rows += accountRow;
+ }
+ ++it_account;
+ }
+}
+
+void ObjectInfoTable::constructAccountLoanTable ( void )
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+ while ( it_account != accounts.end() )
+ {
+ TableRow accountRow;
+ ReportAccount account = *it_account;
+ MyMoneyAccountLoan loan = *it_account;
+
+ if(m_config.includes(account) &&
+ ( account.accountType() == MyMoneyAccount::Loan
+ || account.accountType() == MyMoneyAccount::AssetLoan )
+ && !account.isClosed())
+ {
+ //convert to base currency if needed
+ MyMoneyMoney xr = MyMoneyMoney(1,1);
+ if (m_config.isConvertCurrency() && account.isForeignCurrency()) {
+ xr = account.baseCurrencyPrice(QDate::currentDate()).reduce();
+ }
+
+ accountRow["rank"] = "0";
+ accountRow["topcategory"] = KMyMoneyUtils::accountTypeToString(account.accountGroup());
+ accountRow["institution"] = (file->institution(account.institutionId())).name();
+ accountRow["type"] = KMyMoneyUtils::accountTypeToString(account.accountType());
+ accountRow["name"] = account.name();
+ accountRow["number"] = account.number();
+ accountRow["description"] = account.description();
+ accountRow["openingdate"] = account.openingDate().toString( Qt::ISODate );
+ //accountRow["currency"] = (file->currency(account.currencyId())).tradingSymbol();
+ accountRow["currencyname"] = (file->currency(account.currencyId())).name();
+ accountRow["payee"] = file->payee(loan.payee()).name();
+ accountRow["loanamount"] = (loan.loanAmount() * xr).toString();
+ accountRow["interestrate"] = (loan.interestRate(QDate::currentDate())/MyMoneyMoney(100,1)*xr).toString();
+ accountRow["nextinterestchange"] = loan.nextInterestChange().toString( Qt::ISODate );
+ accountRow["periodicpayment"] = (loan.periodicPayment() * xr).toString();
+ accountRow["finalpayment"] = (loan.finalPayment() * xr).toString();
+ accountRow["favorite"] = account.value("PreferredAccount");
+
+ MyMoneyMoney value = file->balance(account.id());
+ value = value * xr;
+ accountRow["currentbalance"] = value.toString();
+ m_rows += accountRow;
+ }
+ ++it_account;
+ }
+}
+
+MyMoneyMoney ObjectInfoTable::investmentBalance(const MyMoneyAccount& acc)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyMoney value;
+
+ value = file->balance(acc.id());
+ QValueList<QString>::const_iterator it_a;
+ for(it_a = acc.accountList().begin(); it_a != acc.accountList().end(); ++it_a) {
+ MyMoneyAccount stock = file->account(*it_a);
+ try {
+ MyMoneyMoney val;
+ MyMoneyMoney balance = file->balance(stock.id());
+ MyMoneySecurity security = file->security(stock.currencyId());
+ MyMoneyPrice price = file->price(stock.currencyId(), security.tradingCurrency());
+ val = balance * price.rate(security.tradingCurrency());
+ // adjust value of security to the currency of the account
+ MyMoneySecurity accountCurrency = file->currency(acc.currencyId());
+ val = val * file->price(security.tradingCurrency(), accountCurrency.id()).rate(accountCurrency.id());
+ val = val.convert(acc.fraction());
+ value += val;
+ } catch(MyMoneyException* e) {
+ qWarning("%s", (QString("cannot convert stock balance of %1 to base currency: %2").arg(stock.name(), e->what())).data());
+ delete e;
+ }
+ }
+ return value;
+}
+
+}
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/objectinfotable.h b/kmymoney2/reports/objectinfotable.h
new file mode 100644
index 0000000..0b4ab71
--- /dev/null
+++ b/kmymoney2/reports/objectinfotable.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ objectinfotable.h
+ -------------------
+ begin : Sat 28 jun 2008
+ copyright : (C) 2004-2005 by Ace Jones
+ 2008 by Alvaro Soliverez
+ email : acejones@users.sourceforge.net
+ asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef OBJECTINFOTABLE_H
+#define OBJECTINFOTABLE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneyreport.h"
+#include "listtable.h"
+
+namespace reports {
+
+class ReportAccount;
+
+/**
+ * Calculates a query of information about the transaction database.
+ *
+ * This is a middle-layer class, between the UI and the engine. The
+ * MyMoneyReport class holds only the CONFIGURATION parameters. This
+ * class actually does the work of retrieving the data from the engine
+ * and formatting it for the user.
+ *
+ * @author Ace Jones
+ *
+ * @short
+**/
+
+class ObjectInfoTable : public ListTable
+{
+public:
+ ObjectInfoTable ( const MyMoneyReport& );
+ void init ( void );
+
+protected:
+ void constructScheduleTable ( void );
+ void constructAccountTable ( void );
+ void constructAccountLoanTable ( void );
+
+private:
+ /**
+ * @param acc the investment account
+ * @return the balance in the currency of the investment account
+ */
+ MyMoneyMoney investmentBalance(const MyMoneyAccount& acc);
+};
+
+}
+
+#endif // QUERYREPORT_H
diff --git a/kmymoney2/reports/pivotgrid.cpp b/kmymoney2/reports/pivotgrid.cpp
new file mode 100644
index 0000000..9cdf9b3
--- /dev/null
+++ b/kmymoney2/reports/pivotgrid.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+ pivotgrid.cpp
+ -------------------
+ begin : Mon May 17 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qlayout.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdragobject.h>
+#include <qclipboard.h>
+#include <qapplication.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qfile.h>
+#include <qdom.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// This is just needed for i18n() and weekStartDay().
+// Once I figure out how to handle i18n
+// without using this macro directly, I'll be freed of KDE dependency. This
+// is a minor problem because we use these terms when rendering to HTML,
+// and a more major problem because we need it to translate account types
+// (e.g. MyMoneyAccount::Checkings) into their text representation. We also
+// use that text representation in the core data structure of the report. (Ace)
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcalendarsystem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "pivottable.h"
+#include "reportdebug.h"
+#include "kreportchartview.h"
+#include "../kmymoneyglobalsettings.h"
+
+#include <kmymoney/kmymoneyutils.h>
+
+namespace reports {
+
+ const unsigned PivotOuterGroup::m_kDefaultSortOrder = 100;
+
+ PivotCell::PivotCell(const MyMoneyMoney& value) :
+ MyMoneyMoney(value),
+ m_stockSplit(MyMoneyMoney(1,1))
+ {
+ m_cellUsed |= !value.isZero();
+ }
+
+PivotCell PivotCell::operator += (const PivotCell& right)
+{
+ const MyMoneyMoney& r = static_cast<const MyMoneyMoney&>(right);
+ *this += r;
+ m_postSplit = m_postSplit * right.m_stockSplit;
+ m_stockSplit = m_stockSplit * right.m_stockSplit;
+ m_postSplit += right.m_postSplit;
+ m_cellUsed |= right.m_cellUsed;
+ return *this;
+}
+
+PivotCell PivotCell::operator += (const MyMoneyMoney& value)
+{
+ m_cellUsed |= !value.isZero();
+ if(m_stockSplit != MyMoneyMoney(1,1))
+ m_postSplit += value;
+ else
+ MyMoneyMoney::operator += (value);
+ return *this;
+}
+
+PivotCell PivotCell::stockSplit(const MyMoneyMoney& factor)
+{
+ PivotCell s;
+ s.m_stockSplit = factor;
+ return s;
+}
+
+const QString PivotCell::formatMoney(int fraction, bool showThousandSeparator) const
+{
+ return formatMoney("", MyMoneyMoney::denomToPrec(fraction), showThousandSeparator);
+}
+
+const QString PivotCell::formatMoney(const QString& currency, const int prec, bool showThousandSeparator) const
+{
+ // construct the result
+ MyMoneyMoney res = (*this * m_stockSplit) + m_postSplit;
+ return res.formatMoney(currency, prec, showThousandSeparator);
+}
+
+MyMoneyMoney PivotCell::calculateRunningSum(const MyMoneyMoney& runningSum)
+{
+ MyMoneyMoney::operator += (runningSum);
+ MyMoneyMoney::operator = ((*this * m_stockSplit) + m_postSplit);
+ m_postSplit = MyMoneyMoney(0,1);
+ m_stockSplit = MyMoneyMoney(1,1);
+ return *this;
+}
+
+MyMoneyMoney PivotCell::cellBalance(const MyMoneyMoney& _balance)
+{
+ MyMoneyMoney balance(_balance);
+ balance += *this;
+ balance = (balance * m_stockSplit) + m_postSplit;
+ return balance;
+}
+
+PivotGridRowSet::PivotGridRowSet( unsigned _numcolumns )
+{
+ insert(eActual, PivotGridRow(_numcolumns));
+ insert(eBudget, PivotGridRow(_numcolumns));
+ insert(eBudgetDiff, PivotGridRow(_numcolumns));
+ insert(eForecast, PivotGridRow(_numcolumns));
+ insert(eAverage, PivotGridRow(_numcolumns));
+ insert(ePrice, PivotGridRow(_numcolumns));
+}
+
+PivotGridRowSet PivotGrid::rowSet(QString id)
+{
+
+ //go through the data and get the row that matches the id
+ PivotGrid::iterator it_outergroup = begin();
+ while ( it_outergroup != end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ if(it_row.key().id() == id)
+ return it_row.data();
+
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+ return PivotGridRowSet();
+}
+
+} // namespace
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/pivotgrid.h b/kmymoney2/reports/pivotgrid.h
new file mode 100644
index 0000000..ca7f5ab
--- /dev/null
+++ b/kmymoney2/reports/pivotgrid.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+ pivotgrid.h
+ -------------------
+ begin : Sat May 22 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PIVOTGRID_H
+#define PIVOTGRID_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qmap.h>
+#include <qvaluelist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "reportaccount.h"
+
+namespace reports {
+
+ enum ERowType {eActual, eBudget, eBudgetDiff, eForecast, eAverage, ePrice };
+
+ /**
+ * The fundamental data construct of this class is a 'grid'. It is organized as follows:
+ *
+ * A 'Row' is a row of money values, each column is a month. The first month corresponds to
+ * m_beginDate.
+ *
+ * A 'Row Pair' is two rows of money values. Each column is the SAME month. One row is the
+ * 'actual' values for the period, the other row is the 'budgetted' values for the same
+ * period. For ease of implementation, a Row Pair is implemented as a Row which contains
+ * another Row. The inherited Row is the 'actual', the contained row is the 'Budget'.
+ *
+ * An 'Inner Group' contains a rows for each subordinate account within a single top-level
+ * account. It also contains a mapping from the account descriptor for the subordinate account
+ * to its row data. So if we have an Expense account called "Computers", with sub-accounts called
+ * "Hardware", "Software", and "Peripherals", there will be one Inner Group for "Computers"
+ * which contains three Rows.
+ *
+ * An 'Outer Group' contains Inner Row Groups for all the top-level accounts in a given
+ * account class. Account classes are Expense, Income, Asset, Liability. In the case above,
+ * the "Computers" Inner Group is contained within the "Expense" Outer Group.
+ *
+ * A 'Grid' is the set of all Outer Groups contained in this report.
+ *
+ */
+ class PivotCell: public MyMoneyMoney
+ {
+ public:
+ PivotCell() : m_stockSplit(MyMoneyMoney(1,1)), m_cellUsed(false) {}
+ PivotCell(const MyMoneyMoney& value);
+ static PivotCell stockSplit(const MyMoneyMoney& factor);
+ PivotCell operator += (const PivotCell& right);
+ PivotCell operator += (const MyMoneyMoney& value);
+ const QString formatMoney(int fraction, bool showThousandSeparator = true) const;
+ const QString formatMoney(const QString& currency, const int prec, bool showThousandSeparator = true) const;
+ MyMoneyMoney calculateRunningSum(const MyMoneyMoney& runningSum);
+ MyMoneyMoney cellBalance(const MyMoneyMoney& _balance);
+ bool isUsed(void) const { return m_cellUsed; }
+ private:
+ MyMoneyMoney m_stockSplit;
+ MyMoneyMoney m_postSplit;
+ bool m_cellUsed;
+ };
+ class PivotGridRow: public QValueList<PivotCell>
+ {
+ public:
+
+ PivotGridRow( unsigned _numcolumns = 0 )
+ {
+ if ( _numcolumns )
+ insert( end(), _numcolumns, PivotCell() );
+ }
+ MyMoneyMoney m_total;
+ };
+
+ class PivotGridRowSet: public QMap<ERowType, PivotGridRow>
+ {
+ public:
+ PivotGridRowSet( unsigned _numcolumns = 0 );
+ };
+
+ class PivotInnerGroup: public QMap<ReportAccount,PivotGridRowSet>
+ {
+ public:
+ PivotInnerGroup( unsigned _numcolumns = 0 ): m_total(_numcolumns) {}
+
+ PivotGridRowSet m_total;
+ };
+
+ class PivotOuterGroup: public QMap<QString,PivotInnerGroup>
+ {
+ public:
+ PivotOuterGroup( unsigned _numcolumns = 0, unsigned _sort=m_kDefaultSortOrder, bool _inverted=false): m_total(_numcolumns), m_inverted(_inverted), m_sortOrder(_sort) {}
+ int operator<( const PivotOuterGroup& _right )
+ {
+ if ( m_sortOrder != _right.m_sortOrder )
+ return m_sortOrder < _right.m_sortOrder;
+ else
+ return m_displayName < _right.m_displayName;
+ }
+ PivotGridRowSet m_total;
+
+ // An inverted outergroup means that all values placed in subordinate rows
+ // should have their sign inverted from typical cash-flow notation. Also it
+ // means that when the report is summed, the values should be inverted again
+ // so that the grand total is really "non-inverted outergroup MINUS inverted outergroup".
+ bool m_inverted;
+
+ // The localized name of the group for display in the report. Outergoups need this
+ // independently, because they will lose their association with the TGrid when the
+ // report is rendered.
+ QString m_displayName;
+
+ // lower numbers sort toward the top of the report. defaults to 100, which is a nice
+ // middle-of-the-road value
+ unsigned m_sortOrder;
+
+ // default sort order
+ static const unsigned m_kDefaultSortOrder;
+ };
+ class PivotGrid: public QMap<QString,PivotOuterGroup>
+ {
+ public:
+ PivotGridRowSet rowSet (QString id);
+
+ PivotGridRowSet m_total;
+ };
+
+}
+
+#endif
+// PIVOTGRID_H
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/pivotgridtest.cpp b/kmymoney2/reports/pivotgridtest.cpp
new file mode 100644
index 0000000..397491d
--- /dev/null
+++ b/kmymoney2/reports/pivotgridtest.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+ pivotgridtest.cpp
+ -------------------
+ copyright : (C) 2002-2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/*
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qdom.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+// DOH, mmreport.h uses this without including it!!
+#include "../mymoney/mymoneyaccount.h"
+
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyprice.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneystatement.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+*/
+
+#include "pivotgridtest.h"
+
+#include "reportstestcommon.h"
+
+#define private public
+#include "../reports/pivotgrid.h"
+#undef private
+
+using namespace reports;
+using namespace test;
+
+PivotGridTest::PivotGridTest()
+{
+}
+
+void PivotGridTest::setUp ()
+{
+ storage = new MyMoneySeqAccessMgr;
+ file = MyMoneyFile::instance();
+ file->attachStorage(storage);
+
+ MyMoneyFileTransaction ft;
+ file->addCurrency(MyMoneySecurity("CAD", "Canadian Dollar", "C$"));
+ file->addCurrency(MyMoneySecurity("USD", "US Dollar", "$"));
+ file->addCurrency(MyMoneySecurity("JPY", "Japanese Yen", QChar(0x00A5), 100, 1));
+ file->addCurrency(MyMoneySecurity("GBP", "British Pound", "#"));
+ file->setBaseCurrency(file->currency("USD"));
+
+ MyMoneyPayee payeeTest("Test Payee");
+ file->addPayee(payeeTest);
+ MyMoneyPayee payeeTest2("Thomas Baumgart");
+ file->addPayee(payeeTest2);
+
+ acAsset = (MyMoneyFile::instance()->asset().id());
+ acLiability = (MyMoneyFile::instance()->liability().id());
+ acExpense = (MyMoneyFile::instance()->expense().id());
+ acIncome = (MyMoneyFile::instance()->income().id());
+ acChecking = makeAccount(QString("Checking Account"),MyMoneyAccount::Checkings,moCheckingOpen,QDate(2004,5,15),acAsset);
+ acCredit = makeAccount(QString("Credit Card"),MyMoneyAccount::CreditCard,moCreditOpen,QDate(2004,7,15),acLiability);
+ acSolo = makeAccount(QString("Solo"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acParent = makeAccount(QString("Parent"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acChild = makeAccount(QString("Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent);
+ acForeign = makeAccount(QString("Foreign"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+
+ acSecondChild = makeAccount(QString("Second Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent);
+ acGrandChild1 = makeAccount(QString("Grand Child 1"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild);
+ acGrandChild2 = makeAccount(QString("Grand Child 2"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild);
+
+ MyMoneyInstitution i("Bank of the World","","","","","","");
+ file->addInstitution(i);
+ inBank = i.id();
+ ft.commit();
+}
+
+void PivotGridTest::tearDown ()
+{
+ file->detachStorage(storage);
+ delete storage;
+}
+
+void PivotGridTest::testCellAddValue(void)
+{
+ PivotCell a;
+ CPPUNIT_ASSERT(a == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(1,1));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(0,1).formatMoney("", 2));
+
+ PivotCell b(MyMoneyMoney(13,10));
+ CPPUNIT_ASSERT(b == MyMoneyMoney(13,10));
+ CPPUNIT_ASSERT(b.m_stockSplit == MyMoneyMoney(1,1));
+ CPPUNIT_ASSERT(b.m_postSplit == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(b.formatMoney("", 2) == MyMoneyMoney(13,10).formatMoney("", 2));
+
+ PivotCell s(b);
+ CPPUNIT_ASSERT(s == MyMoneyMoney(13,10));
+ CPPUNIT_ASSERT(s.m_stockSplit == MyMoneyMoney(1,1));
+ CPPUNIT_ASSERT(s.m_postSplit == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(s.formatMoney("", 2) == MyMoneyMoney(13,10).formatMoney("", 2));
+
+ s = PivotCell::stockSplit(MyMoneyMoney(1,2));
+ CPPUNIT_ASSERT(s == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(s.m_stockSplit == MyMoneyMoney(1,2));
+ CPPUNIT_ASSERT(s.m_postSplit == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(s.formatMoney("", 2) == MyMoneyMoney(0,1).formatMoney("", 2));
+
+ a += MyMoneyMoney(1,1);
+ a += MyMoneyMoney(2,1);
+ CPPUNIT_ASSERT(a == MyMoneyMoney(3,1));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(1,1));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(3,1).formatMoney("", 2));
+
+ a += s;
+ CPPUNIT_ASSERT(a == MyMoneyMoney(3,1));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(1,2));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(15,10).formatMoney("", 2));
+
+ a += MyMoneyMoney(3,1);
+ a += MyMoneyMoney(3,1);
+ CPPUNIT_ASSERT(a == MyMoneyMoney(3,1));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(1,2));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(6,1));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(75,10).formatMoney("", 2));
+}
+
+void PivotGridTest::testCellAddCell(void)
+{
+ PivotCell a,b;
+
+ a += MyMoneyMoney(3,1);
+ a += PivotCell::stockSplit(MyMoneyMoney(2,1));
+ a += MyMoneyMoney(4,1);
+
+ CPPUNIT_ASSERT(a == MyMoneyMoney(3,1));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(2,1));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(4,1));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(10,1).formatMoney("", 2));
+
+ b += MyMoneyMoney(4,1);
+ b += PivotCell::stockSplit(MyMoneyMoney(4,1));
+ b += MyMoneyMoney(16,1);
+
+ CPPUNIT_ASSERT(b == MyMoneyMoney(4,1));
+ CPPUNIT_ASSERT(b.m_stockSplit == MyMoneyMoney(4,1));
+ CPPUNIT_ASSERT(b.m_postSplit == MyMoneyMoney(16,1));
+ CPPUNIT_ASSERT(b.formatMoney("", 2) == MyMoneyMoney(32,1).formatMoney("", 2));
+
+ a += b;
+
+ CPPUNIT_ASSERT(a == MyMoneyMoney(3,1));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(8,1));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(48,1));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(72,1).formatMoney("", 2));
+}
+
+void PivotGridTest::testCellRunningSum(void)
+{
+ PivotCell a;
+ MyMoneyMoney runningSum(12,10);
+
+ a += MyMoneyMoney(3,1);
+ a += PivotCell::stockSplit(MyMoneyMoney(125,100));
+ a += MyMoneyMoney(134,10);
+
+ CPPUNIT_ASSERT(a.m_stockSplit != MyMoneyMoney(1,1));
+ CPPUNIT_ASSERT(a.m_postSplit != MyMoneyMoney(0,1));
+
+ runningSum = a.calculateRunningSum(runningSum);
+
+ CPPUNIT_ASSERT(runningSum == MyMoneyMoney(1865,100));
+ CPPUNIT_ASSERT(a.formatMoney("", 2) == MyMoneyMoney(1865,100).formatMoney("", 2));
+ CPPUNIT_ASSERT(a.m_stockSplit == MyMoneyMoney(1,1));
+ CPPUNIT_ASSERT(a.m_postSplit == MyMoneyMoney(0,1));
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/pivotgridtest.h b/kmymoney2/reports/pivotgridtest.h
new file mode 100644
index 0000000..50b6f57
--- /dev/null
+++ b/kmymoney2/reports/pivotgridtest.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ pivotgridtest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.jones@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PIVOTGRIDTEST_H
+#define PIVOTGRIDTEST_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+class PivotGridTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(PivotGridTest);
+ CPPUNIT_TEST(testCellAddValue);
+ CPPUNIT_TEST(testCellAddCell);
+ CPPUNIT_TEST(testCellRunningSum);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ MyMoneyAccount *m;
+
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyFile* file;
+
+public:
+ PivotGridTest();
+ void setUp ();
+ void tearDown ();
+ void testCellAddValue();
+ void testCellAddCell();
+ void testCellRunningSum();
+};
+
+#endif // PIVOTGRIDTEST_H
diff --git a/kmymoney2/reports/pivottable.cpp b/kmymoney2/reports/pivottable.cpp
new file mode 100644
index 0000000..c12ca57
--- /dev/null
+++ b/kmymoney2/reports/pivottable.cpp
@@ -0,0 +1,2604 @@
+/***************************************************************************
+ pivottable.cpp
+ -------------------
+ begin : Mon May 17 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Alvaro Soliverez <asoliverez@gmail.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qlayout.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdragobject.h>
+#include <qclipboard.h>
+#include <qapplication.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qfile.h>
+#include <qdom.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// This is just needed for i18n() and weekStartDay().
+// Once I figure out how to handle i18n
+// without using this macro directly, I'll be freed of KDE dependency. This
+// is a minor problem because we use these terms when rendering to HTML,
+// and a more major problem because we need it to translate account types
+// (e.g. MyMoneyAccount::Checkings) into their text representation. We also
+// use that text representation in the core data structure of the report. (Ace)
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcalendarsystem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "pivottable.h"
+#include "pivotgrid.h"
+#include "reportdebug.h"
+#include "kreportchartview.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../kmymoneyutils.h"
+#include "../mymoney/mymoneyforecast.h"
+
+
+#include <kmymoney/kmymoneyutils.h>
+
+namespace reports {
+
+QString Debug::m_sTabs;
+bool Debug::m_sEnabled = DEBUG_ENABLED_BY_DEFAULT;
+QString Debug::m_sEnableKey;
+
+Debug::Debug( const QString& _name ): m_methodName( _name ), m_enabled( m_sEnabled )
+{
+ if (!m_enabled && _name == m_sEnableKey)
+ m_enabled = true;
+
+ if (m_enabled)
+ {
+ qDebug( "%s%s(): ENTER", m_sTabs.latin1(), m_methodName.latin1() );
+ m_sTabs.append("--");
+ }
+}
+
+Debug::~Debug()
+{
+ if ( m_enabled )
+ {
+ m_sTabs.remove(0,2);
+ qDebug( "%s%s(): EXIT", m_sTabs.latin1(), m_methodName.latin1() );
+
+ if (m_methodName == m_sEnableKey)
+ m_enabled = false;
+ }
+}
+
+void Debug::output( const QString& _text )
+{
+ if ( m_enabled )
+ qDebug( "%s%s(): %s", m_sTabs.latin1(), m_methodName.latin1(), _text.latin1() );
+}
+
+PivotTable::PivotTable( const MyMoneyReport& _config_f ):
+ m_runningSumsCalculated(false),
+ m_config_f( _config_f )
+{
+ init();
+}
+
+void PivotTable::init(void)
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ //
+ // Initialize locals
+ //
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //
+ // Initialize member variables
+ //
+
+ //make sure we have all subaccounts of investment accounts
+ includeInvestmentSubAccounts();
+
+ m_config_f.validDateRange( m_beginDate, m_endDate );
+
+ // If we need to calculate running sums, it does not make sense
+ // to show a row total column
+ if ( m_config_f.isRunningSum() )
+ m_config_f.setShowingRowTotals(false);
+
+ // if this is a months-based report
+ if (! m_config_f.isColumnsAreDays())
+ {
+ // strip out the 'days' component of the begin and end dates.
+ // we're only using these variables to contain year and month.
+ m_beginDate = QDate( m_beginDate.year(), m_beginDate.month(), 1 );
+ m_endDate = QDate( m_endDate.year(), m_endDate.month(), 1 );
+ }
+
+ m_numColumns = columnValue(m_endDate) - columnValue(m_beginDate) + 2;
+
+ //Load what types of row the report is going to show
+ loadRowTypeList();
+
+ //
+ // Initialize outer groups of the grid
+ //
+ if ( m_config_f.rowType() == MyMoneyReport::eAssetLiability )
+ {
+ m_grid.insert(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Asset),PivotOuterGroup(m_numColumns));
+ m_grid.insert(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Liability),PivotOuterGroup(m_numColumns,PivotOuterGroup::m_kDefaultSortOrder,true /* inverted */));
+ }
+ else
+ {
+ m_grid.insert(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Income),PivotOuterGroup(m_numColumns,PivotOuterGroup::m_kDefaultSortOrder-2));
+ m_grid.insert(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Expense),PivotOuterGroup(m_numColumns,PivotOuterGroup::m_kDefaultSortOrder-1,true /* inverted */));
+ //
+ // Create rows for income/expense reports with all accounts included
+ //
+ if(m_config_f.isIncludingUnusedAccounts())
+ createAccountRows();
+ }
+
+ //
+ // Initialize grid totals
+ //
+
+ m_grid.m_total = PivotGridRowSet(m_numColumns);
+
+ //
+ // Get opening balances
+ // (for running sum reports only)
+ //
+
+ if ( m_config_f.isRunningSum() )
+ calculateOpeningBalances();
+
+ //
+ // Calculate budget mapping
+ // (for budget-vs-actual reports only)
+ //
+ if ( m_config_f.hasBudget())
+ calculateBudgetMapping();
+
+ //
+ // Populate all transactions into the row/column pivot grid
+ //
+
+ QValueList<MyMoneyTransaction> transactions;
+ m_config_f.setReportAllSplits(false);
+ m_config_f.setConsiderCategory(true);
+ try {
+ transactions = file->transactionList(m_config_f);
+ } catch(MyMoneyException *e) {
+ qDebug("ERR: %s thrown in %s(%ld)", e->what().data(), e->file().data(), e->line());
+ throw e;
+ }
+ DEBUG_OUTPUT(QString("Found %1 matching transactions").arg(transactions.count()));
+
+
+ // Include scheduled transactions if required
+ if ( m_config_f.isIncludingSchedules() )
+ {
+ // Create a custom version of the report filter, excluding date
+ // We'll use this to compare the transaction against
+ MyMoneyTransactionFilter schedulefilter(m_config_f);
+ schedulefilter.setDateFilter(QDate(),QDate());
+
+ // Get the real dates from the config filter
+ QDate configbegin, configend;
+ m_config_f.validDateRange(configbegin, configend);
+
+ QValueList<MyMoneySchedule> schedules = file->scheduleList();
+ QValueList<MyMoneySchedule>::const_iterator it_schedule = schedules.begin();
+ while ( it_schedule != schedules.end() )
+ {
+ // If the transaction meets the filter
+ MyMoneyTransaction tx = (*it_schedule).transaction();
+ if (!(*it_schedule).isFinished() && schedulefilter.match(tx) )
+ {
+ // Keep the id of the schedule with the transaction so that
+ // we can do the autocalc later on in case of a loan payment
+ tx.setValue("kmm-schedule-id", (*it_schedule).id());
+
+ // Get the dates when a payment will be made within the report window
+ QDate nextpayment = (*it_schedule).adjustedNextPayment(configbegin);
+ if ( nextpayment.isValid() )
+ {
+ // Add one transaction for each date
+ QValueList<QDate> paymentDates = (*it_schedule).paymentDates(nextpayment,configend);
+ QValueList<QDate>::const_iterator it_date = paymentDates.begin();
+ while ( it_date != paymentDates.end() )
+ {
+ //if the payment occurs in the past, enter it tomorrow
+ if(QDate::currentDate() >= *it_date) {
+ tx.setPostDate(QDate::currentDate().addDays(1));
+ } else {
+ tx.setPostDate(*it_date);
+ }
+ if ( tx.postDate() <= configend
+ && tx.postDate() >= configbegin ) {
+ transactions += tx;
+ }
+
+ DEBUG_OUTPUT(QString("Added transaction for schedule %1 on %2").arg((*it_schedule).id()).arg((*it_date).toString()));
+
+ ++it_date;
+ }
+ }
+ }
+
+ ++it_schedule;
+ }
+ }
+
+ // whether asset & liability transactions are actually to be considered
+ // transfers
+ bool al_transfers = ( m_config_f.rowType() == MyMoneyReport::eExpenseIncome ) && ( m_config_f.isIncludingTransfers() );
+
+ //this is to store balance for loan accounts when not included in the report
+ QMap<QString, MyMoneyMoney> loanBalances;
+
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ unsigned colofs = columnValue(m_beginDate) - 1;
+ while ( it_transaction != transactions.end() )
+ {
+ QDate postdate = (*it_transaction).postDate();
+ unsigned column = columnValue(postdate) - colofs;
+
+ MyMoneyTransaction tx = (*it_transaction);
+
+ // check if we need to call the autocalculation routine
+ if(tx.isLoanPayment() && tx.hasAutoCalcSplit() && (tx.value("kmm-schedule-id").length() > 0)) {
+ // make sure to consider any autocalculation for loan payments
+ MyMoneySchedule sched = file->schedule(tx.value("kmm-schedule-id"));
+ const MyMoneySplit& split = tx.amortizationSplit();
+ if(!split.id().isEmpty()) {
+ ReportAccount splitAccount = file->account(split.accountId());
+ MyMoneyAccount::accountTypeE type = splitAccount.accountGroup();
+ QString outergroup = KMyMoneyUtils::accountTypeToString(type);
+
+ //if the account is included in the report, calculate the balance from the cells
+ if(m_config_f.includes( splitAccount )) {
+ loanBalances[splitAccount.id()] = cellBalance(outergroup, splitAccount, column, false);
+ } else {
+ //if it is not in the report and also not in loanBalances, get the balance from the file
+ if(!loanBalances.contains(splitAccount.id())) {
+ QDate dueDate = sched.nextDueDate();
+
+ //if the payment is overdue, use current date
+ if(dueDate < QDate::currentDate())
+ dueDate = QDate::currentDate();
+
+ //get the balance from the file for the date
+ loanBalances[splitAccount.id()] = file->balance(splitAccount.id(), dueDate.addDays(-1));
+ }
+ }
+
+ KMyMoneyUtils::calculateAutoLoan(sched, tx, loanBalances);
+
+ //if the loan split is not included in the report, update the balance for the next occurrence
+ if(!m_config_f.includes( splitAccount )) {
+ QValueList<MyMoneySplit>::ConstIterator it_loanSplits;
+ for(it_loanSplits = tx.splits().begin(); it_loanSplits != tx.splits().end(); ++it_loanSplits) {
+ if((*it_loanSplits).isAmortizationSplit() && (*it_loanSplits).accountId() == splitAccount.id() )
+ loanBalances[splitAccount.id()] = loanBalances[splitAccount.id()] + (*it_loanSplits).shares();
+ }
+ }
+ }
+ }
+
+ QValueList<MyMoneySplit> splits = tx.splits();
+ QValueList<MyMoneySplit>::const_iterator it_split = splits.begin();
+ while ( it_split != splits.end() )
+ {
+ ReportAccount splitAccount = (*it_split).accountId();
+
+ // Each split must be further filtered, because if even one split matches,
+ // the ENTIRE transaction is returned with all splits (even non-matching ones)
+ if ( m_config_f.includes( splitAccount ) && m_config_f.match(&(*it_split)))
+ {
+ // reverse sign to match common notation for cash flow direction, only for expense/income splits
+ MyMoneyMoney reverse(splitAccount.isIncomeExpense() ? -1 : 1, 1);
+
+ MyMoneyMoney value;
+ // the outer group is the account class (major account type)
+ MyMoneyAccount::accountTypeE type = splitAccount.accountGroup();
+ QString outergroup = KMyMoneyUtils::accountTypeToString(type);
+
+ value = (*it_split).shares();
+ bool stockSplit = tx.isStockSplit();
+ if(!stockSplit) {
+ // retrieve the value in the account's underlying currency
+ if(value != MyMoneyMoney::autoCalc) {
+ value = value * reverse;
+ } else {
+ qDebug("PivotTable::PivotTable(): This must not happen");
+ value = MyMoneyMoney(); // keep it 0 so far
+ }
+
+ // Except in the case of transfers on an income/expense report
+ if ( al_transfers && ( type == MyMoneyAccount::Asset || type == MyMoneyAccount::Liability ) )
+ {
+ outergroup = i18n("Transfers");
+ value = -value;
+ }
+ }
+ // add the value to its correct position in the pivot table
+ assignCell( outergroup, splitAccount, column, value, false, stockSplit );
+ }
+ ++it_split;
+ }
+
+ ++it_transaction;
+ }
+
+ //
+ // Get forecast data
+ //
+ if(m_config_f.isIncludingForecast())
+ calculateForecast();
+
+ //
+ //Insert Price data
+ //
+ if(m_config_f.isIncludingPrice())
+ fillBasePriceUnit(ePrice);
+
+ //
+ //Insert Average Price data
+ //
+ if(m_config_f.isIncludingAveragePrice()) {
+ fillBasePriceUnit(eActual);
+ calculateMovingAverage();
+ }
+
+ //
+ // Collapse columns to match column type
+ //
+
+
+ if ( m_config_f.columnPitch() > 1 )
+ collapseColumns();
+
+ //
+ // Calculate the running sums
+ // (for running sum reports only)
+ //
+
+ if ( m_config_f.isRunningSum() )
+ calculateRunningSums();
+
+ //
+ // Calculate Moving Average
+ //
+ if ( m_config_f.isIncludingMovingAverage() )
+ calculateMovingAverage();
+
+ //
+ // Calculate Budget Difference
+ //
+
+ if ( m_config_f.isIncludingBudgetActuals() )
+ calculateBudgetDiff();
+
+ //
+ // Convert all values to the deep currency
+ //
+
+ convertToDeepCurrency();
+
+ //
+ // Convert all values to the base currency
+ //
+
+ if ( m_config_f.isConvertCurrency() )
+ convertToBaseCurrency();
+
+ //
+ // Determine column headings
+ //
+
+ calculateColumnHeadings();
+
+ //
+ // Calculate row and column totals
+ //
+
+ calculateTotals();
+}
+
+void PivotTable::collapseColumns(void)
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ unsigned columnpitch = m_config_f.columnPitch();
+ if ( columnpitch != 1 )
+ {
+ unsigned sourcemonth = (m_config_f.isColumnsAreDays())
+ // use the user's locale to determine the week's start
+ ? (m_beginDate.dayOfWeek() + 8 - KGlobal::locale()->weekStartDay()) % 7
+ : m_beginDate.month();
+ unsigned sourcecolumn = 1;
+ unsigned destcolumn = 1;
+ while ( sourcecolumn < m_numColumns )
+ {
+ if ( sourcecolumn != destcolumn )
+ {
+#if 0
+ // TODO: Clean up this rather inefficient kludge. We really should jump by an entire
+ // destcolumn at a time on RS reports, and calculate the proper sourcecolumn to use,
+ // allowing us to clear and accumulate only ONCE per destcolumn
+ if ( m_config_f.isRunningSum() )
+ clearColumn(destcolumn);
+#endif
+ accumulateColumn(destcolumn,sourcecolumn);
+ }
+
+ if (++sourcecolumn < m_numColumns) {
+ if ((sourcemonth++ % columnpitch) == 0) {
+ if (sourcecolumn != ++destcolumn)
+ clearColumn (destcolumn);
+ }
+ }
+ }
+ m_numColumns = destcolumn + 1;
+ }
+}
+
+void PivotTable::accumulateColumn(unsigned destcolumn, unsigned sourcecolumn)
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ DEBUG_OUTPUT(QString("From Column %1 to %2").arg(sourcecolumn).arg(destcolumn));
+
+ // iterate over outer groups
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ // iterate over inner groups
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ // iterator over rows
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ if ( (*it_row)[eActual].count() <= sourcecolumn )
+ throw new MYMONEYEXCEPTION(QString("Sourcecolumn %1 out of grid range (%2) in PivotTable::accumulateColumn").arg(sourcecolumn).arg((*it_row)[eActual].count()));
+ if ( (*it_row)[eActual].count() <= destcolumn )
+ throw new MYMONEYEXCEPTION(QString("Destcolumn %1 out of grid range (%2) in PivotTable::accumulateColumn").arg(sourcecolumn).arg((*it_row)[eActual].count()));
+
+ (*it_row)[eActual][destcolumn] += (*it_row)[eActual][sourcecolumn];
+ ++it_row;
+ }
+
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::clearColumn(unsigned column)
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ DEBUG_OUTPUT(QString("Column %1").arg(column));
+
+ // iterate over outer groups
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ // iterate over inner groups
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ // iterator over rows
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ if ( (*it_row)[eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::accumulateColumn").arg(column).arg((*it_row)[eActual].count()));
+
+ (*it_row++)[eActual][column] = PivotCell();
+ }
+
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::calculateColumnHeadings(void)
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ // one column for the opening balance
+ m_columnHeadings.append( "Opening" );
+
+ unsigned columnpitch = m_config_f.columnPitch();
+
+ // if this is a days-based report
+ if (m_config_f.isColumnsAreDays())
+ {
+ if ( columnpitch == 1 )
+ {
+ QDate columnDate = m_beginDate;
+ unsigned column = 1;
+ while ( column++ < m_numColumns )
+ {
+ QString heading = KGlobal::locale()->calendar()->monthName(columnDate.month(), columnDate.year(), true) + " " + QString::number(columnDate.day());
+ columnDate = columnDate.addDays(1);
+ m_columnHeadings.append( heading);
+ }
+ }
+ else
+ {
+ QDate day = m_beginDate;
+ QDate prv = m_beginDate;
+
+ // use the user's locale to determine the week's start
+ unsigned dow = (day.dayOfWeek() +8 -KGlobal::locale()->weekStartDay())%7;
+
+ while (day <= m_endDate)
+ {
+ if (((dow % columnpitch) == 0) || (day == m_endDate))
+ {
+ m_columnHeadings.append(QString("%1&nbsp;%2 - %3&nbsp;%4")
+ .arg(KGlobal::locale()->calendar()->monthName(prv.month(), prv.year(), true))
+ .arg(prv.day())
+ .arg(KGlobal::locale()->calendar()->monthName(day.month(), day.year(), true))
+ .arg(day.day()));
+ prv = day.addDays(1);
+ }
+ day = day.addDays(1);
+ dow++;
+ }
+ }
+ }
+
+ // else it's a months-based report
+ else
+ {
+ if ( columnpitch == 12 )
+ {
+ unsigned year = m_beginDate.year();
+ unsigned column = 1;
+ while ( column++ < m_numColumns )
+ m_columnHeadings.append(QString::number(year++));
+ }
+ else
+ {
+ unsigned year = m_beginDate.year();
+ bool includeyear = ( m_beginDate.year() != m_endDate.year() );
+ unsigned segment = ( m_beginDate.month() - 1 ) / columnpitch;
+ unsigned column = 1;
+ while ( column++ < m_numColumns )
+ {
+ QString heading = KGlobal::locale()->calendar()->monthName(1+segment*columnpitch, 2000, true);
+ if ( columnpitch != 1 )
+ heading += "-" + KGlobal::locale()->calendar()->monthName((1+segment)*columnpitch, 2000, true);
+ if ( includeyear )
+ heading += " " + QString::number(year);
+ m_columnHeadings.append( heading);
+ if ( ++segment >= 12/columnpitch )
+ {
+ segment -= 12/columnpitch;
+ ++year;
+ }
+ }
+ }
+ }
+}
+
+void PivotTable::createAccountRows(void)
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+
+ while ( it_account != accounts.end() )
+ {
+ ReportAccount account = *it_account;
+
+ // only include this item if its account group is included in this report
+ // and if the report includes this account
+ if ( m_config_f.includes( *it_account ) )
+ {
+ DEBUG_OUTPUT(QString("Includes account %1").arg(account.name()));
+
+ // the row group is the account class (major account type)
+ QString outergroup = KMyMoneyUtils::accountTypeToString(account.accountGroup());
+ // place into the 'opening' column...
+ assignCell( outergroup, account, 0, MyMoneyMoney() );
+ }
+ ++it_account;
+ }
+}
+
+void PivotTable::calculateOpeningBalances( void )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ // First, determine the inclusive dates of the report. Normally, that's just
+ // the begin & end dates of m_config_f. However, if either of those dates are
+ // blank, we need to use m_beginDate and/or m_endDate instead.
+ QDate from = m_config_f.fromDate();
+ QDate to = m_config_f.toDate();
+ if ( ! from.isValid() )
+ from = m_beginDate;
+ if ( ! to.isValid() )
+ to = m_endDate;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+
+ while ( it_account != accounts.end() )
+ {
+ ReportAccount account = *it_account;
+
+ // only include this item if its account group is included in this report
+ // and if the report includes this account
+ if ( m_config_f.includes( *it_account ) )
+ {
+
+ //do not include account if it is closed and it has no transactions in the report period
+ if(account.isClosed()) {
+ //check if the account has transactions for the report timeframe
+ MyMoneyTransactionFilter filter;
+ filter.addAccount(account.id());
+ filter.setDateFilter(m_beginDate, m_endDate);
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ //if a closed account has no transactions in that timeframe, do not include it
+ if(transactions.size() == 0 ) {
+ DEBUG_OUTPUT(QString("DOES NOT INCLUDE account %1").arg(account.name()));
+ ++it_account;
+ continue;
+ }
+ }
+
+ DEBUG_OUTPUT(QString("Includes account %1").arg(account.name()));
+ // the row group is the account class (major account type)
+ QString outergroup = KMyMoneyUtils::accountTypeToString(account.accountGroup());
+
+ // extract the balance of the account for the given begin date, which is
+ // the opening balance plus the sum of all transactions prior to the begin
+ // date
+
+ // this is in the underlying currency
+ MyMoneyMoney value = file->balance(account.id(), from.addDays(-1));
+
+ // place into the 'opening' column...
+ assignCell( outergroup, account, 0, value );
+ }
+ else
+ {
+ DEBUG_OUTPUT(QString("DOES NOT INCLUDE account %1").arg(account.name()));
+ }
+
+ ++it_account;
+ }
+}
+
+void PivotTable::calculateRunningSums( PivotInnerGroup::iterator& it_row)
+{
+ MyMoneyMoney runningsum = it_row.data()[eActual][0].calculateRunningSum(MyMoneyMoney(0,1));
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ if ( it_row.data()[eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateRunningSums").arg(column).arg(it_row.data()[eActual].count()));
+
+ runningsum = it_row.data()[eActual][column].calculateRunningSum(runningsum);
+
+ ++column;
+ }
+}
+
+void PivotTable::calculateRunningSums( void )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ m_runningSumsCalculated = true;
+
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+#if 0
+ MyMoneyMoney runningsum = it_row.data()[0];
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ if ( it_row.data()[eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateRunningSums").arg(column).arg(it_row.data()[eActual].count()));
+
+ runningsum = ( it_row.data()[eActual][column] += runningsum );
+
+ ++column;
+ }
+#endif
+ calculateRunningSums( it_row );
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+MyMoneyMoney PivotTable::cellBalance(const QString& outergroup, const ReportAccount& _row, unsigned _column, bool budget)
+{
+ if(m_runningSumsCalculated) {
+ qDebug("You must not call PivotTable::cellBalance() after calling PivotTable::calculateRunningSums()");
+ throw new MYMONEYEXCEPTION(QString("You must not call PivotTable::cellBalance() after calling PivotTable::calculateRunningSums()"));
+ }
+
+ // for budget reports, if this is the actual value, map it to the account which
+ // holds its budget
+ ReportAccount row = _row;
+ if ( !budget && m_config_f.hasBudget() )
+ {
+ QString newrow = m_budgetMap[row.id()];
+
+ // if there was no mapping found, then the budget report is not interested
+ // in this account.
+ if ( newrow.isEmpty() )
+ return MyMoneyMoney();
+
+ row = newrow;
+ }
+
+ // ensure the row already exists (and its parental hierarchy)
+ createRow( outergroup, row, true );
+
+ // Determine the inner group from the top-most parent account
+ QString innergroup( row.topParentName() );
+
+ if ( m_numColumns <= _column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of m_numColumns range (%2) in PivotTable::cellBalance").arg(_column).arg(m_numColumns));
+ if ( m_grid[outergroup][innergroup][row][eActual].count() <= _column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::cellBalance").arg(_column).arg(m_grid[outergroup][innergroup][row][eActual].count()));
+
+ MyMoneyMoney balance;
+ if ( budget )
+ balance = m_grid[outergroup][innergroup][row][eBudget][0].cellBalance(MyMoneyMoney());
+ else
+ balance = m_grid[outergroup][innergroup][row][eActual][0].cellBalance(MyMoneyMoney());
+
+ unsigned column = 1;
+ while ( column < _column)
+ {
+ if ( m_grid[outergroup][innergroup][row][eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::cellBalance").arg(column).arg(m_grid[outergroup][innergroup][row][eActual].count()));
+
+ balance = m_grid[outergroup][innergroup][row][eActual][column].cellBalance(balance);
+
+ ++column;
+ }
+
+ return balance;
+}
+
+
+void PivotTable::calculateBudgetMapping( void )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // Only do this if there is at least one budget in the file
+ if ( file->countBudgets() )
+ {
+ // Select a budget
+ //
+ // It will choose the first budget in the list for the start year of the report if no budget is select
+ MyMoneyBudget budget = MyMoneyBudget();
+ //if no budget has been selected
+ if (m_config_f.budget() == "Any" ) {
+ QValueList<MyMoneyBudget> budgets = file->budgetList();
+ QValueList<MyMoneyBudget>::const_iterator budgets_it = budgets.begin();
+ while( budgets_it != budgets.end() ) {
+ //pick the first budget that matches the report start year
+ if( (*budgets_it).budgetStart().year() == QDate::currentDate().year() ) {
+ budget = file->budget( (*budgets_it).id());
+ break;
+ }
+ ++budgets_it;
+ }
+ //if we can't find a matching budget, take the first of the list
+ if( budget.id() == "" )
+ budget = budgets[0];
+
+ //assign the budget to the report
+ m_config_f.setBudget(budget.id(), m_config_f.isIncludingBudgetActuals());
+ } else {
+ //pick the budget selected by the user
+ budget = file->budget( m_config_f.budget());
+ }
+
+ // Dump the budget
+ //kdDebug(2) << "Budget " << budget.name() << ": " << endl;
+
+ // Go through all accounts in the system to build the mapping
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+ while ( it_account != accounts.end() )
+ {
+ //include only the accounts selected for the report
+ if ( m_config_f.includes ( *it_account ) ) {
+ QString id = ( *it_account ).id();
+ QString acid = id;
+
+ // If the budget contains this account outright
+ if ( budget.contains ( id ) )
+ {
+ // Add it to the mapping
+ m_budgetMap[acid] = id;
+ // kdDebug(2) << ReportAccount(acid).debugName() << " self-maps / type =" << budget.account(id).budgetLevel() << endl;
+ }
+ // Otherwise, search for a parent account which includes sub-accounts
+ else
+ {
+ //if includeBudgetActuals, include all accounts regardless of whether in budget or not
+ if ( m_config_f.isIncludingBudgetActuals() ) {
+ m_budgetMap[acid] = id;
+ // kdDebug(2) << ReportAccount(acid).debugName() << " maps to " << ReportAccount(id).debugName() << endl;
+ }
+ do
+ {
+ id = file->account ( id ).parentAccountId();
+ if ( budget.contains ( id ) )
+ {
+ if ( budget.account ( id ).budgetSubaccounts() )
+ {
+ m_budgetMap[acid] = id;
+ // kdDebug(2) << ReportAccount(acid).debugName() << " maps to " << ReportAccount(id).debugName() << endl;
+ break;
+ }
+ }
+ }
+ while ( ! id.isEmpty() );
+ }
+ }
+ ++it_account;
+ } // end while looping through the accounts in the file
+
+ // Place the budget values into the budget grid
+ QValueList<MyMoneyBudget::AccountGroup> baccounts = budget.getaccounts();
+ QValueList<MyMoneyBudget::AccountGroup>::const_iterator it_bacc = baccounts.begin();
+ while ( it_bacc != baccounts.end() )
+ {
+ ReportAccount splitAccount = (*it_bacc).id();
+
+ //include the budget account only if it is included in the report
+ if ( m_config_f.includes ( splitAccount ) ) {
+ MyMoneyAccount::accountTypeE type = splitAccount.accountGroup();
+ QString outergroup = KMyMoneyUtils::accountTypeToString(type);
+
+ // reverse sign to match common notation for cash flow direction, only for expense/income splits
+ MyMoneyMoney reverse((splitAccount.accountType() == MyMoneyAccount::Expense) ? -1 : 1, 1);
+
+ const QMap<QDate, MyMoneyBudget::PeriodGroup>& periods = (*it_bacc).getPeriods();
+ MyMoneyMoney value = (*periods.begin()).amount() * reverse;
+ MyMoneyMoney price = MyMoneyMoney(1,1);
+ unsigned column = 1;
+
+ // based on the kind of budget it is, deal accordingly
+ switch ( (*it_bacc).budgetLevel() )
+ {
+ case MyMoneyBudget::AccountGroup::eYearly:
+ // divide the single yearly value by 12 and place it in each column
+ value /= MyMoneyMoney(12,1);
+ case MyMoneyBudget::AccountGroup::eNone:
+ case MyMoneyBudget::AccountGroup::eMax:
+ case MyMoneyBudget::AccountGroup::eMonthly:
+ // place the single monthly value in each column of the report
+ // only add the value if columns are monthly or longer
+ if(m_config_f.columnType() == MyMoneyReport::eBiMonths
+ || m_config_f.columnType() == MyMoneyReport::eMonths
+ || m_config_f.columnType() == MyMoneyReport::eYears
+ || m_config_f.columnType() == MyMoneyReport::eQuarters) {
+ //value = value * MyMoneyMoney(m_config_f.columnType(), 1);
+
+ QDate budgetDate = budget.budgetStart();
+ while ( column < m_numColumns && budget.budgetStart().addYears(1) > budgetDate ) {
+ //only show budget values if the budget year and the column date match
+ //no currency conversion is done here because that is done for all columns later
+ if(budgetDate > columnDate(column) ) {
+ ++column;
+ } else {
+ if(budgetDate >= m_beginDate.addDays(-m_beginDate.day() + 1)
+ && budgetDate <= m_endDate.addDays(m_endDate.daysInMonth() - m_endDate.day() )
+ && budgetDate > (columnDate(column).addMonths(-m_config_f.columnType()))) {
+ assignCell( outergroup, splitAccount, column, value, true /*budget*/ );
+ }
+ budgetDate = budgetDate.addMonths(1);
+ }
+ }
+ }
+ break;
+ case MyMoneyBudget::AccountGroup::eMonthByMonth:
+ // place each value in the appropriate column
+ // budget periods are supposed to come in order just like columns
+ {
+ QMap<QDate, MyMoneyBudget::PeriodGroup>::const_iterator it_period = periods.begin();
+ while ( it_period != periods.end() && column < m_numColumns)
+ {
+ if((*it_period).startDate() > columnDate(column) ) {
+ ++column;
+ } else {
+ switch(m_config_f.columnType()) {
+ case MyMoneyReport::eYears:
+ case MyMoneyReport::eBiMonths:
+ case MyMoneyReport::eQuarters:
+ case MyMoneyReport::eMonths:
+ {
+ if((*it_period).startDate() >= m_beginDate.addDays(-m_beginDate.day() + 1)
+ && (*it_period).startDate() <= m_endDate.addDays(m_endDate.daysInMonth() - m_endDate.day() )
+ && (*it_period).startDate() > (columnDate(column).addMonths(-m_config_f.columnType()))) {
+ //no currency conversion is done here because that is done for all columns later
+ value = (*it_period).amount() * reverse;
+ assignCell( outergroup, splitAccount, column, value, true /*budget*/ );
+ }
+ ++it_period;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ ++it_bacc;
+ }
+ } // end if there was a budget
+}
+
+void PivotTable::convertToBaseCurrency( void )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ int fraction = MyMoneyFile::instance()->baseCurrency().smallestAccountFraction();
+
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ if ( it_row.data()[eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::convertToBaseCurrency").arg(column).arg(it_row.data()[eActual].count()));
+
+ QDate valuedate = columnDate(column);
+
+ //get base price for that date
+ MyMoneyMoney conversionfactor = it_row.key().baseCurrencyPrice(valuedate);
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ if( m_rowTypeList[i] != eAverage ) {
+ //calculate base value
+ MyMoneyMoney oldval = it_row.data()[ m_rowTypeList[i] ][column];
+ MyMoneyMoney value = (oldval * conversionfactor).reduce();
+
+ //convert to lowest fraction
+ it_row.data()[ m_rowTypeList[i] ][column] = PivotCell(value.convert(fraction));
+
+ DEBUG_OUTPUT_IF(conversionfactor != MyMoneyMoney(1,1) ,QString("Factor of %1, value was %2, now %3").arg(conversionfactor).arg(DEBUG_SENSITIVE(oldval)).arg(DEBUG_SENSITIVE(it_row.data()[m_rowTypeList[i]][column].toDouble())));
+ }
+ }
+
+
+ ++column;
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::convertToDeepCurrency( void )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ if ( it_row.data()[eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::convertToDeepCurrency").arg(column).arg(it_row.data()[eActual].count()));
+
+ QDate valuedate = columnDate(column);
+
+ //get conversion factor for the account and date
+ MyMoneyMoney conversionfactor = it_row.key().deepCurrencyPrice(valuedate);
+
+ //use the fraction relevant to the account at hand
+ int fraction = it_row.key().currency().smallestAccountFraction();
+
+ //use base currency fraction if not initialized
+ if(fraction == -1)
+ fraction = file->baseCurrency().smallestAccountFraction();
+
+ //convert to deep currency
+ MyMoneyMoney oldval = it_row.data()[eActual][column];
+ MyMoneyMoney value = (oldval * conversionfactor).reduce();
+ //reduce to lowest fraction
+ it_row.data()[eActual][column] = PivotCell(value.convert(fraction));
+
+ //convert price data
+ if(m_config_f.isIncludingPrice()) {
+ MyMoneyMoney oldPriceVal = it_row.data()[ePrice][column];
+ MyMoneyMoney priceValue = (oldPriceVal * conversionfactor).reduce();
+ it_row.data()[ePrice][column] = PivotCell(priceValue.convert(10000));
+ }
+
+ DEBUG_OUTPUT_IF(conversionfactor != MyMoneyMoney(1,1) ,QString("Factor of %1, value was %2, now %3").arg(conversionfactor).arg(DEBUG_SENSITIVE(oldval)).arg(DEBUG_SENSITIVE(it_row.data()[eActual][column].toDouble())));
+
+ ++column;
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::calculateTotals( void )
+{
+ //insert the row type that is going to be used
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ m_grid.m_total[ m_rowTypeList[i] ].insert( m_grid.m_total[ m_rowTypeList[i] ].end(), m_numColumns, PivotCell() );
+
+ //
+ // Outer groups
+ //
+
+ // iterate over outer groups
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ (*it_outergroup).m_total[ m_rowTypeList[i] ].insert( (*it_outergroup).m_total[ m_rowTypeList[i] ].end(), m_numColumns, PivotCell() );
+
+ //
+ // Inner Groups
+ //
+
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ (*it_innergroup).m_total[ m_rowTypeList[i] ].insert( (*it_innergroup).m_total[ m_rowTypeList[i] ].end(), m_numColumns, PivotCell() );
+ //
+ // Rows
+ //
+
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ //
+ // Columns
+ //
+
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ if ( it_row.data()[ m_rowTypeList[i] ].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateTotals, row columns").arg(column).arg(it_row.data()[ m_rowTypeList[i] ].count()));
+ if ( (*it_innergroup).m_total[ m_rowTypeList[i] ].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateTotals, inner group totals").arg(column).arg((*it_innergroup).m_total[ m_rowTypeList[i] ].count()));
+
+ //calculate total
+ MyMoneyMoney value = it_row.data()[ m_rowTypeList[i] ][column];
+ (*it_innergroup).m_total[ m_rowTypeList[i] ][column] += value;
+ (*it_row)[ m_rowTypeList[i] ].m_total += value;
+ }
+ ++column;
+ }
+ ++it_row;
+ }
+
+ //
+ // Inner Row Group Totals
+ //
+
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ if ( (*it_innergroup).m_total[ m_rowTypeList[i] ].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateTotals, inner group totals").arg(column).arg((*it_innergroup).m_total[ m_rowTypeList[i] ].count()));
+ if ( (*it_outergroup).m_total[ m_rowTypeList[i] ].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateTotals, outer group totals").arg(column).arg((*it_innergroup).m_total[ m_rowTypeList[i] ].count()));
+
+ //calculate totals
+ MyMoneyMoney value = (*it_innergroup).m_total[ m_rowTypeList[i] ][column];
+ (*it_outergroup).m_total[ m_rowTypeList[i] ][column] += value;
+ (*it_innergroup).m_total[ m_rowTypeList[i] ].m_total += value;
+ }
+ ++column;
+ }
+
+ ++it_innergroup;
+ }
+
+ //
+ // Outer Row Group Totals
+ //
+
+ bool invert_total = (*it_outergroup).m_inverted;
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ if ( m_grid.m_total[ m_rowTypeList[i] ].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::calculateTotals, grid totals").arg(column).arg((*it_innergroup).m_total[ m_rowTypeList[i] ].count()));
+
+ //calculate actual totals
+ MyMoneyMoney value = (*it_outergroup).m_total[ m_rowTypeList[i] ][column];
+ (*it_outergroup).m_total[ m_rowTypeList[i] ].m_total += value;
+
+ //so far the invert only applies to actual and budget
+ if ( invert_total
+ && m_rowTypeList[i] != eBudgetDiff
+ && m_rowTypeList[i] != eForecast)
+ value = -value;
+
+ m_grid.m_total[ m_rowTypeList[i] ][column] += value;
+ }
+ ++column;
+ }
+ ++it_outergroup;
+ }
+
+ //
+ // Report Totals
+ //
+
+ unsigned totalcolumn = 1;
+ while ( totalcolumn < m_numColumns )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ if ( m_grid.m_total[ m_rowTypeList[i] ].count() <= totalcolumn )
+ throw new MYMONEYEXCEPTION(QString("Total column %1 out of grid range (%2) in PivotTable::calculateTotals, grid totals").arg(totalcolumn).arg(m_grid.m_total[ m_rowTypeList[i] ].count()));
+
+ //calculate actual totals
+ MyMoneyMoney value = m_grid.m_total[ m_rowTypeList[i] ][totalcolumn];
+ m_grid.m_total[ m_rowTypeList[i] ].m_total += value;
+ }
+ ++totalcolumn;
+ }
+}
+
+void PivotTable::assignCell( const QString& outergroup, const ReportAccount& _row, unsigned column, MyMoneyMoney value, bool budget, bool stockSplit )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ DEBUG_OUTPUT(QString("Parameters: %1,%2,%3,%4,%5").arg(outergroup).arg(_row.debugName()).arg(column).arg(DEBUG_SENSITIVE(value.toDouble())).arg(budget));
+
+ // for budget reports, if this is the actual value, map it to the account which
+ // holds its budget
+ ReportAccount row = _row;
+ if ( !budget && m_config_f.hasBudget() )
+ {
+ QString newrow = m_budgetMap[row.id()];
+
+ // if there was no mapping found, then the budget report is not interested
+ // in this account.
+ if ( newrow.isEmpty() )
+ return;
+
+ row = newrow;
+ }
+
+ // ensure the row already exists (and its parental hierarchy)
+ createRow( outergroup, row, true );
+
+ // Determine the inner group from the top-most parent account
+ QString innergroup( row.topParentName() );
+
+ if ( m_numColumns <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of m_numColumns range (%2) in PivotTable::assignCell").arg(column).arg(m_numColumns));
+ if ( m_grid[outergroup][innergroup][row][eActual].count() <= column )
+ throw new MYMONEYEXCEPTION(QString("Column %1 out of grid range (%2) in PivotTable::assignCell").arg(column).arg(m_grid[outergroup][innergroup][row][eActual].count()));
+
+ if(!stockSplit) {
+ // Determine whether the value should be inverted before being placed in the row
+ if ( m_grid[outergroup].m_inverted )
+ value = -value;
+
+ // Add the value to the grid cell
+ if ( budget )
+ m_grid[outergroup][innergroup][row][eBudget][column] += value;
+ else
+ m_grid[outergroup][innergroup][row][eActual][column] += value;
+ } else {
+ m_grid[outergroup][innergroup][row][eActual][column] += PivotCell::stockSplit(value);
+ }
+
+}
+
+void PivotTable::createRow( const QString& outergroup, const ReportAccount& row, bool recursive )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ // Determine the inner group from the top-most parent account
+ QString innergroup( row.topParentName() );
+
+ if ( ! m_grid.contains(outergroup) )
+ {
+ DEBUG_OUTPUT(QString("Adding group [%1]").arg(outergroup));
+ m_grid[outergroup] = PivotOuterGroup(m_numColumns);
+ }
+
+ if ( ! m_grid[outergroup].contains(innergroup) )
+ {
+ DEBUG_OUTPUT(QString("Adding group [%1][%2]").arg(outergroup).arg(innergroup));
+ m_grid[outergroup][innergroup] = PivotInnerGroup(m_numColumns);
+ }
+
+ if ( ! m_grid[outergroup][innergroup].contains(row) )
+ {
+ DEBUG_OUTPUT(QString("Adding row [%1][%2][%3]").arg(outergroup).arg(innergroup).arg(row.debugName()));
+ m_grid[outergroup][innergroup][row] = PivotGridRowSet(m_numColumns);
+
+ if ( recursive && !row.isTopLevel() )
+ createRow( outergroup, row.parent(), recursive );
+ }
+}
+
+unsigned PivotTable::columnValue(const QDate& _date) const
+{
+ if (m_config_f.isColumnsAreDays())
+ return (QDate().daysTo(_date));
+ else
+ return (_date.year() * 12 + _date.month());
+}
+
+QDate PivotTable::columnDate(int column) const
+{
+ if (m_config_f.isColumnsAreDays())
+ return m_beginDate.addDays( m_config_f.columnPitch() * column - 1 );
+ else
+ return m_beginDate.addMonths( m_config_f.columnPitch() * column ).addDays(-1);
+}
+
+QString PivotTable::renderCSV( void ) const
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ //
+ // Report Title
+ //
+
+ QString result = QString("\"Report: %1\"\n").arg(m_config_f.name());
+ if ( m_config_f.isConvertCurrency() )
+ result += i18n("All currencies converted to %1\n").arg(MyMoneyFile::instance()->baseCurrency().name());
+ else
+ result += i18n("All values shown in %1 unless otherwise noted\n").arg(MyMoneyFile::instance()->baseCurrency().name());
+
+ //
+ // Table Header
+ //
+
+ result += i18n("Account");
+
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ result += QString(",%1").arg(QString(m_columnHeadings[column++]));
+
+ if ( m_config_f.isShowingRowTotals() )
+ result += QString(",%1").arg(i18n("Total"));
+
+ result += "\n";
+
+ int fraction = MyMoneyFile::instance()->baseCurrency().smallestAccountFraction();
+
+ //
+ // Outer groups
+ //
+
+ // iterate over outer groups
+ PivotGrid::const_iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ //
+ // Outer Group Header
+ //
+
+ result += it_outergroup.key() + "\n";
+
+ //
+ // Inner Groups
+ //
+
+ PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
+ unsigned rownum = 0;
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ //
+ // Rows
+ //
+
+ QString innergroupdata;
+ PivotInnerGroup::const_iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ ReportAccount rowname = it_row.key();
+ int fraction = rowname.currency().smallestAccountFraction();
+
+ //
+ // Columns
+ //
+
+ QString rowdata;
+ unsigned column = 1;
+
+ bool isUsed = false;
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ isUsed |= it_row.data()[ m_rowTypeList[i] ][0].isUsed();
+
+ while ( column < m_numColumns ) {
+ //show columns
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ isUsed |= it_row.data()[ m_rowTypeList[i] ][column].isUsed();
+ rowdata += QString(",\"%1\"").arg(it_row.data()[ m_rowTypeList[i] ][column].formatMoney(fraction, false));
+ }
+ column++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ rowdata += QString(",\"%1\"").arg((*it_row)[ m_rowTypeList[i] ].m_total.formatMoney(fraction, false));
+ }
+
+ //
+ // Row Header
+ //
+
+ if(!rowname.isClosed() || isUsed) {
+ innergroupdata += "\"" + QString().fill(' ',rowname.hierarchyDepth() - 1) + rowname.name();
+
+ // if we don't convert the currencies to the base currency and the
+ // current row contains a foreign currency, then we append the currency
+ // to the name of the account
+ if (!m_config_f.isConvertCurrency() && rowname.isForeignCurrency() )
+ innergroupdata += QString(" (%1)").arg(rowname.currencyId());
+
+ innergroupdata += "\"";
+
+ if ( isUsed )
+ innergroupdata += rowdata;
+
+ innergroupdata += "\n";
+ }
+ ++it_row;
+ }
+
+ //
+ // Inner Row Group Totals
+ //
+
+ bool finishrow = true;
+ QString finalRow;
+ bool isUsed = false;
+ if ( m_config_f.detailLevel() == MyMoneyReport::eDetailAll && ((*it_innergroup).size() > 1 ))
+ {
+ // Print the individual rows
+ result += innergroupdata;
+
+ if ( m_config_f.isShowingColumnTotals() )
+ {
+ // Start the TOTALS row
+ finalRow = i18n("Total");
+ isUsed = true;
+ }
+ else
+ {
+ ++rownum;
+ finishrow = false;
+ }
+ }
+ else
+ {
+ // Start the single INDIVIDUAL ACCOUNT row
+ ReportAccount rowname = (*it_innergroup).begin().key();
+ isUsed |= !rowname.isClosed();
+
+ finalRow = "\"" + QString().fill(' ',rowname.hierarchyDepth() - 1) + rowname.name();
+ if (!m_config_f.isConvertCurrency() && rowname.isForeignCurrency() )
+ finalRow += QString(" (%1)").arg(rowname.currencyId());
+ finalRow += "\"";
+ }
+
+ // Finish the row started above, unless told not to
+ if ( finishrow )
+ {
+ unsigned column = 1;
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ isUsed |= (*it_innergroup).m_total[ m_rowTypeList[i] ][0].isUsed();
+
+ while ( column < m_numColumns )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ isUsed |= (*it_innergroup).m_total[ m_rowTypeList[i] ][column].isUsed();
+ finalRow += QString(",\"%1\"").arg((*it_innergroup).m_total[ m_rowTypeList[i] ][column].formatMoney(fraction, false));
+ }
+ column++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ finalRow += QString(",\"%1\"").arg((*it_innergroup).m_total[ m_rowTypeList[i] ].m_total.formatMoney(fraction, false));
+ }
+
+ finalRow += "\n";
+ }
+
+ if(isUsed)
+ {
+ result += finalRow;
+ ++rownum;
+ }
+ ++it_innergroup;
+ }
+
+ //
+ // Outer Row Group Totals
+ //
+
+ if ( m_config_f.isShowingColumnTotals() )
+ {
+ result += QString("%1 %2").arg(i18n("Total")).arg(it_outergroup.key());
+ unsigned column = 1;
+ while ( column < m_numColumns ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ result += QString(",\"%1\"").arg((*it_outergroup).m_total[ m_rowTypeList[i] ][column].formatMoney(fraction, false));
+
+ column++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ result += QString(",\"%1\"").arg((*it_outergroup).m_total[ m_rowTypeList[i] ].m_total.formatMoney(fraction, false));
+ }
+
+ result += "\n";
+ }
+ ++it_outergroup;
+ }
+
+ //
+ // Report Totals
+ //
+
+ if ( m_config_f.isShowingColumnTotals() )
+ {
+ result += i18n("Grand Total");
+ unsigned totalcolumn = 1;
+ while ( totalcolumn < m_numColumns ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ result += QString(",\"%1\"").arg(m_grid.m_total[ m_rowTypeList[i] ][totalcolumn].formatMoney(fraction, false));
+
+ totalcolumn++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i)
+ result += QString(",\"%1\"").arg(m_grid.m_total[ m_rowTypeList[i] ].m_total.formatMoney(fraction, false));
+ }
+
+ result += "\n";
+ }
+
+ return result;
+}
+
+QString PivotTable::renderHTML( void ) const
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ QString colspan = QString(" colspan=\"%1\"").arg(m_numColumns + 1 + (m_config_f.isShowingRowTotals() ? 1 : 0) );
+
+ //
+ // Report Title
+ //
+
+ QString result = QString("<h2 class=\"report\">%1</h2>\n").arg(m_config_f.name());
+
+ //actual dates of the report
+ result += QString("<div class=\"subtitle\">");
+ result += i18n("Report date range", "%1 through %2").arg(KGlobal::locale()->formatDate(m_config_f.fromDate(), true)).arg(KGlobal::locale()->formatDate(m_config_f.toDate(), true));
+ result += QString("</div>\n");
+ result += QString("<div class=\"gap\">&nbsp;</div>\n");
+
+ //currency conversion message
+ result += QString("<div class=\"subtitle\">");
+ if ( m_config_f.isConvertCurrency() )
+ result += i18n("All currencies converted to %1").arg(MyMoneyFile::instance()->baseCurrency().name());
+ else
+ result += i18n("All values shown in %1 unless otherwise noted").arg(MyMoneyFile::instance()->baseCurrency().name());
+ result += QString("</div>\n");
+ result += QString("<div class=\"gap\">&nbsp;</div>\n");
+
+ // setup a leftborder for better readability of budget vs actual reports
+ QString leftborder;
+ if (m_rowTypeList.size() > 1)
+ leftborder = " class=\"leftborder\"";
+
+ //
+ // Table Header
+ //
+ result += QString("\n\n<table class=\"report\" cellspacing=\"0\">\n"
+ "<thead><tr class=\"itemheader\">\n<th>%1</th>").arg(i18n("Account"));
+
+ QString headerspan;
+ int span = m_rowTypeList.size();
+
+ headerspan = QString(" colspan=\"%1\"").arg(span);
+
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ result += QString("<th%1>%2</th>").arg(headerspan,QString(m_columnHeadings[column++]).replace(QRegExp(" "),"<br>"));
+
+ if ( m_config_f.isShowingRowTotals() )
+ result += QString("<th%1>%2</th>").arg(headerspan).arg(i18n("Total"));
+
+ result += "</tr></thead>\n";
+
+ //
+ // Header for multiple columns
+ //
+ if ( span > 1 )
+ {
+ result += "<tr><td></td>";
+
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ QString lb;
+ if(column != 1)
+ lb = leftborder;
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ result += QString("<td%2>%1</td>")
+ .arg(i18n( m_columnTypeHeaderList[i] ))
+ .arg(i == 0 ? lb : QString() );
+ }
+ column++;
+ }
+ if ( m_config_f.isShowingRowTotals() ) {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ result += QString("<td%2>%1</td>")
+ .arg(i18n( m_columnTypeHeaderList[i] ))
+ .arg(i == 0 ? leftborder : QString() );
+ }
+ }
+ result += "</tr>";
+ }
+
+
+ // Skip the body of the report if the report only calls for totals to be shown
+ if ( m_config_f.detailLevel() != MyMoneyReport::eDetailTotal )
+ {
+ //
+ // Outer groups
+ //
+
+ // Need to sort the outergroups. They can't always be sorted by name. So we create a list of
+ // map iterators, and sort that. Then we'll iterate through the map iterators and use those as
+ // before.
+ //
+ // I hope this doesn't bog the performance of reports, given that we're copying the entire report
+ // data. If this is a perf hit, we could change to storing outergroup pointers, I think.
+ QValueList<PivotOuterGroup> outergroups;
+ PivotGrid::const_iterator it_outergroup_map = m_grid.begin();
+ while ( it_outergroup_map != m_grid.end() )
+ {
+ outergroups.push_back(it_outergroup_map.data());
+
+ // copy the name into the outergroup, because we will now lose any association with
+ // the map iterator
+ outergroups.back().m_displayName = it_outergroup_map.key();
+
+ ++it_outergroup_map;
+ }
+ qHeapSort(outergroups);
+
+ QValueList<PivotOuterGroup>::const_iterator it_outergroup = outergroups.begin();
+ while ( it_outergroup != outergroups.end() )
+ {
+ //
+ // Outer Group Header
+ //
+
+ result += QString("<tr class=\"sectionheader\"><td class=\"left\"%1>%2</td></tr>\n").arg(colspan).arg((*it_outergroup).m_displayName);
+
+ // Skip the inner groups if the report only calls for outer group totals to be shown
+ if ( m_config_f.detailLevel() != MyMoneyReport::eDetailGroup )
+ {
+
+ //
+ // Inner Groups
+ //
+
+ PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
+ unsigned rownum = 0;
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ //
+ // Rows
+ //
+
+ QString innergroupdata;
+ PivotInnerGroup::const_iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ //
+ // Columns
+ //
+
+ QString rowdata;
+ unsigned column = 1;
+ bool isUsed = it_row.data()[eActual][0].isUsed();
+ while ( column < m_numColumns )
+ {
+ QString lb;
+ if(column != 1)
+ lb = leftborder;
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ rowdata += QString("<td%2>%1</td>")
+ .arg(coloredAmount(it_row.data()[ m_rowTypeList[i] ][column]))
+ .arg(i == 0 ? lb : QString());
+
+ isUsed |= it_row.data()[ m_rowTypeList[i] ][column].isUsed();
+ }
+
+ column++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ rowdata += QString("<td%2>%1</td>")
+ .arg(coloredAmount(it_row.data()[ m_rowTypeList[i] ].m_total))
+ .arg(i == 0 ? leftborder : QString());
+ }
+ }
+
+ //
+ // Row Header
+ //
+
+ ReportAccount rowname = it_row.key();
+
+ // don't show closed accounts if they have not been used
+ if(!rowname.isClosed() || isUsed) {
+ innergroupdata += QString("<tr class=\"row-%1\"%2><td%3 class=\"left\" style=\"text-indent: %4.0em\">%5%6</td>")
+ .arg(rownum & 0x01 ? "even" : "odd")
+ .arg(rowname.isTopLevel() ? " id=\"topparent\"" : "")
+ .arg("") //.arg((*it_row).m_total.isZero() ? colspan : "") // colspan the distance if this row will be blank
+ .arg(rowname.hierarchyDepth() - 1)
+ .arg(rowname.name().replace(QRegExp(" "), "&nbsp;"))
+ .arg((m_config_f.isConvertCurrency() || !rowname.isForeignCurrency() )?QString():QString(" (%1)").arg(rowname.currency().id()));
+
+ // Don't print this row if it's going to be all zeros
+ // TODO: Uncomment this, and deal with the case where the data
+ // is zero, but the budget is non-zero
+ //if ( !(*it_row).m_total.isZero() )
+ innergroupdata += rowdata;
+
+ innergroupdata += "</tr>\n";
+ }
+
+ ++it_row;
+ }
+
+ //
+ // Inner Row Group Totals
+ //
+
+ bool finishrow = true;
+ QString finalRow;
+ bool isUsed = false;
+ if ( m_config_f.detailLevel() == MyMoneyReport::eDetailAll && ((*it_innergroup).size() > 1 ))
+ {
+ // Print the individual rows
+ result += innergroupdata;
+
+ if ( m_config_f.isShowingColumnTotals() )
+ {
+ // Start the TOTALS row
+ finalRow = QString("<tr class=\"row-%1\" id=\"subtotal\"><td class=\"left\">&nbsp;&nbsp;%2</td>")
+ .arg(rownum & 0x01 ? "even" : "odd")
+ .arg(i18n("Total"));
+ // don't suppress display of totals
+ isUsed = true;
+ }
+ else {
+ finishrow = false;
+ ++rownum;
+ }
+ }
+ else
+ {
+ // Start the single INDIVIDUAL ACCOUNT row
+ // FIXME: There is a bit of a bug here with class=leftX. There's only a finite number
+ // of classes I can define in the .CSS file, and the user can theoretically nest deeper.
+ // The right solution is to use style=Xem, and calculate X. Let's see if anyone complains
+ // first :) Also applies to the row header case above.
+ // FIXED: I found it in one of my reports and changed it to the proposed method.
+ // This works for me (ipwizard)
+ ReportAccount rowname = (*it_innergroup).begin().key();
+ isUsed |= !rowname.isClosed();
+ finalRow = QString("<tr class=\"row-%1\"%2><td class=\"left\" style=\"text-indent: %3.0em;\">%5%6</td>")
+ .arg(rownum & 0x01 ? "even" : "odd")
+ .arg( m_config_f.detailLevel() == MyMoneyReport::eDetailAll ? "id=\"solo\"" : "" )
+ .arg(rowname.hierarchyDepth() - 1)
+ .arg(rowname.name().replace(QRegExp(" "), "&nbsp;"))
+ .arg((m_config_f.isConvertCurrency() || !rowname.isForeignCurrency() )?QString():QString(" (%1)").arg(rowname.currency().id()));
+ }
+
+ // Finish the row started above, unless told not to
+ if ( finishrow )
+ {
+ unsigned column = 1;
+ isUsed |= (*it_innergroup).m_total[eActual][0].isUsed();
+ while ( column < m_numColumns )
+ {
+ QString lb;
+ if(column != 1)
+ lb = leftborder;
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ finalRow += QString("<td%2>%1</td>")
+ .arg(coloredAmount((*it_innergroup).m_total[ m_rowTypeList[i] ][column]))
+ .arg(i == 0 ? lb : QString());
+ isUsed |= (*it_innergroup).m_total[ m_rowTypeList[i] ][column].isUsed();
+ }
+
+ column++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ finalRow += QString("<td%2>%1</td>")
+ .arg(coloredAmount((*it_innergroup).m_total[ m_rowTypeList[i] ].m_total))
+ .arg(i == 0 ? leftborder : QString());
+ }
+ }
+
+ finalRow += "</tr>\n";
+ if(isUsed) {
+ result += finalRow;
+ ++rownum;
+ }
+ }
+
+ ++it_innergroup;
+
+ } // end while iterating on the inner groups
+
+ } // end if detail level is not "group"
+
+ //
+ // Outer Row Group Totals
+ //
+
+ if ( m_config_f.isShowingColumnTotals() )
+ {
+ result += QString("<tr class=\"sectionfooter\"><td class=\"left\">%1&nbsp;%2</td>").arg(i18n("Total")).arg((*it_outergroup).m_displayName);
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ QString lb;
+ if(column != 1)
+ lb = leftborder;
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ result += QString("<td%2>%1</td>")
+ .arg(coloredAmount((*it_outergroup).m_total[ m_rowTypeList[i] ][column]))
+ .arg(i == 0 ? lb : QString());
+ }
+
+ column++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ result += QString("<td%2>%1</td>")
+ .arg(coloredAmount((*it_outergroup).m_total[ m_rowTypeList[i] ].m_total))
+ .arg(i == 0 ? leftborder : QString());
+ }
+ }
+ result += "</tr>\n";
+ }
+
+ ++it_outergroup;
+
+ } // end while iterating on the outergroups
+
+ } // end if detail level is not "total"
+
+ //
+ // Report Totals
+ //
+
+ if ( m_config_f.isShowingColumnTotals() )
+ {
+ result += QString("<tr class=\"spacer\"><td>&nbsp;</td></tr>\n");
+ result += QString("<tr class=\"reportfooter\"><td class=\"left\">%1</td>").arg(i18n("Grand Total"));
+ unsigned totalcolumn = 1;
+ while ( totalcolumn < m_numColumns )
+ {
+ QString lb;
+ if(totalcolumn != 1)
+ lb = leftborder;
+
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ result += QString("<td%2>%1</td>")
+ .arg(coloredAmount(m_grid.m_total[ m_rowTypeList[i] ][totalcolumn]))
+ .arg(i == 0 ? lb : QString());
+ }
+
+ totalcolumn++;
+ }
+
+ if ( m_config_f.isShowingRowTotals() )
+ {
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ result += QString("<td%2>%1</td>")
+ .arg(coloredAmount(m_grid.m_total[ m_rowTypeList[i] ].m_total))
+ .arg(i == 0 ? leftborder : QString());
+ }
+ }
+
+ result += "</tr>\n";
+ }
+
+ result += QString("<tr class=\"spacer\"><td>&nbsp;</td></tr>\n");
+ result += QString("<tr class=\"spacer\"><td>&nbsp;</td></tr>\n");
+ result += "</table>\n";
+
+ return result;
+}
+
+void PivotTable::dump( const QString& file, const QString& /* context */) const
+{
+ QFile g( file );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << renderHTML();
+ g.close();
+}
+
+#ifdef HAVE_KDCHART
+void PivotTable::drawChart( KReportChartView& _view ) const
+{
+#if 1 // make this "#if 1" if you want to play with the axis settings
+ // not sure if 0 is X and 1 is Y.
+ KDChartAxisParams xAxisParams, yAxisParams;
+ KDChartAxisParams::deepCopy(xAxisParams, _view.params()->axisParams(0));
+ KDChartAxisParams::deepCopy(yAxisParams, _view.params()->axisParams(1));
+
+ // modify axis settings here
+ xAxisParams.setAxisLabelsFontMinSize(12);
+ xAxisParams.setAxisLabelsFontRelSize(20);
+ yAxisParams.setAxisLabelsFontMinSize(12);
+ yAxisParams.setAxisLabelsFontRelSize(20);
+
+ _view.params()->setAxisParams( 0, xAxisParams );
+ _view.params()->setAxisParams( 1, yAxisParams );
+
+#endif
+ _view.params()->setLegendFontRelSize(20);
+ _view.params()->setLegendTitleFontRelSize(24);
+ _view.params()->setLegendTitleText(i18n("Legend"));
+
+ _view.params()->setAxisShowGrid(0,m_config_f.isChartGridLines());
+ _view.params()->setAxisShowGrid(1,m_config_f.isChartGridLines());
+ _view.params()->setPrintDataValues(m_config_f.isChartDataLabels());
+
+ // whether to limit the chart to use series totals only. Used for reports which only
+ // show one dimension (pie).
+ bool seriesTotals = false;
+
+ // whether series (rows) are accounts (true) or months (false). This causes a lot
+ // of complexity in the charts. The problem is that circular reports work best with
+ // an account in a COLUMN, while line/bar prefer it in a ROW.
+ bool accountSeries = true;
+
+ //what values should be shown
+ bool showBudget = m_config_f.hasBudget();
+ bool showForecast = m_config_f.isIncludingForecast();
+ bool showActual = false;
+ if( (m_config_f.isIncludingBudgetActuals()) || ( !showBudget && !showForecast) )
+ showActual = true;
+
+ _view.params()->setLineWidth( m_config_f.chartLineWidth() );
+
+ switch( m_config_f.chartType() )
+ {
+ case MyMoneyReport::eChartNone:
+ case MyMoneyReport::eChartEnd:
+ case MyMoneyReport::eChartLine:
+ _view.params()->setChartType( KDChartParams::Line );
+ _view.params()->setAxisDatasets( 0,0 );
+ break;
+ case MyMoneyReport::eChartBar:
+ _view.params()->setChartType( KDChartParams::Bar );
+ _view.params()->setBarChartSubType( KDChartParams::BarNormal );
+ break;
+ case MyMoneyReport::eChartStackedBar:
+ _view.params()->setChartType( KDChartParams::Bar );
+ _view.params()->setBarChartSubType( KDChartParams::BarStacked );
+ break;
+ case MyMoneyReport::eChartPie:
+ _view.params()->setChartType( KDChartParams::Pie );
+ // Charts should only be 3D if this adds any information
+ _view.params()->setThreeDPies( false );
+ accountSeries = false;
+ seriesTotals = true;
+ break;
+ case MyMoneyReport::eChartRing:
+ _view.params()->setChartType( KDChartParams::Ring );
+ _view.params()->setRelativeRingThickness( true );
+ accountSeries = false;
+ break;
+ }
+
+ // For onMouseOver events, we want to activate mouse tracking
+ _view.setMouseTracking( true );
+
+ //
+ // In KDChart parlance, a 'series' (or row) is an account (or accountgroup, etc)
+ // and an 'item' (or column) is a month
+ //
+ unsigned r;
+ unsigned c;
+ if ( accountSeries )
+ {
+ r = 1;
+ c = m_numColumns - 1;
+ }
+ else
+ {
+ c = 1;
+ r = m_numColumns - 1;
+ }
+ KDChartTableData data( r,c );
+
+ // The KReportChartView widget needs to know whether the legend
+ // corresponds to rows or columns
+ _view.setAccountSeries( accountSeries );
+
+ // Set up X axis labels (ie "abscissa" to use the technical term)
+ QStringList& abscissaNames = _view.abscissaNames();
+ abscissaNames.clear();
+ if ( accountSeries )
+ {
+ unsigned column = 1;
+ while ( column < m_numColumns ) {
+ abscissaNames += QString(m_columnHeadings[column++]).replace("&nbsp;", " ");
+ }
+ }
+ else
+ {
+ // we will set these up while putting in the chart values.
+ }
+
+ switch ( m_config_f.detailLevel() )
+ {
+ case MyMoneyReport::eDetailNone:
+ case MyMoneyReport::eDetailEnd:
+ case MyMoneyReport::eDetailAll:
+ {
+ unsigned rowNum = 0;
+
+ // iterate over outer groups
+ PivotGrid::const_iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+
+ // iterate over inner groups
+ PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ //
+ // Rows
+ //
+ QString innergroupdata;
+ PivotInnerGroup::const_iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ //Do not include investments accounts in the chart because they are merely container of stock and other accounts
+ if( it_row.key().accountType() != MyMoneyAccount::Investment) {
+ //iterate row types
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ //skip the budget difference rowset
+ if(m_rowTypeList[i] != eBudgetDiff ) {
+ rowNum = drawChartRowSet(rowNum, seriesTotals, accountSeries, data, it_row.data(), m_rowTypeList[i]);
+
+ //only show the column type in the header if there is more than one type
+ if(m_rowTypeList.size() > 1) {
+ _view.params()->setLegendText( rowNum-1, m_columnTypeHeaderList[i] + " - " + it_row.key().name() );
+ } else {
+ _view.params()->setLegendText( rowNum-1, it_row.key().name() );
+ }
+ }
+ }
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+ }
+ break;
+
+ case MyMoneyReport::eDetailTop:
+ {
+ unsigned rowNum = 0;
+
+ // iterate over outer groups
+ PivotGrid::const_iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+
+ // iterate over inner groups
+ PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ //iterate row types
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ //skip the budget difference rowset
+ if(m_rowTypeList[i] != eBudgetDiff ) {
+ rowNum = drawChartRowSet(rowNum, seriesTotals, accountSeries, data, (*it_innergroup).m_total, m_rowTypeList[i]);
+
+ //only show the column type in the header if there is more than one type
+ if(m_rowTypeList.size() > 1) {
+ _view.params()->setLegendText( rowNum-1, m_columnTypeHeaderList[i] + " - " + it_innergroup.key() );
+ } else {
+ _view.params()->setLegendText( rowNum-1, it_innergroup.key() );
+ }
+ }
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+ }
+ break;
+
+ case MyMoneyReport::eDetailGroup:
+ {
+ unsigned rowNum = 0;
+
+ // iterate over outer groups
+ PivotGrid::const_iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ //iterate row types
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ //skip the budget difference rowset
+ if(m_rowTypeList[i] != eBudgetDiff ) {
+ rowNum = drawChartRowSet(rowNum, seriesTotals, accountSeries, data, (*it_outergroup).m_total, m_rowTypeList[i]);
+
+ //only show the column type in the header if there is more than one type
+ if(m_rowTypeList.size() > 1) {
+ _view.params()->setLegendText( rowNum-1, m_columnTypeHeaderList[i] + " - " + it_outergroup.key() );
+ } else {
+ _view.params()->setLegendText( rowNum-1, it_outergroup.key() );
+ }
+ }
+ }
+ ++it_outergroup;
+ }
+
+ //if selected, show totals too
+ if (m_config_f.isShowingRowTotals())
+ {
+ //iterate row types
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ //skip the budget difference rowset
+ if(m_rowTypeList[i] != eBudgetDiff ) {
+ rowNum = drawChartRowSet(rowNum, seriesTotals, accountSeries, data, m_grid.m_total, m_rowTypeList[i]);
+
+ //only show the column type in the header if there is more than one type
+ if(m_rowTypeList.size() > 1) {
+ _view.params()->setLegendText( rowNum-1, m_columnTypeHeaderList[i] + " - " + i18n("Total") );
+ } else {
+ _view.params()->setLegendText( rowNum-1, i18n("Total") );
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case MyMoneyReport::eDetailTotal:
+ {
+ unsigned rowNum = 0;
+
+ //iterate row types
+ for(unsigned i = 0; i < m_rowTypeList.size(); ++i) {
+ //skip the budget difference rowset
+ if(m_rowTypeList[i] != eBudgetDiff ) {
+ rowNum = drawChartRowSet(rowNum, seriesTotals, accountSeries, data, m_grid.m_total, m_rowTypeList[i]);
+
+ //only show the column type in the header if there is more than one type
+ if(m_rowTypeList.size() > 1) {
+ _view.params()->setLegendText( rowNum-1, m_columnTypeHeaderList[i] + " - " + i18n("Total") );
+ } else {
+ _view.params()->setLegendText( rowNum-1, i18n("Total") );
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ _view.setNewData(data);
+
+ // make sure to show only the required number of fractional digits on the labels of the graph
+ _view.params()->setDataValuesCalc(0, MyMoneyMoney::denomToPrec(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction()));
+ _view.refreshLabels();
+
+#if 0
+ // I have not been able to get this to work (ace)
+
+ //
+ // Set line to dashed for the future
+ //
+
+ if ( accountSeries )
+ {
+ // the first column of report which represents a date in the future, or one past the
+ // last column if all columns are in the present day. Only relevant when accountSeries==true
+ unsigned futurecolumn = columnValue(QDate::currentDate()) - columnValue(m_beginDate) + 1;
+
+ // kdDebug(2) << "futurecolumn: " << futurecolumn << endl;
+ // kdDebug(2) << "m_numColumns: " << m_numColumns << endl;
+
+ // Properties for line charts whose values are in the future.
+ KDChartPropertySet propSetFutureValue("future value", KDChartParams::KDCHART_PROPSET_NORMAL_DATA);
+ propSetFutureValue.setLineStyle(KDChartPropertySet::OwnID, Qt::DotLine);
+ const int idPropFutureValue = _view.params()->registerProperties(propSetFutureValue);
+
+ for(int col = futurecolumn; col < m_numColumns; ++col) {
+ _view.setProperty(0, col, idPropFutureValue);
+ }
+
+ }
+#endif
+}
+#else
+void PivotTable::drawChart( KReportChartView& ) const { }
+#endif
+
+unsigned PivotTable::drawChartRowSet(unsigned rowNum, const bool seriesTotals, const bool accountSeries, KDChartTableData& data, const PivotGridRowSet& rowSet, const ERowType rowType ) const
+{
+ //only add a row if one has been added before
+ // TODO: This is inefficient. Really we should total up how many rows
+ // there will be and allocate it all at once.
+ if(rowNum > 0) {
+ if ( accountSeries )
+ data.expand( rowNum+1, m_numColumns-1 );
+ else
+ data.expand( m_numColumns-1, rowNum+1 );
+ }
+
+ // Columns
+ if ( seriesTotals )
+ {
+ if ( accountSeries )
+ data.setCell( rowNum, 0, rowSet[rowType].m_total.toDouble() );
+ else
+ data.setCell( 0, rowNum, rowSet[rowType].m_total.toDouble() );
+ }
+ else
+ {
+ unsigned column = 1;
+ while ( column < m_numColumns )
+ {
+ if ( accountSeries )
+ data.setCell( rowNum, column-1, rowSet[rowType][column].toDouble() );
+ else
+ data.setCell( column-1, rowNum, rowSet[rowType][column].toDouble() );
+ ++column;
+ }
+ }
+
+ return ++rowNum;
+}
+
+QString PivotTable::coloredAmount(const MyMoneyMoney& amount, const QString& currencySymbol, int prec) const
+{
+ QString result;
+ if( amount.isNegative() )
+ result += QString("<font color=\"rgb(%1,%2,%3)\">")
+ .arg(KMyMoneyGlobalSettings::listNegativeValueColor().red())
+ .arg(KMyMoneyGlobalSettings::listNegativeValueColor().green())
+ .arg(KMyMoneyGlobalSettings::listNegativeValueColor().blue());
+ result += amount.formatMoney(currencySymbol, prec);
+ if( amount.isNegative() )
+ result += QString("</font>");
+ return result;
+}
+
+void PivotTable::calculateBudgetDiff(void)
+{
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ unsigned column = 1;
+ switch( it_row.key().accountGroup() )
+ {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Asset:
+ while ( column < m_numColumns ) {
+ it_row.data()[eBudgetDiff][column] = it_row.data()[eActual][column] - it_row.data()[eBudget][column];
+ ++column;
+ }
+ break;
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::Liability:
+ while ( column < m_numColumns ) {
+ it_row.data()[eBudgetDiff][column] = it_row.data()[eBudget][column] - it_row.data()[eActual][column];
+ ++column;
+ }
+ break;
+ default:
+ break;
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+
+}
+
+void PivotTable::calculateForecast(void)
+{
+ //setup forecast
+ MyMoneyForecast forecast;
+
+ //setup forecast settings
+
+ //since this is a net worth forecast we want to include all account even those that are not in use
+ forecast.setIncludeUnusedAccounts(true);
+
+ //setup forecast dates
+ if(m_endDate > QDate::currentDate()) {
+ forecast.setForecastEndDate(m_endDate);
+ forecast.setForecastStartDate(QDate::currentDate());
+ forecast.setForecastDays(QDate::currentDate().daysTo(m_endDate));
+ } else {
+ forecast.setForecastStartDate(m_beginDate);
+ forecast.setForecastEndDate(m_endDate);
+ forecast.setForecastDays(m_beginDate.daysTo(m_endDate) + 1);
+ }
+
+ //adjust history dates if beginning date is before today
+ if(m_beginDate < QDate::currentDate()) {
+ forecast.setHistoryEndDate(m_beginDate.addDays(-1));
+ forecast.setHistoryStartDate(forecast.historyEndDate().addDays(-forecast.accountsCycle()*forecast.forecastCycles()));
+ }
+
+ //run forecast
+ forecast.doForecast();
+
+ //go through the data and add forecast
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ unsigned column = 1;
+ QDate forecastDate = m_beginDate;
+ //check whether columns are days or months
+ if(m_config_f.isColumnsAreDays())
+ {
+ while(column < m_numColumns) {
+ it_row.data()[eForecast][column] = forecast.forecastBalance(it_row.key(), forecastDate);
+
+ forecastDate = forecastDate.addDays(1);
+ ++column;
+ }
+ } else {
+ //if columns are months
+ while(column < m_numColumns) {
+ //set forecastDate to last day of each month
+ //TODO we really need a date manipulation util
+ forecastDate = QDate(forecastDate.year(), forecastDate.month(), forecastDate.daysInMonth());
+ //check that forecastDate is not over ending date
+ if(forecastDate > m_endDate)
+ forecastDate = m_endDate;
+
+ //get forecast balance and set the corresponding column
+ it_row.data()[eForecast][column] = forecast.forecastBalance(it_row.key(), forecastDate);
+
+ forecastDate = forecastDate.addDays(1);
+ ++column;
+ }
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::loadRowTypeList()
+{
+ if( (m_config_f.isIncludingBudgetActuals()) ||
+ ( !m_config_f.hasBudget()
+ && !m_config_f.isIncludingForecast()
+ && !m_config_f.isIncludingMovingAverage()
+ && !m_config_f.isIncludingPrice()
+ && !m_config_f.isIncludingAveragePrice())
+ ) {
+ m_rowTypeList.append(eActual);
+ m_columnTypeHeaderList.append(i18n("Actual"));
+ }
+
+ if (m_config_f.hasBudget()) {
+ m_rowTypeList.append(eBudget);
+ m_columnTypeHeaderList.append(i18n("Budget"));
+ }
+
+ if(m_config_f.isIncludingBudgetActuals()) {
+ m_rowTypeList.append(eBudgetDiff);
+ m_columnTypeHeaderList.append(i18n("Difference"));
+ }
+
+ if(m_config_f.isIncludingForecast()) {
+ m_rowTypeList.append(eForecast);
+ m_columnTypeHeaderList.append(i18n("Forecast"));
+ }
+
+ if(m_config_f.isIncludingMovingAverage()) {
+ m_rowTypeList.append(eAverage);
+ m_columnTypeHeaderList.append(i18n("Moving Average"));
+ }
+
+ if(m_config_f.isIncludingAveragePrice()) {
+ m_rowTypeList.append(eAverage);
+ m_columnTypeHeaderList.append(i18n("Moving Average Price"));
+ }
+
+ if(m_config_f.isIncludingPrice()) {
+ m_rowTypeList.append(ePrice);
+ m_columnTypeHeaderList.append(i18n("Price"));
+ }
+}
+
+
+void PivotTable::calculateMovingAverage (void)
+{
+ int delta = m_config_f.movingAverageDays()/2;
+
+ //go through the data and add the moving average
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ unsigned column = 1;
+
+ //check whether columns are days or months
+ if(m_config_f.columnType() == MyMoneyReport::eDays) {
+ while(column < m_numColumns) {
+ MyMoneyMoney totalPrice = MyMoneyMoney( 0, 1 );
+
+ QDate averageStart = columnDate(column).addDays(-delta);
+ QDate averageEnd = columnDate(column).addDays(delta);
+ for(QDate averageDate = averageStart; averageDate <= averageEnd; averageDate = averageDate.addDays(1)) {
+ if(m_config_f.isConvertCurrency()) {
+ totalPrice += it_row.key().deepCurrencyPrice(averageDate) * it_row.key().baseCurrencyPrice(averageDate);
+ } else {
+ totalPrice += it_row.key().deepCurrencyPrice(averageDate);
+ }
+ totalPrice = totalPrice.convert(10000);
+ }
+
+ //calculate the average price
+ MyMoneyMoney averagePrice = totalPrice / MyMoneyMoney ((averageStart.daysTo(averageEnd) + 1), 1);
+
+ //get the actual value, multiply by the average price and save that value
+ MyMoneyMoney averageValue = it_row.data()[eActual][column] * averagePrice;
+ it_row.data()[eAverage][column] = averageValue.convert(10000);
+
+ ++column;
+ }
+ } else {
+ //if columns are months
+ while(column < m_numColumns) {
+ QDate averageStart = columnDate(column);
+
+ //set the right start date depending on the column type
+ switch(m_config_f.columnType()) {
+ case MyMoneyReport::eYears:
+ {
+ averageStart = QDate(columnDate(column).year(), 1, 1);
+ break;
+ }
+ case MyMoneyReport::eBiMonths:
+ {
+ averageStart = QDate(columnDate(column).year(), columnDate(column).month(), 1).addMonths(-1);
+ break;
+ }
+ case MyMoneyReport::eQuarters:
+ {
+ averageStart = QDate(columnDate(column).year(), columnDate(column).month(), 1).addMonths(-1);
+ break;
+ }
+ case MyMoneyReport::eMonths:
+ {
+ averageStart = QDate(columnDate(column).year(), columnDate(column).month(), 1);
+ break;
+ }
+ case MyMoneyReport::eWeeks:
+ {
+ averageStart = columnDate(column).addDays(-columnDate(column).dayOfWeek() + 1);
+ break;
+ }
+ default:
+ break;
+ }
+
+ //gather the actual data and calculate the average
+ MyMoneyMoney totalPrice = MyMoneyMoney(0, 1);
+ QDate averageEnd = columnDate(column);
+ for(QDate averageDate = averageStart; averageDate <= averageEnd; averageDate = averageDate.addDays(1)) {
+ if(m_config_f.isConvertCurrency()) {
+ totalPrice += it_row.key().deepCurrencyPrice(averageDate) * it_row.key().baseCurrencyPrice(averageDate);
+ } else {
+ totalPrice += it_row.key().deepCurrencyPrice(averageDate);
+ }
+ totalPrice = totalPrice.convert(10000);
+ }
+
+ MyMoneyMoney averagePrice = totalPrice / MyMoneyMoney ((averageStart.daysTo(averageEnd) + 1), 1);
+ MyMoneyMoney averageValue = it_row.data()[eActual][column] * averagePrice;
+
+ //fill in the average
+ it_row.data()[eAverage][column] = averageValue.convert(10000);
+
+ ++column;
+ }
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::fillBasePriceUnit(ERowType rowType)
+{
+ //go through the data and add forecast
+ PivotGrid::iterator it_outergroup = m_grid.begin();
+ while ( it_outergroup != m_grid.end() )
+ {
+ PivotOuterGroup::iterator it_innergroup = ( *it_outergroup ).begin();
+ while ( it_innergroup != ( *it_outergroup ).end() )
+ {
+ PivotInnerGroup::iterator it_row = ( *it_innergroup ).begin();
+ while ( it_row != ( *it_innergroup ).end() )
+ {
+ unsigned column = 1;
+ while ( column < m_numColumns ) {
+ //insert a unit of currency for each account
+ it_row.data() [rowType][column] = MyMoneyMoney ( 1, 1 );
+ ++column;
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+}
+
+void PivotTable::includeInvestmentSubAccounts()
+{
+ // if we're not in expert mode, we need to make sure
+ // that all stock accounts for the selected investment
+ // account are also selected
+ QStringList accountList;
+ if(m_config_f.accounts(accountList)) {
+ if(!KMyMoneyGlobalSettings::expertMode()) {
+ QStringList::const_iterator it_a, it_b;
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
+ if(!accountList.contains(*it_b)) {
+ m_config_f.addAccount(*it_b);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/pivottable.h b/kmymoney2/reports/pivottable.h
new file mode 100644
index 0000000..226c9a5
--- /dev/null
+++ b/kmymoney2/reports/pivottable.h
@@ -0,0 +1,356 @@
+/***************************************************************************
+ pivottable.h
+ -------------------
+ begin : Sat May 22 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Alvaro Soliverez <asoliverez@gmail.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PIVOTTABLE_H
+#define PIVOTTABLE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qmap.h>
+#include <qvaluelist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kreportchartview.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneyreport.h"
+#include "reporttable.h"
+#include "pivotgrid.h"
+#include "reportaccount.h"
+
+namespace reports {
+
+/**
+ * Calculates a 'pivot table' of information about the transaction database.
+ * Based on pivot tables in MS Excel, and implemented as 'Data Pilot' in
+ * OpenOffice.Org Calc.
+ *
+ * | Month,etc
+ * -------------+------------
+ * Expense Type | Sum(Value)
+ * Category |
+ *
+ * This is a middle-layer class, between the UI and the engine. The
+ * MyMoneyReport class holds only the CONFIGURATION parameters. This
+ * class actually does the work of retrieving the data from the engine
+ * and formatting it for the user.
+ *
+ * @author Ace Jones
+ *
+ * @short
+**/
+class PivotTable : public ReportTable
+{
+public:
+ /**
+ * Create a Pivot table style report
+ *
+ * @param _config_f The configuration parameters for this report
+ */
+ PivotTable( const MyMoneyReport& _config_f );
+
+ /**
+ * virtual Destructur
+ */
+ virtual ~PivotTable() {}
+
+ /**
+ * Render the report to an HTML stream.
+ *
+ * @return QString HTML string representing the report
+ */
+ QString renderHTML( void ) const;
+ /**
+ * Render the report to a comma-separated-values stream.
+ *
+ * @return QString CSV string representing the report
+ */
+ QString renderCSV( void ) const;
+
+ /**
+ * Render the report to a graphical chart
+ *
+ * @param view The KReportChartView into which to draw the chart.
+ */
+ void drawChart( KReportChartView& view ) const;
+
+ /**
+ * Dump the report's HTML to a file
+ *
+ * @param file The filename to dump into
+ * @param context unused, but provided for interface compatibility
+ */
+ void dump( const QString& file, const QString& context=QString()) const;
+
+ /**
+ * Returns the grid generated by the report
+ *
+ */
+ PivotGrid grid(void) {return m_grid;}
+
+protected:
+ void init(void); // used for debugging the constructor
+
+private:
+
+ PivotGrid m_grid;
+
+ QStringList m_columnHeadings;
+ unsigned m_numColumns;
+ QDate m_beginDate;
+ QDate m_endDate;
+ bool m_runningSumsCalculated;
+
+ /**
+ * For budget-vs-actual reports only, maps each account to the account which holds
+ * the budget for it. If an account is not contained in this map, it is not included
+ * in the budget.
+ */
+ QMap<QString, QString> m_budgetMap;
+
+ /**
+ * This list contains the types of PivotGridRows that are going to be shown in the report
+ */
+ QValueList<ERowType> m_rowTypeList;
+
+ /**
+ * This list contains the i18n headers for the column types
+ */
+ QValueList<QString> m_columnTypeHeaderList;
+
+ MyMoneyReport m_config_f;
+
+ /**
+ * This method returns the formatted value of @a amount with
+ * a possible @a currencySymbol added and @a prec fractional digits.
+ * @a currencySymbol defaults to be empty and @a prec defaults to 2.
+ *
+ * If @a amount is negative the formatted value is enclosed in an
+ * HTML font tag to modify the color to reflect the user settings for
+ * negtive numbers.
+ *
+ * Example: 1.23 is returned as '1.23' whereas -1.23 is returned as
+ * @verbatim <font color="rgb($red,$green,$blue)">-1.23</font>@endverbatim
+ * with $red, $green and $blue being the actual value for the
+ * chosen color.
+ */
+ QString coloredAmount(const MyMoneyMoney& amount, const QString& currencySymbol = QString(), int prec = 2 ) const;
+
+protected:
+ /**
+ * Creates a row in the grid if it doesn't already exist
+ *
+ * Downsteam assignment functions will assume that this row already
+ * exists, so this function creates a row of the needed length populated
+ * with zeros.
+ *
+ * @param outergroup The outer row group
+ * @param row The row itself
+ * @param recursive Whether to also recursively create rows for our parent accounts
+ */
+ void createRow( const QString& outergroup, const ReportAccount& row, bool recursive );
+
+ /**
+ * Assigns a value into the grid
+ *
+ * Adds the given value to the value which already exists at the specified grid position
+ *
+ * @param outergroup The outer row group
+ * @param row The row itself
+ * @param column The column
+ * @param value The value to be added in
+ * @param budget Whether this is a budget value (@p true) or an actual
+ * value (@p false). Defaults to @p false.
+ * @param stockSplit Wheter this is a stock split (@p true) or an actual
+ * value (@p false). Defaults to @p false.
+ */
+ inline void assignCell( const QString& outergroup, const ReportAccount& row, unsigned column, MyMoneyMoney value, bool budget = false, bool stockSplit = false );
+
+ /**
+ * Create a row for each included account. This is used when
+ * the config parameter isIncludingUnusedAccount() is true
+ */
+ void createAccountRows(void);
+
+ /**
+ * Record the opening balances of all qualifying accounts into the grid.
+ *
+ * For accounts opened before the report period, places the balance into the '0' column.
+ * For those opened during the report period, places the balance into the appropriate column
+ * for the month when it was opened.
+ */
+ void calculateOpeningBalances( void );
+
+ /**
+ * Calculate budget mapping
+ *
+ * For budget-vs-actual reports, this creates a mapping between each account
+ * in the user's hierarchy and the account where the budget is held for it.
+ * This is needed because the user can budget on a given account for that
+ * account and all its descendants. Also if NO budget is placed on the
+ * account or any of its parents, the account is not included in the map.
+ */
+ void calculateBudgetMapping( void );
+
+ /**
+ * Calculate the running sums.
+ *
+ * After calling this method, each cell of the report will contain the running sum of all
+ * the cells in its row in this and earlier columns.
+ *
+ * For example, consider a row with these values:
+ * 01 02 03 04 05 06 07 08 09 10
+ *
+ * After calling this function, the row will look like this:
+ * 01 03 06 10 15 21 28 36 45 55
+ */
+ void calculateRunningSums( void );
+ void calculateRunningSums( PivotInnerGroup::iterator& it_row);
+
+ /**
+ * This method calculates the difference between a @a budgeted and an @a
+ * actual amount. The calculation is based on the type of the
+ * @a repAccount. The difference value is calculated as follows:
+ *
+ * If @a repAccount is of type MyMoneyAccount::Income
+ *
+ * @code
+ * diff = actual - budgeted
+ * @endcode
+ *
+ * If @a repAccount is of type MyMoneyAccount::Expense
+ *
+ * @code
+ * diff = budgeted - actual
+ * @endcode
+ *
+ * In all other cases, 0 is returned.
+ */
+ void calculateBudgetDiff(void);
+
+ /**
+ * This method calculates forecast for a report
+ */
+ void calculateForecast(void);
+
+ /**
+ * This method inserts units to be used to display prices
+ */
+ void fillBasePriceUnit(ERowType rowType);
+
+ /**
+ * This method calculates moving average for a report
+ */
+ void calculateMovingAverage(void);
+
+ /**
+ * Calculate the row and column totals
+ *
+ * This function will set the m_total members of all the TGrid objects. Be sure the values are
+ * all converted to the base currency first!!
+ *
+ */
+ void calculateTotals( void );
+
+ /**
+ * Convert each value in the grid to the base currency
+ *
+ */
+ void convertToBaseCurrency( void );
+
+ /**
+ * Convert each value in the grid to the account/category's deep currency
+ *
+ * See AccountDescriptor::deepCurrencyPrice() for a description of 'deep' currency
+ *
+ */
+ void convertToDeepCurrency( void );
+
+ /**
+ * Turn month-long columns into larger time periods if needed
+ *
+ * For example, consider a row with these values:
+ * 01 02 03 04 05 06 07 08 09 10
+ *
+ * If the column pitch is 3 (i.e. quarterly), after calling this function,
+ * the row will look like this:
+ * 06 15 26 10
+ */
+ void collapseColumns(void);
+
+ /**
+ * Determine the proper column headings based on the time periods covered by each column
+ *
+ */
+ void calculateColumnHeadings(void);
+
+ /**
+ * Helper methods for collapseColumns
+ *
+ */
+ void accumulateColumn(unsigned destcolumn, unsigned sourcecolumn);
+ void clearColumn(unsigned column);
+
+ /**
+ * Calculate the column of a given date. This is the absolute column in a
+ * hypothetical report that covers all of known time. In reality an actual
+ * report will be a subset of that.
+ *
+ * @param _date The date
+ */
+ unsigned columnValue(const QDate& _date) const;
+
+ /**
+ * Calculate the date of the last day covered by a given column.
+ *
+ * @param column The column
+ */
+ QDate columnDate(int column) const;
+
+ /**
+ * Returns the balance of a given cell. Throws an exception once calculateRunningSums() has been run.
+ */
+ MyMoneyMoney cellBalance(const QString& outergroup, const ReportAccount& _row, unsigned column, bool budget);
+
+ /**
+ * Draws a PivotGridRowSet in a chart for the given ERowType
+ */
+ unsigned drawChartRowSet(unsigned rowNum, const bool seriesTotals, const bool accountSeries, KDChartTableData& data, const PivotGridRowSet& rowSet, const ERowType rowType ) const;
+
+ /**
+ * Loads m_rowTypeList with the list of PivotGridRow types that the reporttable
+ * should show
+ */
+ void loadRowTypeList(void);
+
+ /**
+ * If not in expert mode, include all subaccounts for each selected
+ * investment account
+ */
+ void includeInvestmentSubAccounts(void);
+};
+
+
+}
+#endif
+// PIVOTTABLE_H
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/pivottabletest.cpp b/kmymoney2/reports/pivottabletest.cpp
new file mode 100644
index 0000000..a235c0b
--- /dev/null
+++ b/kmymoney2/reports/pivottabletest.cpp
@@ -0,0 +1,1021 @@
+/***************************************************************************
+ pivottabletest.cpp
+ -------------------
+ copyright : (C) 2002-2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qdom.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+// DOH, mmreport.h uses this without including it!!
+#include "../mymoney/mymoneyaccount.h"
+
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyprice.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneystatement.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+
+#define private public
+#include "../reports/pivottable.h"
+#undef private
+
+#include "reportstestcommon.h"
+#include "pivottabletest.h"
+
+using namespace reports;
+using namespace test;
+
+PivotTableTest::PivotTableTest()
+{
+}
+
+void PivotTableTest::setUp ()
+{
+ storage = new MyMoneySeqAccessMgr;
+ file = MyMoneyFile::instance();
+ file->attachStorage(storage);
+
+ MyMoneyFileTransaction ft;
+ file->addCurrency(MyMoneySecurity("CAD", "Canadian Dollar", "C$"));
+ file->addCurrency(MyMoneySecurity("USD", "US Dollar", "$"));
+ file->addCurrency(MyMoneySecurity("JPY", "Japanese Yen", QChar(0x00A5), 100, 1));
+ file->addCurrency(MyMoneySecurity("GBP", "British Pound", "#"));
+ file->setBaseCurrency(file->currency("USD"));
+
+ MyMoneyPayee payeeTest("Test Payee");
+ file->addPayee(payeeTest);
+ MyMoneyPayee payeeTest2("Thomas Baumgart");
+ file->addPayee(payeeTest2);
+
+ acAsset = (MyMoneyFile::instance()->asset().id());
+ acLiability = (MyMoneyFile::instance()->liability().id());
+ acExpense = (MyMoneyFile::instance()->expense().id());
+ acIncome = (MyMoneyFile::instance()->income().id());
+ acChecking = makeAccount(QString("Checking Account"),MyMoneyAccount::Checkings,moCheckingOpen,QDate(2004,5,15),acAsset);
+ acCredit = makeAccount(QString("Credit Card"),MyMoneyAccount::CreditCard,moCreditOpen,QDate(2004,7,15),acLiability);
+ acSolo = makeAccount(QString("Solo"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acParent = makeAccount(QString("Parent"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acChild = makeAccount(QString("Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent);
+ acForeign = makeAccount(QString("Foreign"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+
+ acSecondChild = makeAccount(QString("Second Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent);
+ acGrandChild1 = makeAccount(QString("Grand Child 1"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild);
+ acGrandChild2 = makeAccount(QString("Grand Child 2"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild);
+
+ MyMoneyInstitution i("Bank of the World","","","","","","");
+ file->addInstitution(i);
+ inBank = i.id();
+ ft.commit();
+}
+
+void PivotTableTest::tearDown ()
+{
+ file->detachStorage(storage);
+ delete storage;
+}
+
+void PivotTableTest::testNetWorthSingle()
+{
+ try
+ {
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2004,7,1).addDays(-1));
+ XMLandback(filter);
+ PivotTable networth_f(filter);
+ writeTabletoCSV(networth_f);
+
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Checking Account"][acChecking][eActual][5]==moCheckingOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Checking Account"][acChecking][eActual][6]==moCheckingOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Checking Account"].m_total[eActual][5]==moCheckingOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][0]==moZero);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][4]==moZero);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][5]==moCheckingOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][6]==moCheckingOpen);
+ }
+ catch(MyMoneyException *e)
+ {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+}
+
+void PivotTableTest::testNetWorthOfsetting()
+{
+ // Test the net worth report to make sure it picks up the opening balance for two
+ // accounts opened during the period of the report, one asset & one liability. Test
+ // that it calculates the totals correctly.
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ CPPUNIT_ASSERT(networth_f.m_grid["Liability"]["Credit Card"][acCredit][eActual][7]==-moCreditOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][0]==moZero);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][12]==moCheckingOpen+moCreditOpen);
+
+}
+
+void PivotTableTest::testNetWorthOpeningPrior()
+{
+ // Test the net worth report to make sure it's picking up opening balances PRIOR to
+ // the period of the report.
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ filter.setDateFilter(QDate(2005,8,1),QDate(2005,12,31));
+ filter.setName("Net Worth Opening Prior 1");
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ writeTabletoCSV(networth_f);
+
+ CPPUNIT_ASSERT(networth_f.m_grid["Liability"]["Credit Card"].m_total[eActual][0]==-moCreditOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Checking Account"].m_total[eActual][0]==moCheckingOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][0]==moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][1]==moCheckingOpen+moCreditOpen);
+
+ // Test the net worth report to make sure that transactions prior to the report
+ // period are included in the opening balance
+
+ TransactionHelper t1( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acChecking, acChild );
+
+ filter.setName("Net Worth Opening Prior 2");
+ PivotTable networth_f2( filter );
+ writeTabletoCSV(networth_f2);
+ CPPUNIT_ASSERT(networth_f2.m_grid["Liability"]["Credit Card"].m_total[eActual][1]==-moCreditOpen+moParent);
+ CPPUNIT_ASSERT(networth_f2.m_grid["Asset"]["Checking Account"].m_total[eActual][1]==moCheckingOpen-moChild);
+ CPPUNIT_ASSERT(networth_f2.m_grid.m_total[eActual][1]==moCheckingOpen+moCreditOpen-moChild-moParent);
+}
+
+void PivotTableTest::testNetWorthDateFilter()
+{
+ // Test a net worth report whose period is prior to the time any accounts are open,
+ // so the report should be zero.
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2004,2,1).addDays(-1));
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][1]==moZero);
+
+}
+
+void PivotTableTest::testSpendingEmpty()
+{
+ // test a spending report with no entries
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ XMLandback(filter);
+ PivotTable spending_f1( filter );
+ CPPUNIT_ASSERT(spending_f1.m_grid.m_total[eActual].m_total==moZero);
+
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ PivotTable spending_f2( filter );
+ CPPUNIT_ASSERT(spending_f2.m_grid.m_total[eActual].m_total==moZero);
+}
+
+void PivotTableTest::testSingleTransaction()
+{
+ // Test a single transaction
+ TransactionHelper t( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal,moSolo, acChecking, acSolo );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.setName("Spending with Single Transaction.html");
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ writeTabletoHTML(spending_f,"Spending with Single Transaction.html");
+
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Solo"][acSolo][eActual][2]==moSolo);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Solo"].m_total[eActual][2]==moSolo);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Solo"].m_total[eActual][1]==moZero);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual][2]==(-moSolo));
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==(-moSolo));
+
+ filter.clear();
+ filter.setRowType(MyMoneyReport::eAssetLiability);
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Checking Account"].m_total[eActual][2]==(moCheckingOpen-moSolo) );
+}
+
+void PivotTableTest::testSubAccount()
+{
+ // Test a sub-account with a value, under an account with a value
+
+ TransactionHelper t1( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.setDetailLevel(MyMoneyReport::eDetailAll);
+ filter.setName("Spending with Sub-Account");
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ writeTabletoHTML(spending_f,"Spending with Sub-Account.html");
+
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"][acParent][eActual][3]==moParent);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"][acChild][eActual][3]==moChild);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"].m_total[eActual][3]==moParent+moChild);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"].m_total[eActual][2]==moZero);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"].m_total[eActual].m_total==moParent+moChild);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual][3]==(-moParent-moChild));
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==(-moParent-moChild));
+
+ filter.clear();
+ filter.setRowType(MyMoneyReport::eAssetLiability);
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.setName("Net Worth with Sub-Account");
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ writeTabletoHTML(networth_f,"Net Worth with Sub-Account.html");
+ CPPUNIT_ASSERT(networth_f.m_grid["Liability"]["Credit Card"].m_total[eActual][3]==moParent+moChild-moCreditOpen );
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][4] == -moParent-moChild+moCreditOpen+moCheckingOpen );
+
+}
+
+void PivotTableTest::testFilterIEvsIE()
+{
+ // Test that removing an income/spending account will remove the entry from an income/spending report
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.addCategory(acChild);
+ filter.addCategory(acSolo);
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"].m_total[eActual][3]==moChild);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"].m_total[eActual][2]==moSolo);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moSolo-moChild);
+
+}
+
+void PivotTableTest::testFilterALvsAL()
+{
+ // Test that removing an asset/liability account will remove the entry from an asset/liability report
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.addAccount(acChecking);
+ filter.addCategory(acChild);
+ filter.addCategory(acSolo);
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ CPPUNIT_ASSERT(networth_f.m_grid.m_total[eActual][3] == -moSolo+moCheckingOpen );
+}
+
+void PivotTableTest::testFilterALvsIE()
+{
+ // Test that removing an asset/liability account will remove the entry from an income/spending report
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.addAccount(acChecking);
+ CPPUNIT_ASSERT(file->transactionList(filter).count() == 1);
+
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"].m_total[eActual][3]==moZero);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"].m_total[eActual][2]==moSolo);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moSolo);
+}
+
+void PivotTableTest::testFilterAllvsIE()
+{
+ // Test that removing an asset/liability account AND an income/expense
+ // category will remove the entry from an income/spending report
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.addAccount(acCredit);
+ filter.addCategory(acChild);
+ PivotTable spending_f( filter );
+
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"].m_total[eActual][2]==moZero);
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"].m_total[eActual][3]==moChild);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moChild);
+}
+
+void PivotTableTest::testFilterBasics()
+{
+ // Test that the filters are operating the way that the reports expect them to
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyTransactionFilter filter;
+ filter.clear();
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.addCategory(acSolo);
+ filter.setReportAllSplits(false);
+ filter.setConsiderCategory(true);
+
+ CPPUNIT_ASSERT(file->transactionList(filter).count() == 1);
+
+ filter.addCategory(acParent);
+
+ CPPUNIT_ASSERT(file->transactionList(filter).count() == 3);
+
+ filter.addAccount(acChecking);
+
+ CPPUNIT_ASSERT(file->transactionList(filter).count() == 1);
+
+ filter.clear();
+ filter.setDateFilter(QDate(2004,9,1),QDate(2005,1,1).addDays(-1));
+ filter.addCategory(acParent);
+ filter.addAccount(acCredit);
+ filter.setReportAllSplits(false);
+ filter.setConsiderCategory(true);
+
+ CPPUNIT_ASSERT(file->transactionList(filter).count() == 2);
+}
+
+void PivotTableTest::testMultipleCurrencies()
+{
+ MyMoneyMoney moCanOpening( 0.0 );
+ MyMoneyMoney moJpyOpening( 0.0 );
+ MyMoneyMoney moCanPrice( 0.75 );
+ MyMoneyMoney moJpyPrice( 0.010 );
+ MyMoneyMoney moJpyPrice2( 0.011 );
+ MyMoneyMoney moJpyPrice3( 0.014 );
+ MyMoneyMoney moJpyPrice4( 0.0395 );
+ MyMoneyMoney moCanTransaction( 100.0 );
+ MyMoneyMoney moJpyTransaction( 100.0 );
+
+ QString acCanChecking = makeAccount(QString("Canadian Checking"),MyMoneyAccount::Checkings,moCanOpening,QDate(2003,11,15),acAsset,"CAD");
+ QString acJpyChecking = makeAccount(QString("Japanese Checking"),MyMoneyAccount::Checkings,moJpyOpening,QDate(2003,11,15),acAsset,"JPY");
+ QString acCanCash = makeAccount(QString("Canadian"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acForeign,"CAD");
+ QString acJpyCash = makeAccount(QString("Japanese"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acForeign,"JPY");
+
+ makePrice("CAD",QDate(2004,1,1),MyMoneyMoney(moCanPrice));
+ makePrice("JPY",QDate(2004,1,1),MyMoneyMoney(moJpyPrice));
+ makePrice("JPY",QDate(2004,5,1),MyMoneyMoney(moJpyPrice2));
+ makePrice("JPY",QDate(2004,6,30),MyMoneyMoney(moJpyPrice3));
+ makePrice("JPY",QDate(2004,7,15),MyMoneyMoney(moJpyPrice4));
+
+ TransactionHelper t1( QDate(2004,2,20), MyMoneySplit::ActionWithdrawal,MyMoneyMoney(moJpyTransaction), acJpyChecking, acJpyCash, "JPY" );
+ TransactionHelper t2( QDate(2004,3,20), MyMoneySplit::ActionWithdrawal,MyMoneyMoney(moJpyTransaction), acJpyChecking, acJpyCash, "JPY" );
+ TransactionHelper t3( QDate(2004,4,20), MyMoneySplit::ActionWithdrawal,MyMoneyMoney(moJpyTransaction), acJpyChecking, acJpyCash, "JPY" );
+ TransactionHelper t4( QDate(2004,2,20), MyMoneySplit::ActionWithdrawal,MyMoneyMoney(moCanTransaction), acCanChecking, acCanCash, "CAD" );
+ TransactionHelper t5( QDate(2004,3,20), MyMoneySplit::ActionWithdrawal,MyMoneyMoney(moCanTransaction), acCanChecking, acCanCash, "CAD" );
+ TransactionHelper t6( QDate(2004,4,20), MyMoneySplit::ActionWithdrawal,MyMoneyMoney(moCanTransaction), acCanChecking, acCanCash, "CAD" );
+
+#if 0
+ QFile g( "multicurrencykmy.xml" );
+ g.open( IO_WriteOnly );
+ MyMoneyStorageXML xml;
+ IMyMoneyStorageFormat& interface = xml;
+ interface.writeFile(&g, dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()));
+ g.close();
+#endif
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.setDetailLevel(MyMoneyReport::eDetailAll);
+ filter.setConvertCurrency(true);
+ filter.setName("Multiple Currency Spending Rerport (with currency conversion)");
+ XMLandback(filter);
+
+ PivotTable spending_f( filter );
+
+ writeTabletoCSV(spending_f);
+
+ // test single foreign currency
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"][acCanCash][eActual][2]==(moCanTransaction*moCanPrice));
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"][acCanCash][eActual][3]==(moCanTransaction*moCanPrice));
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"][acCanCash][eActual][4]==(moCanTransaction*moCanPrice));
+
+ // test multiple foreign currencies under a common parent
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"][acJpyCash][eActual][2]==(moJpyTransaction*moJpyPrice));
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"][acJpyCash][eActual][3]==(moJpyTransaction*moJpyPrice));
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"][acJpyCash][eActual][4]==(moJpyTransaction*moJpyPrice));
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"].m_total[eActual][2]==(moJpyTransaction*moJpyPrice + moCanTransaction*moCanPrice));
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Foreign"].m_total[eActual].m_total==(moJpyTransaction*moJpyPrice + moCanTransaction*moCanPrice + moJpyTransaction*moJpyPrice + moCanTransaction*moCanPrice + moJpyTransaction*moJpyPrice + moCanTransaction*moCanPrice));
+
+ // Test the report type where we DO NOT convert the currency
+ filter.setConvertCurrency(false);
+ filter.setDetailLevel(MyMoneyReport::eDetailAll);
+ filter.setName("Multiple Currency Spending Report (WITHOUT currency conversion)");
+ XMLandback(filter);
+ PivotTable spending_fnc( filter );
+ writeTabletoCSV(spending_fnc);
+
+ CPPUNIT_ASSERT(spending_fnc.m_grid["Expense"]["Foreign"][acCanCash][eActual][2]==(moCanTransaction));
+ CPPUNIT_ASSERT(spending_fnc.m_grid["Expense"]["Foreign"][acCanCash][eActual][3]==(moCanTransaction));
+ CPPUNIT_ASSERT(spending_fnc.m_grid["Expense"]["Foreign"][acCanCash][eActual][4]==(moCanTransaction));
+ CPPUNIT_ASSERT(spending_fnc.m_grid["Expense"]["Foreign"][acJpyCash][eActual][2]==(moJpyTransaction));
+ CPPUNIT_ASSERT(spending_fnc.m_grid["Expense"]["Foreign"][acJpyCash][eActual][3]==(moJpyTransaction));
+ CPPUNIT_ASSERT(spending_fnc.m_grid["Expense"]["Foreign"][acJpyCash][eActual][4]==(moJpyTransaction));
+
+ filter.setConvertCurrency(true);
+ filter.clear();
+ filter.setName("Multiple currency net worth");
+ filter.setRowType(MyMoneyReport::eAssetLiability);
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ XMLandback(filter);
+ PivotTable networth_f( filter );
+ writeTabletoCSV(networth_f);
+
+ // test single foreign currency
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Canadian Checking"][acCanChecking][eActual][1]==(moCanOpening*moCanPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Canadian Checking"][acCanChecking][eActual][2]==((moCanOpening-moCanTransaction)*moCanPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Canadian Checking"][acCanChecking][eActual][3]==((moCanOpening-moCanTransaction-moCanTransaction)*moCanPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Canadian Checking"][acCanChecking][eActual][4]==((moCanOpening-moCanTransaction-moCanTransaction-moCanTransaction)*moCanPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Canadian Checking"][acCanChecking][eActual][12]==((moCanOpening-moCanTransaction-moCanTransaction-moCanTransaction)*moCanPrice));
+
+ // test Stable currency price, fluctuating account balance
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][1]==(moJpyOpening*moJpyPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][2]==((moJpyOpening-moJpyTransaction)*moJpyPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][3]==((moJpyOpening-moJpyTransaction-moJpyTransaction)*moJpyPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][4]==((moJpyOpening-moJpyTransaction-moJpyTransaction-moJpyTransaction)*moJpyPrice));
+
+ // test Fluctuating currency price, stable account balance
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][5]==((moJpyOpening-moJpyTransaction-moJpyTransaction-moJpyTransaction)*moJpyPrice2));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][6]==((moJpyOpening-moJpyTransaction-moJpyTransaction-moJpyTransaction)*moJpyPrice3));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"]["Japanese Checking"][acJpyChecking][eActual][7]==((moJpyOpening-moJpyTransaction-moJpyTransaction-moJpyTransaction)*moJpyPrice4));
+
+ // test multiple currencies totalled up
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"].m_total[eActual][4]==((moCanOpening-moCanTransaction-moCanTransaction-moCanTransaction)*moCanPrice)+((moJpyOpening-moJpyTransaction-moJpyTransaction-moJpyTransaction)*moJpyPrice));
+ CPPUNIT_ASSERT(networth_f.m_grid["Asset"].m_total[eActual][5]==((moCanOpening-moCanTransaction-moCanTransaction-moCanTransaction)*moCanPrice)+((moJpyOpening-moJpyTransaction-moJpyTransaction-moJpyTransaction)*moJpyPrice2)+moCheckingOpen);
+
+}
+
+void PivotTableTest::testAdvancedFilter()
+{
+ // test more advanced filtering capabilities
+
+ // amount
+ {
+ TransactionHelper t1( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.setAmountFilter(moChild,moChild);
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moChild);
+ }
+
+ // payee (specific)
+ {
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+ TransactionHelper t4( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moThomas, acCredit, acParent, QString(), "Thomas Baumgart" );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.addPayee(MyMoneyFile::instance()->payeeByName("Thomas Baumgart").id());
+ filter.setName("Spending with Payee Filter");
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ writeTabletoHTML(spending_f,"Spending with Payee Filter.html");
+
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"][acParent][eActual][11]==moThomas);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moThomas);
+ }
+ // payee (no payee)
+ {
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+ TransactionHelper t4( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moNoPayee, acCredit, acParent, QString(), QString() );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.addPayee(QString());
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ CPPUNIT_ASSERT(spending_f.m_grid["Expense"]["Parent"][acParent][eActual][11]==moNoPayee);
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moNoPayee);
+ }
+
+ // text
+ {
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+ TransactionHelper t4( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moThomas, acCredit, acParent, QString(), "Thomas Baumgart" );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.setTextFilter(QRegExp("Thomas"));
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ }
+
+ // type (payment, deposit, transfer)
+ {
+ TransactionHelper t1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,2,1), MyMoneySplit::ActionDeposit, -moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,1), MyMoneySplit::ActionTransfer, moChild, acCredit, acChecking );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.addType(MyMoneyTransactionFilter::payments);
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total == -moSolo);
+
+ filter.clear();
+ filter.addType(MyMoneyTransactionFilter::deposits);
+ XMLandback(filter);
+ PivotTable spending_f2( filter );
+
+ CPPUNIT_ASSERT(spending_f2.m_grid.m_total[eActual].m_total == moParent1);
+
+ filter.clear();
+ filter.addType(MyMoneyTransactionFilter::transfers);
+ XMLandback(filter);
+ PivotTable spending_f3( filter );
+
+ CPPUNIT_ASSERT(spending_f3.m_grid.m_total[eActual].m_total == moZero);
+
+ filter.setRowType(MyMoneyReport::eAssetLiability);
+ filter.setDateFilter( QDate(2004,1,1), QDate(2004,12,31) );
+ XMLandback(filter);
+ PivotTable networth_f4( filter );
+
+ CPPUNIT_ASSERT(networth_f4.m_grid["Asset"].m_total[eActual][11] == moCheckingOpen + moChild);
+ CPPUNIT_ASSERT(networth_f4.m_grid["Liability"].m_total[eActual][11] == - moCreditOpen + moChild);
+ CPPUNIT_ASSERT(networth_f4.m_grid.m_total[eActual][10] == moCheckingOpen + moCreditOpen);
+ CPPUNIT_ASSERT(networth_f4.m_grid.m_total[eActual][11] == moCheckingOpen + moCreditOpen);
+ }
+
+ // state (reconciled, cleared, not)
+ {
+ TransactionHelper t1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,2,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,3,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4( QDate(2004,4,1), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ QValueList<MyMoneySplit> splits = t1.splits();
+ splits[0].setReconcileFlag(MyMoneySplit::Cleared);
+ splits[1].setReconcileFlag(MyMoneySplit::Cleared);
+ t1.modifySplit(splits[0]);
+ t1.modifySplit(splits[1]);
+ t1.update();
+
+ splits.clear();
+ splits = t2.splits();
+ splits[0].setReconcileFlag(MyMoneySplit::Reconciled);
+ splits[1].setReconcileFlag(MyMoneySplit::Reconciled);
+ t2.modifySplit(splits[0]);
+ t2.modifySplit(splits[1]);
+ t2.update();
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.addState(MyMoneyTransactionFilter::cleared);
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moSolo);
+
+ filter.addState(MyMoneyTransactionFilter::reconciled);
+ XMLandback(filter);
+ PivotTable spending_f2( filter );
+
+ CPPUNIT_ASSERT(spending_f2.m_grid.m_total[eActual].m_total==-moSolo-moParent1);
+
+ filter.clear();
+ filter.addState(MyMoneyTransactionFilter::notReconciled);
+ XMLandback(filter);
+ PivotTable spending_f3( filter );
+
+ CPPUNIT_ASSERT(spending_f3.m_grid.m_total[eActual].m_total==-moChild-moParent2);
+ }
+
+ // number
+ {
+ TransactionHelper t1( QDate(2004,10,31), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ QValueList<MyMoneySplit> splits = t1.splits();
+ splits[0].setNumber("1");
+ splits[1].setNumber("1");
+ t1.modifySplit(splits[0]);
+ t1.modifySplit(splits[1]);
+ t1.update();
+
+ splits.clear();
+ splits = t2.splits();
+ splits[0].setNumber("2");
+ splits[1].setNumber("2");
+ t2.modifySplit(splits[0]);
+ t2.modifySplit(splits[1]);
+ t2.update();
+
+ splits.clear();
+ splits = t3.splits();
+ splits[0].setNumber("3");
+ splits[1].setNumber("3");
+ t3.modifySplit(splits[0]);
+ t3.modifySplit(splits[1]);
+ t3.update();
+
+ splits.clear();
+ splits = t2.splits();
+ splits[0].setNumber("4");
+ splits[1].setNumber("4");
+ t4.modifySplit(splits[0]);
+ t4.modifySplit(splits[1]);
+ t4.update();
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2004,1,1),QDate(2005,1,1).addDays(-1));
+ filter.setNumberFilter("1","3");
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moSolo-moParent1-moParent2);
+ }
+
+ // blank dates
+ {
+ TransactionHelper t1y1( QDate(2003,10,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y1( QDate(2003,11,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y1( QDate(2003,12,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ TransactionHelper t1y2( QDate(2004,4,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y2( QDate(2004,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y2( QDate(2004,6,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ TransactionHelper t1y3( QDate(2005,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y3( QDate(2005,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y3( QDate(2005,9,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(),QDate(2004,7,1));
+ XMLandback(filter);
+ PivotTable spending_f( filter );
+ CPPUNIT_ASSERT(spending_f.m_grid.m_total[eActual].m_total==-moSolo-moParent1-moParent2-moSolo-moParent1-moParent2);
+
+ filter.clear();
+ XMLandback(filter);
+ PivotTable spending_f2( filter );
+ CPPUNIT_ASSERT(spending_f2.m_grid.m_total[eActual].m_total==-moSolo-moParent1-moParent2-moSolo-moParent1-moParent2-moSolo-moParent1-moParent2);
+
+ }
+
+}
+
+void PivotTableTest::testColumnType()
+{
+ // test column type values of other than 'month'
+
+ TransactionHelper t1q1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q1( QDate(2004,2,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q1( QDate(2004,3,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ TransactionHelper t1q2( QDate(2004,4,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q2( QDate(2004,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q2( QDate(2004,6,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ TransactionHelper t1y2( QDate(2005,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y2( QDate(2005,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y2( QDate(2005,9,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setDateFilter(QDate(2003,12,31),QDate(2005,12,31));
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setColumnType(MyMoneyReport::eBiMonths);
+ XMLandback(filter);
+ PivotTable spending_b( filter );
+
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][1] == moZero);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][2] == -moParent1-moSolo);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][3] == -moParent2-moSolo);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][4] == -moParent);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][5] == moZero);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][6] == moZero);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][7] == moZero);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][8] == -moSolo);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][9] == moZero);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][10] == -moParent1);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][11] == moZero);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][12] == -moParent2);
+ CPPUNIT_ASSERT(spending_b.m_grid.m_total[eActual][13] == moZero);
+
+ filter.setColumnType(MyMoneyReport::eQuarters);
+ XMLandback(filter);
+ PivotTable spending_q( filter );
+
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][1] == moZero);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][2] == -moSolo-moParent);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][3] == -moSolo-moParent);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][4] == moZero);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][5] == moZero);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][6] == -moSolo);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][7] == -moParent1);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][8] == -moParent2);
+ CPPUNIT_ASSERT(spending_q.m_grid.m_total[eActual][9] == moZero);
+
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ filter.setName( "Net Worth by Quarter" );
+ XMLandback(filter);
+ PivotTable networth_q( filter );
+ writeTabletoHTML( networth_q, "Net Worth by Quarter.html" );
+
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][1] == moZero);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][2] == -moSolo-moParent);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][3] == -moSolo-moParent-moSolo-moParent+moCheckingOpen);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][4] == -moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][5] == -moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][6] == -moSolo-moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][7] == -moParent1-moSolo-moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][8] == -moParent2-moParent1-moSolo-moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_q.m_grid.m_total[eActual][9] == -moParent2-moParent1-moSolo-moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setColumnType(MyMoneyReport::eYears);
+ XMLandback(filter);
+ PivotTable spending_y( filter );
+
+ CPPUNIT_ASSERT(spending_y.m_grid.m_total[eActual][1] == moZero);
+ CPPUNIT_ASSERT(spending_y.m_grid.m_total[eActual][2] == -moSolo-moParent-moSolo-moParent);
+ CPPUNIT_ASSERT(spending_y.m_grid.m_total[eActual][3] == -moSolo-moParent);
+ CPPUNIT_ASSERT(spending_y.m_grid.m_total[eActual].m_total == -moSolo-moParent-moSolo-moParent-moSolo-moParent);
+
+ filter.setRowType( MyMoneyReport::eAssetLiability );
+ XMLandback(filter);
+ PivotTable networth_y( filter );
+
+ CPPUNIT_ASSERT(networth_y.m_grid.m_total[eActual][1] == moZero);
+ CPPUNIT_ASSERT(networth_y.m_grid.m_total[eActual][2] == -moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+ CPPUNIT_ASSERT(networth_y.m_grid.m_total[eActual][3] == -moSolo-moParent-moSolo-moParent-moSolo-moParent+moCheckingOpen+moCreditOpen);
+
+ // Test days-based reports
+
+ TransactionHelper t1d1( QDate(2004,7,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2d1( QDate(2004,7,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3d1( QDate(2004,7,5), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ TransactionHelper t1d2( QDate(2004,7,14), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2d2( QDate(2004,7,15), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3d2( QDate(2004,7,20), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ TransactionHelper t1d3( QDate(2004,8,2), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2d3( QDate(2004,8,3), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3d3( QDate(2004,8,4), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+
+ filter.setDateFilter(QDate(2004,7,2),QDate(2004,7,14));
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setColumnType(MyMoneyReport::eMonths);
+ filter.setColumnsAreDays(true);
+
+ XMLandback(filter);
+ PivotTable spending_days( filter );
+ writeTabletoHTML(spending_days,"Spending by Days.html");
+
+ CPPUNIT_ASSERT(spending_days.m_grid.m_total[eActual][4] == -moParent2);
+ CPPUNIT_ASSERT(spending_days.m_grid.m_total[eActual][13] == -moSolo);
+ CPPUNIT_ASSERT(spending_days.m_grid.m_total[eActual].m_total == -moSolo-moParent2);
+
+ unsigned save_dayweekstart = KGlobal::locale()->weekStartDay();
+ KGlobal::locale()->setWeekStartDay(2);
+
+ filter.setDateFilter(QDate(2004,7,2),QDate(2004,8,1));
+ filter.setRowType( MyMoneyReport::eExpenseIncome );
+ filter.setColumnType(static_cast<MyMoneyReport::EColumnType>(7));
+ filter.setColumnsAreDays(true);
+
+ XMLandback(filter);
+ PivotTable spending_weeks( filter );
+ writeTabletoHTML(spending_weeks,"Spending by Weeks.html");
+
+ KGlobal::locale()->setWeekStartDay(save_dayweekstart);
+
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual][0] == moZero);
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual][1] == -moParent2);
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual][2] == moZero);
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual][3] == -moSolo-moParent1);
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual][4] == -moParent2);
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual][5] == moZero);
+ CPPUNIT_ASSERT(spending_weeks.m_grid.m_total[eActual].m_total == -moSolo-moParent-moParent2);
+
+
+}
+
+void PivotTableTest::testInvestment(void)
+{
+ try
+ {
+ // Equities
+ eqStock1 = makeEquity("Stock1","STK1");
+ eqStock2 = makeEquity("Stock2","STK2");
+
+ // Accounts
+ acInvestment = makeAccount("Investment",MyMoneyAccount::Investment,moZero,QDate(2004,1,1),acAsset);
+ acStock1 = makeAccount("Stock 1",MyMoneyAccount::Stock,moZero,QDate(2004,1,1),acInvestment,eqStock1);
+ acStock2 = makeAccount("Stock 2",MyMoneyAccount::Stock,moZero,QDate(2004,1,1),acInvestment,eqStock2);
+ acDividends = makeAccount("Dividends",MyMoneyAccount::Income,moZero,QDate(2004,1,1),acIncome);
+
+ // Transactions
+ // Date Action Shares Price Stock Asset Income
+ InvTransactionHelper s1b1( QDate(2004,2,1), MyMoneySplit::ActionBuyShares, 1000.00, 100.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1b2( QDate(2004,3,1), MyMoneySplit::ActionBuyShares, 1000.00, 110.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1s1( QDate(2004,4,1), MyMoneySplit::ActionBuyShares, -200.00, 120.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1s2( QDate(2004,5,1), MyMoneySplit::ActionBuyShares, -200.00, 100.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1r1( QDate(2004,6,1), MyMoneySplit::ActionReinvestDividend, 50.00, 100.00, acStock1, QString(), acDividends );
+ InvTransactionHelper s1r2( QDate(2004,7,1), MyMoneySplit::ActionReinvestDividend, 50.00, 80.00, acStock1, QString(), acDividends );
+ InvTransactionHelper s1c1( QDate(2004,8,1), MyMoneySplit::ActionDividend, 10.00, 100.00, acStock1, acChecking, acDividends );
+ InvTransactionHelper s1c2( QDate(2004,9,1), MyMoneySplit::ActionDividend, 10.00, 120.00, acStock1, acChecking, acDividends );
+
+ makeEquityPrice( eqStock1, QDate(2004,10,1), 100.00 );
+
+ //
+ // Net Worth Report (with investments)
+ //
+
+ MyMoneyReport networth_r;
+ networth_r.setRowType( MyMoneyReport::eAssetLiability );
+ networth_r.setDateFilter(QDate(2004,1,1),QDate(2004,12,31).addDays(-1));
+ XMLandback(networth_r);
+ PivotTable networth(networth_r);
+
+ networth.dump("networth_i.html");
+
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][1]==moZero);
+ // 1000 shares @ $100.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][2]==MyMoneyMoney(100000.0));
+ // 2000 shares @ $110.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][3]==MyMoneyMoney(220000.0));
+ // 1800 shares @ $120.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][4]==MyMoneyMoney(216000.0));
+ // 1600 shares @ $100.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][5]==MyMoneyMoney(160000.0));
+ // 1650 shares @ $100.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][6]==MyMoneyMoney(165000.0));
+ // 1700 shares @ $ 80.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][7]==MyMoneyMoney(136000.0));
+ // 1700 shares @ $100.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][8]==MyMoneyMoney(170000.0));
+ // 1700 shares @ $120.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][9]==MyMoneyMoney(204000.0));
+ // 1700 shares @ $100.00
+ CPPUNIT_ASSERT(networth.m_grid["Asset"]["Investment"].m_total[eActual][10]==MyMoneyMoney(170000.0));
+
+#if 0
+ // Dump file & reports
+ QFile g( "investmentkmy.xml" );
+ g.open( IO_WriteOnly );
+ MyMoneyStorageXML xml;
+ IMyMoneyStorageFormat& interface = xml;
+ interface.writeFile(&g, dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()));
+ g.close();
+
+ invtran.dump("invtran.html","<html><head></head><body>%1</body></html>");
+ invhold.dump("invhold.html","<html><head></head><body>%1</body></html>");
+#endif
+
+ }
+ catch(MyMoneyException *e)
+ {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+}
+
+void PivotTableTest::testBudget(void)
+{
+
+ // 1. Budget on A, transations on A
+ {
+ BudgetHelper budget;
+ budget += BudgetEntryHelper( QDate(2006,1,1), acSolo, false, 100.0 );
+
+ MyMoneyReport report(MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ "Yearly Budgeted vs. Actual","Default Report");
+ PivotTable table(report);
+ }
+
+ // 2. Budget on B, not applying to sub accounts, transactions on B and B:1
+ {
+ BudgetHelper budget;
+ budget += BudgetEntryHelper( QDate(2006,1,1), acParent, false, 100.0 );
+ MyMoneyReport report(MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ "Yearly Budgeted vs. Actual","Default Report");
+ PivotTable table(report);
+ }
+
+ // - Both B and B:1 totals should show up
+ // - B actuals compare against B budget
+ // - B:1 actuals compare against 0
+
+ // 3. Budget on C, applying to sub accounts, transactions on C and C:1 and C:1:a
+ {
+ BudgetHelper budget;
+ budget += BudgetEntryHelper( QDate(2006,1,1), acParent, true, 100.0 );
+ MyMoneyReport report(MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop ,
+ "Yearly Budgeted vs. Actual","Default Report");
+ PivotTable table(report);
+ }
+
+ // - Only C totals show up, not C:1 or C:1:a totals
+ // - C + C:1 totals compare against C budget
+
+ // 4. Budget on D, not applying to sub accounts, budget on D:1 not applying, budget on D:2 applying. Transactions on D, D:1, D:2, D:2:a, D:2:b
+ {
+ BudgetHelper budget;
+ budget += BudgetEntryHelper( QDate(2006,1,1), acParent, false, 100.0 );
+ budget += BudgetEntryHelper( QDate(2006,1,1), acChild, false, 100.0 );
+ budget += BudgetEntryHelper( QDate(2006,1,1), acSecondChild, true, 100.0 );
+ MyMoneyReport report(MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ "Yearly Budgeted vs. Actual","Default Report");
+ PivotTable table(report);
+ }
+
+ // - Totals for D, D:1, D:2 show up. D:2:a and D:2:b do not
+ // - D actuals (only) compare against D budget
+ // - Ditto for D:1
+ // - D:2 acutals and children compare against D:2 budget
+
+ // 5. Budget on E, no transactions on E
+ {
+ BudgetHelper budget;
+ budget += BudgetEntryHelper( QDate(2006,1,1), acSolo, false, 100.0 );
+ MyMoneyReport report(MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ "Yearly Budgeted vs. Actual","Default Report");
+ PivotTable table(report);
+ }
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/pivottabletest.h b/kmymoney2/reports/pivottabletest.h
new file mode 100644
index 0000000..299355c
--- /dev/null
+++ b/kmymoney2/reports/pivottabletest.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ pivottabletest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.jones@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PIVOTTABLETEST_H
+#define PIVOTTABLETEST_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+class PivotTableTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(PivotTableTest);
+ CPPUNIT_TEST(testNetWorthSingle);
+ CPPUNIT_TEST(testNetWorthOfsetting);
+ CPPUNIT_TEST(testNetWorthOpeningPrior);
+ CPPUNIT_TEST(testNetWorthDateFilter);
+ CPPUNIT_TEST(testSpendingEmpty);
+ CPPUNIT_TEST(testSingleTransaction);
+ CPPUNIT_TEST(testSubAccount);
+ CPPUNIT_TEST(testFilterIEvsIE);
+ CPPUNIT_TEST(testFilterALvsAL);
+ CPPUNIT_TEST(testFilterALvsIE);
+ CPPUNIT_TEST(testFilterAllvsIE);
+ CPPUNIT_TEST(testFilterBasics);
+ CPPUNIT_TEST(testMultipleCurrencies);
+ CPPUNIT_TEST(testAdvancedFilter);
+ CPPUNIT_TEST(testColumnType);
+ CPPUNIT_TEST(testInvestment);
+ CPPUNIT_TEST(testBudget);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ MyMoneyAccount *m;
+
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyFile* file;
+
+public:
+ PivotTableTest();
+ void setUp ();
+ void tearDown ();
+ void testNetWorthSingle();
+ void testNetWorthOfsetting();
+ void testNetWorthOpeningPrior();
+ void testNetWorthDateFilter();
+ void testSpendingEmpty();
+ void testSingleTransaction();
+ void testSubAccount();
+ void testFilterIEvsIE();
+ void testFilterALvsAL();
+ void testFilterALvsIE();
+ void testFilterAllvsIE();
+ void testFilterBasics();
+ void testMultipleCurrencies();
+ void testAdvancedFilter();
+ void testColumnType();
+ void testInvestment();
+ void testBudget();
+};
+
+#endif // PIVOTTABLETEST_H
diff --git a/kmymoney2/reports/querytable.cpp b/kmymoney2/reports/querytable.cpp
new file mode 100644
index 0000000..29702c6
--- /dev/null
+++ b/kmymoney2/reports/querytable.cpp
@@ -0,0 +1,1522 @@
+/***************************************************************************
+ querytable.cpp
+ -------------------
+ begin : Fri Jul 23 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ (C) 2007 Sascha Pfau
+ email : acejones@users.sourceforge.net
+ MrPeacock@gmail.com
+ ***************************************************************************/
+
+/****************************************************************************
+ Contains code from the func_xirr and related methods of financial.cpp
+ - KOffice 1.6 by Sascha Pfau. Sascha agreed to relicense those methods under
+ GPLv2 or later.
+*****************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qvaluelist.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// This is just needed for i18n(). Once I figure out how to handle i18n
+// without using this macro directly, I'll be freed of KDE dependency.
+
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneytransaction.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneyexception.h"
+#include "../kmymoneyutils.h"
+#include "../kmymoneyglobalsettings.h"
+#include "reportaccount.h"
+#include "reportdebug.h"
+#include "querytable.h"
+
+namespace reports {
+
+// ****************************************************************************
+//
+// CashFlowListItem implementation
+//
+// Cash flow analysis tools for investment reports
+//
+// ****************************************************************************
+
+QDate CashFlowListItem::m_sToday = QDate::currentDate();
+
+MyMoneyMoney CashFlowListItem::NPV( double _rate ) const
+{
+ double T = static_cast<double>(m_sToday.daysTo(m_date)) / 365.0;
+ MyMoneyMoney result = m_value.toDouble() / pow(1+_rate,T);
+
+ //kdDebug(2) << "CashFlowListItem::NPV( " << _rate << " ) == " << result << endl;
+
+ return result;
+}
+
+// ****************************************************************************
+//
+// CashFlowList implementation
+//
+// Cash flow analysis tools for investment reports
+//
+// ****************************************************************************
+
+CashFlowListItem CashFlowList::mostRecent(void) const
+{
+ CashFlowList dupe( *this );
+ qHeapSort( dupe );
+
+ //kdDebug(2) << " CashFlowList::mostRecent() == " << dupe.back().date().toString(Qt::ISODate) << endl;
+
+ return dupe.back();
+}
+
+MyMoneyMoney CashFlowList::NPV( double _rate ) const
+{
+ MyMoneyMoney result = 0.0;
+
+ const_iterator it_cash = begin();
+ while ( it_cash != end() )
+ {
+ result += (*it_cash).NPV( _rate );
+ ++it_cash;
+ }
+
+ //kdDebug(2) << "CashFlowList::NPV( " << _rate << " ) == " << result << endl << "------------------------" << endl;
+
+ return result;
+}
+
+double CashFlowList::calculateXIRR ( void ) const
+{
+ double resultRate = 0.00001;
+
+ double resultZero = 0.00000;
+ //if ( args.count() > 2 )
+ // resultRate = calc->conv()->asFloat ( args[2] ).asFloat();
+
+// check pairs and count >= 2 and guess > -1.0
+ //if ( args[0].count() != args[1].count() || args[1].count() < 2 || resultRate <= -1.0 )
+ // return Value::errorVALUE();
+
+// define max epsilon
+ static const double maxEpsilon = 1e-5;
+
+// max number of iterations
+ static const int maxIter = 50;
+
+// Newton's method - try to find a res, with a accuracy of maxEpsilon
+ double rateEpsilon, newRate, resultValue;
+ int i = 0;
+ bool contLoop;
+
+ do
+ {
+ resultValue = xirrResult ( resultRate );
+
+ double resultDerive = xirrResultDerive ( resultRate );
+
+ //check what happens if xirrResultDerive is zero
+ //Don't know if it is correct to dismiss the result
+ if( resultDerive != 0 ) {
+ newRate = resultRate - resultValue / resultDerive;
+ } else {
+
+ newRate = resultRate - resultValue;
+ }
+
+ rateEpsilon = fabs ( newRate - resultRate );
+
+ resultRate = newRate;
+ contLoop = ( rateEpsilon > maxEpsilon ) && ( fabs ( resultValue ) > maxEpsilon );
+ }
+ while ( contLoop && ( ++i < maxIter ) );
+
+ if ( contLoop )
+ return resultZero;
+
+ return resultRate;
+}
+
+double CashFlowList::xirrResult ( double& rate ) const
+{
+ QDate date;
+
+ double r = rate + 1.0;
+ double res = 0.00000;//back().value().toDouble();
+
+ QValueList<CashFlowListItem>::const_iterator list_it = begin();
+ while( list_it != end() ) {
+ double e_i = ( (* list_it).today().daysTo ( (* list_it).date() ) ) / 365.0;
+ MyMoneyMoney val = (* list_it).value();
+
+ res += val.toDouble() / pow ( r, e_i );
+ ++list_it;
+ }
+
+ return res;
+}
+
+
+double CashFlowList::xirrResultDerive ( double& rate ) const
+{
+ QDate date;
+
+ double r = rate + 1.0;
+ double res = 0.00000;
+
+ QValueList<CashFlowListItem>::const_iterator list_it = begin();
+ while( list_it != end() ) {
+ double e_i = ( (* list_it).today().daysTo ( (* list_it).date() ) ) / 365.0;
+ MyMoneyMoney val = (* list_it).value();
+
+ res -= e_i * val.toDouble() / pow ( r, e_i + 1.0 );
+ ++list_it;
+ }
+
+ return res;
+}
+
+double CashFlowList::IRR( void ) const
+{
+ double result = 0.0;
+
+ // set 'today', which is the most recent of all dates in the list
+ CashFlowListItem::setToday( mostRecent().date() );
+
+ result = calculateXIRR();
+ return result;
+}
+
+MyMoneyMoney CashFlowList::total(void) const
+{
+ MyMoneyMoney result;
+
+ const_iterator it_cash = begin();
+ while ( it_cash != end() )
+ {
+ result += (*it_cash).value();
+ ++it_cash;
+ }
+
+ return result;
+}
+
+void CashFlowList::dumpDebug(void) const
+{
+ const_iterator it_item = begin();
+ while ( it_item != end() )
+ {
+ kdDebug(2) << (*it_item).date().toString(Qt::ISODate) << " " << (*it_item).value().toString() << endl;
+ ++it_item;
+ }
+}
+
+// ****************************************************************************
+//
+// QueryTable implementation
+//
+// ****************************************************************************
+
+/**
+ * TODO
+ *
+ * - Collapse 2- & 3- groups when they are identical
+ * - Way more test cases (especially splits & transfers)
+ * - Option to collapse splits
+ * - Option to exclude transfers
+ *
+ */
+
+QueryTable::QueryTable(const MyMoneyReport& _report): ListTable(_report)
+{
+ // seperated into its own method to allow debugging (setting breakpoints
+ // directly in ctors somehow does not work for me (ipwizard))
+ // TODO: remove the init() method and move the code back to the ctor
+ init();
+}
+
+void QueryTable::init(void)
+{
+ switch ( m_config.rowType() )
+ {
+ case MyMoneyReport::eAccountByTopAccount:
+ case MyMoneyReport::eEquityType:
+ case MyMoneyReport::eAccountType:
+ case MyMoneyReport::eInstitution:
+ constructAccountTable();
+ m_columns="account";
+ break;
+
+ case MyMoneyReport::eAccount:
+ constructTransactionTable();
+ m_columns="accountid,postdate";
+ break;
+
+ case MyMoneyReport::ePayee:
+ case MyMoneyReport::eMonth:
+ case MyMoneyReport::eWeek:
+ constructTransactionTable();
+ m_columns="postdate,account";
+ break;
+ case MyMoneyReport::eCashFlow:
+ constructSplitsTable();
+ m_columns="postdate";
+ break;
+ default:
+ constructTransactionTable();
+ m_columns="postdate";
+ }
+
+ // Sort the data to match the report definition
+ m_subtotal="value";
+
+ switch ( m_config.rowType() )
+ {
+ case MyMoneyReport::eCashFlow:
+ m_group = "categorytype,topcategory,category";
+ break;
+ case MyMoneyReport::eCategory:
+ m_group = "categorytype,topcategory,category";
+ break;
+ case MyMoneyReport::eTopCategory:
+ m_group = "categorytype,topcategory";
+ break;
+ case MyMoneyReport::eTopAccount:
+ m_group = "topaccount,account";
+ break;
+ case MyMoneyReport::eAccount:
+ m_group = "account";
+ break;
+ case MyMoneyReport::eAccountReconcile:
+ m_group = "account,reconcileflag";
+ break;
+ case MyMoneyReport::ePayee:
+ m_group = "payee";
+ break;
+ case MyMoneyReport::eMonth:
+ m_group = "month";
+ break;
+ case MyMoneyReport::eWeek:
+ m_group = "week";
+ break;
+ case MyMoneyReport::eAccountByTopAccount:
+ m_group = "topaccount";
+ break;
+ case MyMoneyReport::eEquityType:
+ m_group = "equitytype";
+ break;
+ case MyMoneyReport::eAccountType:
+ m_group = "type";
+ break;
+ case MyMoneyReport::eInstitution:
+ m_group = "institution,topaccount";
+ break;
+ default:
+ throw new MYMONEYEXCEPTION("QueryTable::QueryTable(): unhandled row type");
+ }
+
+ QString sort = m_group + "," + m_columns + ",id,rank";
+
+ switch (m_config.rowType()) {
+ case MyMoneyReport::eAccountByTopAccount:
+ case MyMoneyReport::eEquityType:
+ case MyMoneyReport::eAccountType:
+ case MyMoneyReport::eInstitution:
+ m_columns="account";
+ break;
+
+ default:
+ m_columns="postdate";
+ }
+
+ unsigned qc = m_config.queryColumns();
+
+ if ( qc & MyMoneyReport::eQCnumber )
+ m_columns += ",number";
+ if ( qc & MyMoneyReport::eQCpayee )
+ m_columns += ",payee";
+ if ( qc & MyMoneyReport::eQCcategory )
+ m_columns += ",category";
+ if ( qc & MyMoneyReport::eQCaccount )
+ m_columns += ",account";
+ if ( qc & MyMoneyReport::eQCreconciled )
+ m_columns += ",reconcileflag";
+ if ( qc & MyMoneyReport::eQCmemo )
+ m_columns += ",memo";
+ if ( qc & MyMoneyReport::eQCaction )
+ m_columns += ",action";
+ if ( qc & MyMoneyReport::eQCshares )
+ m_columns += ",shares";
+ if ( qc & MyMoneyReport::eQCprice )
+ m_columns += ",price";
+ if ( qc & MyMoneyReport::eQCperformance )
+ m_columns += ",startingbal,buys,sells,reinvestincome,cashincome,return,returninvestment";
+ if ( qc & MyMoneyReport::eQCloan )
+ {
+ m_columns += ",payment,interest,fees";
+ m_postcolumns = "balance";
+ }
+ if ( qc & MyMoneyReport::eQCbalance)
+ m_postcolumns = "balance";
+
+ TableRow::setSortCriteria(sort);
+ qHeapSort(m_rows);
+}
+
+void QueryTable::constructTransactionTable(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //make sure we have all subaccounts of investment accounts
+ includeInvestmentSubAccounts();
+
+ MyMoneyReport report(m_config);
+ report.setReportAllSplits(false);
+ report.setConsiderCategory(true);
+
+ bool use_transfers;
+ bool use_summary;
+ bool hide_details;
+
+ switch (m_config.rowType()) {
+ case MyMoneyReport::eCategory:
+ case MyMoneyReport::eTopCategory:
+ use_summary = false;
+ use_transfers = false;
+ hide_details = false;
+ break;
+ case MyMoneyReport::ePayee:
+ use_summary = false;
+ use_transfers = false;
+ hide_details = (m_config.detailLevel() == MyMoneyReport::eDetailNone);
+ break;
+ default:
+ use_summary = true;
+ use_transfers = true;
+ hide_details = (m_config.detailLevel() == MyMoneyReport::eDetailNone);
+ break;
+ }
+
+ // support for opening and closing balances
+ QMap<QString, MyMoneyAccount> accts;
+
+ //get all transactions for this report
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(report);
+ for (QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin(); it_transaction != transactions.end(); ++it_transaction) {
+
+ TableRow qA, qS;
+ QDate pd;
+
+ qA["id"] = qS["id"] = (* it_transaction).id();
+ qA["entrydate"] = qS["entrydate"] = (* it_transaction).entryDate().toString(Qt::ISODate);
+ qA["postdate"] = qS["postdate"] = (* it_transaction).postDate().toString(Qt::ISODate);
+ qA["commodity"] = qS["commodity"] = (* it_transaction).commodity();
+
+ pd = (* it_transaction).postDate();
+ qA["month"] = qS["month"] = i18n("Month of %1").arg(QDate(pd.year(),pd.month(),1).toString(Qt::ISODate));
+ qA["week"] = qS["week"] = i18n("Week of %1").arg(pd.addDays(1-pd.dayOfWeek()).toString(Qt::ISODate));
+
+ qA["currency"] = qS["currency"] = "";
+
+ if((* it_transaction).commodity() != file->baseCurrency().id()) {
+ if (!report.isConvertCurrency()) {
+ qA["currency"] = qS["currency"] = (*it_transaction).commodity();
+ }
+ }
+
+ // to handle splits, we decide on which account to base the split
+ // (a reference point or point of view so to speak). here we take the
+ // first account that is a stock account or loan account (or the first account
+ // that is not an income or expense account if there is no stock or loan account)
+ // to be the account (qA) that will have the sub-item "split" entries. we add
+ // one transaction entry (qS) for each subsequent entry in the split.
+
+ const QValueList<MyMoneySplit>& splits = (*it_transaction).splits();
+ QValueList<MyMoneySplit>::const_iterator myBegin, it_split;
+ //S_end = splits.end();
+
+ for (it_split = splits.begin(), myBegin = splits.end(); it_split != splits.end(); ++it_split) {
+ ReportAccount splitAcc = (* it_split).accountId();
+ // always put split with a "stock" account if it exists
+ if (splitAcc.isInvest())
+ break;
+
+ // prefer to put splits with a "loan" account if it exists
+ if(splitAcc.isLoan())
+ myBegin = it_split;
+
+ if((myBegin == splits.end()) && ! splitAcc.isIncomeExpense()) {
+ myBegin = it_split;
+ }
+ }
+
+ // select our "reference" split
+ if (it_split == splits.end()) {
+ it_split = myBegin;
+ } else {
+ myBegin = it_split;
+ }
+
+ // if the split is still unknown, use the first one. I have seen this
+ // happen with a transaction that has only a single split referencing an income or expense
+ // account and has an amount and value of 0. Such a transaction will fall through
+ // the above logic and leave 'it_split' pointing to splits.end() which causes the remainder
+ // of this to end in an infinite loop.
+ if(it_split == splits.end()) {
+ it_split = splits.begin();
+ }
+
+ // for "loan" reports, the loan transaction gets special treatment.
+ // the splits of a loan transaction are placed on one line in the
+ // reference (loan) account (qA). however, we process the matching
+ // split entries (qS) normally.
+
+ bool loan_special_case = false;
+ if(m_config.queryColumns() & MyMoneyReport::eQCloan) {
+ ReportAccount splitAcc = (*it_split).accountId();
+ loan_special_case = splitAcc.isLoan();
+ }
+
+#if 0
+ // a stock dividend or yield transaction is also a special case.
+ // [dv: the original comment follows]
+ // handle cash dividends. these little fellas require very special handling.
+ // the stock account will produce a row with zero value & zero shares. Then
+ // there will be 2 split rows, a category and a transfer account. We are
+ // only concerned with the transfer account, and we will NOT show the income
+ // account. (This may have to be changed later if we feel we need it.)
+
+ // [dv: this special case just doesn't make sense to me -- it seems to
+ // violate the "zero sum" transaction concept. for now, then, the stock
+ // dividend / yield special case goes unimplemented.]
+
+ bool stock_special_case =
+ (a.isInvest() &&
+ ((* is).action() == MyMoneySplit::ActionDividend ||
+ (* is).action() == MyMoneySplit::ActionYield));
+#endif
+
+ bool include_me = true;
+ bool transaction_text = false; //indicates whether a text should be considered as a match for the transaction or for a split only
+ QString a_fullname = "";
+ QString a_memo = "";
+ unsigned int pass = 1;
+ QString myBeginCurrency = (file->account((*myBegin).accountId())).currencyId(); //currency of the main split
+ do {
+ MyMoneyMoney xr;
+ ReportAccount splitAcc = (* it_split).accountId();
+
+ //use the fraction relevant to the account at hand
+ int fraction = splitAcc.currency().smallestAccountFraction();
+
+ //use base currency fraction if not initialized
+ if(fraction == -1)
+ fraction = file->baseCurrency().smallestAccountFraction();
+
+ QString institution = splitAcc.institutionId();
+ QString payee = (*it_split).payeeId();
+
+ //convert to base currency
+ if ( m_config.isConvertCurrency() ) {
+ xr = (splitAcc.deepCurrencyPrice((*it_transaction).postDate()) * splitAcc.baseCurrencyPrice((*it_transaction).postDate())).reduce();
+ } else {
+ xr = (splitAcc.deepCurrencyPrice((*it_transaction).postDate())).reduce();
+ //if the currency of the split is different from the currency of the main split, then convert to the currency of the main split
+ if(splitAcc.currency().id() != myBeginCurrency) {
+ xr = (xr * splitAcc.foreignCurrencyPrice(myBeginCurrency, (*it_transaction).postDate())).reduce();
+ }
+ }
+
+ if (splitAcc.isInvest()) {
+
+ // use the institution of the parent for stock accounts
+ institution = splitAcc.parent().institutionId();
+ MyMoneyMoney shares = (*it_split).shares();
+
+ qA["action"] = (*it_split).action();
+ qA["shares"] = shares.isZero() ? "" : (*it_split).shares().toString();
+ qA["price"] = shares.isZero() ? "" : xr.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+
+ if (((*it_split).action() == MyMoneySplit::ActionBuyShares) && (*it_split).shares().isNegative())
+ qA["action"] = "Sell";
+
+ qA["investaccount"] = splitAcc.parent().name();
+ }
+
+ if (it_split == myBegin) {
+
+ include_me = m_config.includes(splitAcc);
+ a_fullname = splitAcc.fullName();
+ a_memo = (*it_split).memo();
+
+ transaction_text = m_config.match(&(*it_split));
+
+ qA["price"] = xr.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+ qA["account"] = splitAcc.name();
+ qA["accountid"] = splitAcc.id();
+ qA["topaccount"] = splitAcc.topParentName();
+
+ qA["institution"] = institution.isEmpty()
+ ? i18n("No Institution")
+ : file->institution(institution).name();
+
+ qA["payee"] = payee.isEmpty()
+ ? i18n("[Empty Payee]")
+ : file->payee(payee).name().simplifyWhiteSpace();
+
+ qA["reconciledate"] = (*it_split).reconcileDate().toString(Qt::ISODate);
+ qA["reconcileflag"] = KMyMoneyUtils::reconcileStateToString((*it_split).reconcileFlag(), true );
+ qA["number"] = (*it_split).number();
+
+ qA["memo"] = a_memo;
+
+ qS["reconciledate"] = qA["reconciledate"];
+ qS["reconcileflag"] = qA["reconcileflag"];
+ qS["number"] = qA["number"];
+
+ qS["topcategory"] = splitAcc.topParentName();
+ qS["categorytype"] = i18n("Transfer");
+
+ // only include the configured accounts
+ if (include_me) {
+
+ if (loan_special_case) {
+
+ // put the principal amount in the "value" column and convert to lowest fraction
+ qA["value"] = ((-(*it_split).shares()) * xr).convert(fraction).toString();
+
+ qA["rank"] = "0";
+ qA["split"] = "";
+
+ } else {
+ if ((splits.count() > 2) && use_summary) {
+
+ // add the "summarized" split transaction
+ // this is the sub-total of the split detail
+ // convert to lowest fraction
+ qA["value"] = ((*it_split).shares() * xr).convert(fraction).toString();
+ qA["rank"] = "0";
+ qA["category"] = i18n("[Split Transaction]");
+ qA["topcategory"] = i18n("Split");
+ qA["categorytype"] = i18n("Split");
+
+ m_rows += qA;
+ }
+ }
+
+ // track accts that will need opening and closing balances
+ //FIXME in some cases it will show the opening and closing
+ //balances but no transactions if the splits are all filtered out -- asoliverez
+ accts.insert (splitAcc.id(), splitAcc);
+ }
+
+ } else {
+
+ if (include_me) {
+
+ if (loan_special_case) {
+ MyMoneyMoney value = ((-(* it_split).shares()) * xr).convert(fraction);
+
+ if ((*it_split).action() == MyMoneySplit::ActionAmortization) {
+ // put the payment in the "payment" column and convert to lowest fraction
+ qA["payment"] = value.toString();
+ }
+ else if ((*it_split).action() == MyMoneySplit::ActionInterest) {
+ // put the interest in the "interest" column and convert to lowest fraction
+ qA["interest"] = value.toString();
+ }
+ else if (splits.count() > 2) {
+ // [dv: This comment carried from the original code. I am
+ // not exactly clear on what it means or why we do this.]
+ // Put the initial pay-in nowhere (that is, ignore it). This
+ // is dangerous, though. The only way I can tell the initial
+ // pay-in apart from fees is if there are only 2 splits in
+ // the transaction. I wish there was a better way.
+ }
+ else {
+ // accumulate everything else in the "fees" column
+ MyMoneyMoney n0 = MyMoneyMoney(qA["fees"]);
+ qA["fees"] = (n0 + value).toString();
+ }
+ // we don't add qA here for a loan transaction. we'll add one
+ // qA afer all of the split components have been processed.
+ // (see below)
+
+ }
+
+ //--- special case to hide split transaction details
+ else if (hide_details && (splits.count() > 2)) {
+ // essentially, don't add any qA entries
+ }
+
+ //--- default case includes all transaction details
+ else {
+
+ //this is when the splits are going to be shown as children of the main split
+ if ((splits.count() > 2) && use_summary) {
+ qA["value"] = "";
+
+ //convert to lowest fraction
+ qA["split"] = ((-(*it_split).shares()) * xr).convert(fraction).toString();
+ qA["rank"] = "1";
+ } else {
+ //this applies when the transaction has only 2 splits, or each split is going to be
+ //shown separately, eg. transactions by category
+
+ qA["split"] = "";
+
+ //multiply by currency and convert to lowest fraction
+ qA["value"] = ((-(*it_split).shares()) * xr).convert(fraction).toString();
+ qA["rank"] = "0";
+ }
+
+ qA ["memo"] = (*it_split).memo();
+
+ if (! splitAcc.isIncomeExpense()) {
+ qA["category"] = ((*it_split).shares().isNegative()) ?
+ i18n("Transfer from %1").arg(splitAcc.fullName())
+ : i18n("Transfer to %1").arg(splitAcc.fullName());
+ qA["topcategory"] = splitAcc.topParentName();
+ qA["categorytype"] = i18n("Transfer");
+ }
+ else {
+ qA ["category"] = splitAcc.fullName();
+ qA ["topcategory"] = splitAcc.topParentName();
+ qA ["categorytype"] = KMyMoneyUtils::accountTypeToString(splitAcc.accountGroup());
+ }
+
+ if (use_transfers || (splitAcc.isIncomeExpense() && m_config.includes(splitAcc)))
+ {
+ //if it matches the text of the main split of the transaction or
+ //it matches this particular split, include it
+ //otherwise, skip it
+ //if the filter is "does not contain" exclude the split if it does not match
+ //even it matches the whole split
+ if((m_config.isInvertingText() &&
+ m_config.match( &(*it_split) ))
+ || ( !m_config.isInvertingText()
+ && (transaction_text
+ || m_config.match( &(*it_split) )))) {
+ m_rows += qA;
+ }
+ }
+ }
+ }
+
+ if (m_config.includes(splitAcc) && use_transfers) {
+ if (! splitAcc.isIncomeExpense()) {
+
+ //multiply by currency and convert to lowest fraction
+ qS["value"] = ((*it_split).shares() * xr).convert(fraction).toString();
+
+ qS["rank"] = "0";
+
+ qS["account"] = splitAcc.name();
+ qS["accountid"] = splitAcc.id();
+ qS["topaccount"] = splitAcc.topParentName();
+
+ qS["category"] = ((*it_split).shares().isNegative())
+ ? i18n("Transfer to %1").arg(a_fullname)
+ : i18n("Transfer from %1").arg(a_fullname);
+
+ qS["institution"] = institution.isEmpty()
+ ? i18n("No Institution")
+ : file->institution(institution).name();
+
+ qS["memo"] = (*it_split).memo().isEmpty()
+ ? a_memo
+ : (*it_split).memo();
+
+ qS["payee"] = payee.isEmpty()
+ ? qA["payee"]
+ : file->payee(payee).name().simplifyWhiteSpace();
+
+ //check the specific split against the filter for text and amount
+ //TODO this should be done at the engine, but I have no clear idea how -- asoliverez
+ //if the filter is "does not contain" exclude the split if it does not match
+ //even it matches the whole split
+ if((m_config.isInvertingText() &&
+ m_config.match( &(*it_split) ))
+ || ( !m_config.isInvertingText()
+ && (transaction_text
+ || m_config.match( &(*it_split) )))) {
+ m_rows += qS;
+
+ // track accts that will need opening and closing balances
+ accts.insert (splitAcc.id(), splitAcc);
+ }
+ }
+ }
+ }
+
+ ++it_split;
+
+ // look for wrap-around
+ if (it_split == splits.end())
+ it_split = splits.begin();
+
+ // but terminate if this transaction has only a single split
+ if(splits.count() < 2)
+ break;
+
+ //check if there have been more passes than there are splits
+ //this is to prevent infinite loops in cases of data inconsistency -- asoliverez
+ ++pass;
+ if( pass > splits.count() )
+ break;
+
+ } while (it_split != myBegin);
+
+ if (loan_special_case) {
+ m_rows += qA;
+ }
+ }
+
+ // now run through our accts list and add opening and closing balances
+
+ switch (m_config.rowType()) {
+ case MyMoneyReport::eAccount:
+ case MyMoneyReport::eTopAccount:
+ break;
+
+ // case MyMoneyReport::eCategory:
+ // case MyMoneyReport::eTopCategory:
+ // case MyMoneyReport::ePayee:
+ // case MyMoneyReport::eMonth:
+ // case MyMoneyReport::eWeek:
+ default:
+ return;
+ }
+
+ QDate startDate, endDate;
+
+ report.validDateRange(startDate, endDate);
+ QString strStartDate = startDate.toString(Qt::ISODate);
+ QString strEndDate = endDate.toString(Qt::ISODate);
+ startDate = startDate.addDays(-1);
+
+ QMap<QString, MyMoneyAccount>::const_iterator it_account, accts_end;
+ for (it_account = accts.begin(); it_account != accts.end(); ++it_account) {
+ TableRow qA;
+
+ ReportAccount account = (* it_account);
+
+ //get fraction for account
+ int fraction = account.currency().smallestAccountFraction();
+
+ //use base currency fraction if not initialized
+ if(fraction == -1)
+ fraction = file->baseCurrency().smallestAccountFraction();
+
+ QString institution = account.institutionId();
+
+ // use the institution of the parent for stock accounts
+ if (account.isInvest())
+ institution = account.parent().institutionId();
+
+ MyMoneyMoney startBalance, endBalance, startPrice, endPrice;
+ MyMoneyMoney startShares, endShares;
+
+ //get price and convert currency if necessary
+ if ( m_config.isConvertCurrency() ) {
+ startPrice = (account.deepCurrencyPrice(startDate) * account.baseCurrencyPrice(startDate)).reduce();
+ endPrice = (account.deepCurrencyPrice(endDate) * account.baseCurrencyPrice(endDate)).reduce();
+ } else {
+ startPrice = account.deepCurrencyPrice(startDate).reduce();
+ endPrice = account.deepCurrencyPrice(endDate).reduce();
+ }
+ startShares = file->balance(account.id(),startDate);
+ endShares = file->balance(account.id(),endDate);
+
+ //get starting and ending balances
+ startBalance = startShares * startPrice;
+ endBalance = endShares * endPrice;
+
+ //starting balance
+ // don't show currency if we're converting or if it's not foreign
+ qA["currency"] = (m_config.isConvertCurrency() || ! account.isForeignCurrency()) ? "" : account.currency().id();
+
+ qA["accountid"] = account.id();
+ qA["account"] = account.name();
+ qA["topaccount"] = account.topParentName();
+ qA["institution"] = institution.isEmpty() ? i18n("No Institution") : file->institution(institution).name();
+ qA["rank"] = "-2";
+
+ qA["price"] = startPrice.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+ if (account.isInvest()) {
+ qA["shares"] = startShares.toString();
+ }
+
+ qA["postdate"] = strStartDate;
+ qA["balance"] = startBalance.convert(fraction).toString();
+ qA["value"] = QString();
+ qA["id"] = "A";
+ m_rows += qA;
+
+ //ending balance
+ qA["price"] = endPrice.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+
+ if (account.isInvest()) {
+ qA["shares"] = endShares.toString();
+ }
+
+ qA["postdate"] = strEndDate;
+ qA["balance"] = endBalance.toString();
+ qA["id"] = "Z";
+ m_rows += qA;
+ }
+}
+
+void QueryTable::constructPerformanceRow( const ReportAccount& account, TableRow& result ) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneySecurity security = file->security(account.currencyId());
+
+ result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType());
+
+ //set fraction
+ int fraction = account.currency().smallestAccountFraction();
+
+ //
+ // Calculate performance
+ //
+
+ // The following columns are created:
+ // Account, Value on <Opening>, Buys, Sells, Income, Value on <Closing>, Return%
+
+ MyMoneyReport report = m_config;
+ QDate startingDate;
+ QDate endingDate;
+ MyMoneyMoney price;
+ report.validDateRange( startingDate, endingDate );
+ startingDate = startingDate.addDays(-1);
+
+ //calculate starting balance
+ if ( m_config.isConvertCurrency() ) {
+ price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate);
+ } else {
+ price = account.deepCurrencyPrice(startingDate);
+ }
+
+ //work around if there is no price for the starting balance
+ if(!(file->balance(account.id(),startingDate)).isZero()
+ && account.deepCurrencyPrice(startingDate) == MyMoneyMoney(1, 1))
+ {
+ MyMoneyTransactionFilter filter;
+ //get the transactions for the time before the report
+ filter.setDateFilter(QDate(), startingDate);
+ filter.addAccount(account.id());
+ filter.setReportAllSplits(true);
+
+ QValueList<MyMoneyTransaction> startTransactions = file->transactionList(filter);
+ if(startTransactions.size() > 0)
+ {
+ //get the last transaction
+ MyMoneyTransaction startTrans = startTransactions.back();
+ MyMoneySplit s = startTrans.splitByAccount(account.id());
+ //get the price from the split of that account
+ price = s.price();
+ if ( m_config.isConvertCurrency() )
+ price = price * account.baseCurrencyPrice(startingDate);
+ }
+ }if ( m_config.isConvertCurrency() ) {
+ price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate);
+ } else {
+ price = account.deepCurrencyPrice(startingDate);
+ }
+
+
+ MyMoneyMoney startingBal = file->balance(account.id(),startingDate) * price;
+
+ //convert to lowest fraction
+ startingBal = startingBal.convert(fraction);
+
+ //calculate ending balance
+ if ( m_config.isConvertCurrency() ) {
+ price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate);
+ } else {
+ price = account.deepCurrencyPrice(endingDate);
+ }
+ MyMoneyMoney endingBal = file->balance((account).id(),endingDate) * price;
+
+ //convert to lowest fraction
+ endingBal = endingBal.convert(fraction);
+
+ //add start balance to calculate return on investment
+ MyMoneyMoney returnInvestment = startingBal;
+ MyMoneyMoney paidDividend;
+ CashFlowList buys;
+ CashFlowList sells;
+ CashFlowList reinvestincome;
+ CashFlowList cashincome;
+
+ report.setReportAllSplits(false);
+ report.setConsiderCategory(true);
+ report.clearAccountFilter();
+ report.addAccount(account.id());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList( report );
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ // s is the split for the stock account
+ MyMoneySplit s = (*it_transaction).splitByAccount(account.id());
+
+ //get price for the day of the transaction if we have to calculate base currency
+ //we are using the value of the split which is in deep currency
+ if ( m_config.isConvertCurrency() ) {
+ price = account.baseCurrencyPrice((*it_transaction).postDate()); //we only need base currency because the value is in deep currency
+ } else {
+ price = MyMoneyMoney(1,1);
+ }
+
+ MyMoneyMoney value = s.value() * price;
+
+ const QString& action = s.action();
+ if ( action == MyMoneySplit::ActionBuyShares )
+ {
+ if ( s.value().isPositive() ) {
+ buys += CashFlowListItem( (*it_transaction).postDate(), -value );
+ } else {
+ sells += CashFlowListItem( (*it_transaction).postDate(), -value );
+ }
+ returnInvestment += value;
+ //convert to lowest fraction
+ returnInvestment = returnInvestment.convert(fraction);
+ } else if ( action == MyMoneySplit::ActionReinvestDividend ) {
+ reinvestincome += CashFlowListItem( (*it_transaction).postDate(), value );
+ } else if ( action == MyMoneySplit::ActionDividend || action == MyMoneySplit::ActionYield ) {
+ // find the split with the category, which has the actual amount of the dividend
+ QValueList<MyMoneySplit> splits = (*it_transaction).splits();
+ QValueList<MyMoneySplit>::const_iterator it_split = splits.begin();
+ bool found = false;
+ while( it_split != splits.end() ) {
+ ReportAccount acc = (*it_split).accountId();
+ if ( acc.isIncomeExpense() ) {
+ found = true;
+ break;
+ }
+ ++it_split;
+ }
+
+ if ( found ) {
+ cashincome += CashFlowListItem( (*it_transaction).postDate(), -(*it_split).value() * price);
+ paidDividend += ((-(*it_split).value()) * price).convert(fraction);
+ }
+ } else {
+ //if the split does not match any action above, add it as buy or sell depending on sign
+
+ //if value is zero, get the price for that date
+ if( s.value().isZero() ) {
+ if ( m_config.isConvertCurrency() ) {
+ price = account.deepCurrencyPrice((*it_transaction).postDate()) * account.baseCurrencyPrice((*it_transaction).postDate());
+ } else {
+ price = account.deepCurrencyPrice((*it_transaction).postDate());
+ }
+ value = s.shares() * price;
+ if ( s.shares().isPositive() ) {
+ buys += CashFlowListItem( (*it_transaction).postDate(), -value );
+ } else {
+ sells += CashFlowListItem( (*it_transaction).postDate(), -value );
+ }
+ returnInvestment += value;
+ } else {
+ value = s.value() * price;
+ if ( s.value().isPositive() ) {
+ buys += CashFlowListItem( (*it_transaction).postDate(), -value );
+ } else {
+ sells += CashFlowListItem( (*it_transaction).postDate(), -value );
+ }
+ returnInvestment += value;
+ }
+ }
+ ++it_transaction;
+ }
+
+ // Note that reinvested dividends are not included , because these do not
+ // represent a cash flow event.
+ CashFlowList all;
+ all += buys;
+ all += sells;
+ all += cashincome;
+ all += CashFlowListItem(startingDate, -startingBal);
+ all += CashFlowListItem(endingDate, endingBal);
+
+ //check if no activity on that term
+ if(!returnInvestment.isZero() && !endingBal.isZero()) {
+ returnInvestment = ((endingBal + paidDividend) - returnInvestment)/returnInvestment;
+ returnInvestment = returnInvestment.convert(10000);
+ } else {
+ returnInvestment = MyMoneyMoney(0,1);
+ }
+
+ try
+ {
+ MyMoneyMoney annualReturn = MyMoneyMoney(all.IRR(),10000);
+ result["return"] = annualReturn.toString();
+ result["returninvestment"] = returnInvestment.toString();
+ }
+ catch (QString e)
+ {
+ kdDebug(2) << e << endl;
+ }
+
+ result["buys"] = (-(buys.total())).toString();
+ result["sells"] = (-(sells.total())).toString();
+ result["cashincome"] = (cashincome.total()).toString();
+ result["reinvestincome"] = (reinvestincome.total()).toString();
+ result["startingbal"] = (startingBal).toString();
+ result["endingbal"] = (endingBal).toString();
+}
+
+void QueryTable::constructAccountTable(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //make sure we have all subaccounts of investment accounts
+ includeInvestmentSubAccounts();
+
+ QValueList<MyMoneyAccount> accounts;
+ file->accountList(accounts);
+ QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin();
+ while ( it_account != accounts.end() )
+ {
+ ReportAccount account = *it_account;
+
+ //get fraction for account
+ int fraction = account.currency().smallestAccountFraction();
+
+ //use base currency fraction if not initialized
+ if(fraction == -1)
+ fraction = MyMoneyFile::instance()->baseCurrency().smallestAccountFraction();
+
+ // Note, "Investment" accounts are never included in account rows because
+ // they don't contain anything by themselves. In reports, they are only
+ // useful as a "topaccount" aggregator of stock accounts
+ if ( account.isAssetLiability() && m_config.includes(account) && account.accountType() != MyMoneyAccount::Investment )
+ {
+ TableRow qaccountrow;
+
+ // help for sort and render functions
+ qaccountrow["rank"] = "0";
+
+ //
+ // Handle currency conversion
+ //
+
+ MyMoneyMoney displayprice(1.0);
+ if ( m_config.isConvertCurrency() )
+ {
+ // display currency is base currency, so set the price
+ if ( account.isForeignCurrency() )
+ displayprice = account.baseCurrencyPrice(m_config.toDate()).reduce();
+ }
+ else
+ {
+ // display currency is the account's deep currency. display this fact in the report
+ qaccountrow["currency"] = account.currency().id();
+ }
+
+ qaccountrow["account"] = account.name();
+ qaccountrow["accountid"] = account.id();
+ qaccountrow["topaccount"] = account.topParentName();
+
+ MyMoneyMoney shares = file->balance(account.id(),m_config.toDate());
+ qaccountrow["shares"] = shares.toString();
+
+ MyMoneyMoney netprice = account.deepCurrencyPrice(m_config.toDate()).reduce() * displayprice;
+ qaccountrow["price"] = ( netprice.reduce() ).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+ qaccountrow["value"] = ( netprice.reduce() * shares.reduce() ).convert(fraction).toString();
+
+ QString iid = (*it_account).institutionId();
+
+ // If an account does not have an institution, get it from the top-parent.
+ if ( iid.isEmpty() && ! account.isTopLevel() )
+ {
+ ReportAccount topaccount = account.topParent();
+ iid = topaccount.institutionId();
+ }
+
+ if ( iid.isEmpty() )
+ qaccountrow["institution"] = i18n("None");
+ else
+ qaccountrow["institution"] = file->institution(iid).name();
+
+ qaccountrow["type"] = KMyMoneyUtils::accountTypeToString((*it_account).accountType());
+
+ // TODO: Only do this if the report we're making really needs performance. Otherwise
+ // it's an expensive calculation done for no reason
+ if ( account.isInvest() )
+ {
+ constructPerformanceRow( account, qaccountrow );
+ }
+ else
+ qaccountrow["equitytype"] = QString();
+
+ // don't add the account if it is closed. In fact, the business logic
+ // should prevent that an account can be closed with a balance not equal
+ // to zero, but we never know.
+ if(!(shares.isZero() && account.isClosed()))
+ m_rows += qaccountrow;
+ }
+
+ ++it_account;
+ }
+}
+
+void QueryTable::constructSplitsTable(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //make sure we have all subaccounts of investment accounts
+ includeInvestmentSubAccounts();
+
+ MyMoneyReport report(m_config);
+ report.setReportAllSplits(false);
+ report.setConsiderCategory(true);
+
+ // support for opening and closing balances
+ QMap<QString, MyMoneyAccount> accts;
+
+ //get all transactions for this report
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(report);
+ for (QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin(); it_transaction != transactions.end(); ++it_transaction) {
+
+ TableRow qA, qS;
+ QDate pd;
+
+ qA["id"] = qS["id"] = (* it_transaction).id();
+ qA["entrydate"] = qS["entrydate"] = (* it_transaction).entryDate().toString(Qt::ISODate);
+ qA["postdate"] = qS["postdate"] = (* it_transaction).postDate().toString(Qt::ISODate);
+ qA["commodity"] = qS["commodity"] = (* it_transaction).commodity();
+
+ pd = (* it_transaction).postDate();
+ qA["month"] = qS["month"] = i18n("Month of %1").arg(QDate(pd.year(),pd.month(),1).toString(Qt::ISODate));
+ qA["week"] = qS["week"] = i18n("Week of %1").arg(pd.addDays(1-pd.dayOfWeek()).toString(Qt::ISODate));
+
+ qA["currency"] = qS["currency"] = "";
+
+ if((* it_transaction).commodity() != file->baseCurrency().id()) {
+ if (!report.isConvertCurrency()) {
+ qA["currency"] = qS["currency"] = (*it_transaction).commodity();
+ }
+ }
+
+ // to handle splits, we decide on which account to base the split
+ // (a reference point or point of view so to speak). here we take the
+ // first account that is a stock account or loan account (or the first account
+ // that is not an income or expense account if there is no stock or loan account)
+ // to be the account (qA) that will have the sub-item "split" entries. we add
+ // one transaction entry (qS) for each subsequent entry in the split.
+ const QValueList<MyMoneySplit>& splits = (*it_transaction).splits();
+ QValueList<MyMoneySplit>::const_iterator myBegin, it_split;
+ //S_end = splits.end();
+
+ for (it_split = splits.begin(), myBegin = splits.end(); it_split != splits.end(); ++it_split) {
+ ReportAccount splitAcc = (* it_split).accountId();
+ // always put split with a "stock" account if it exists
+ if (splitAcc.isInvest())
+ break;
+
+ // prefer to put splits with a "loan" account if it exists
+ if(splitAcc.isLoan())
+ myBegin = it_split;
+
+ if((myBegin == splits.end()) && ! splitAcc.isIncomeExpense()) {
+ myBegin = it_split;
+ }
+ }
+
+ // select our "reference" split
+ if (it_split == splits.end()) {
+ it_split = myBegin;
+ } else {
+ myBegin = it_split;
+ }
+
+ // if the split is still unknown, use the first one. I have seen this
+ // happen with a transaction that has only a single split referencing an income or expense
+ // account and has an amount and value of 0. Such a transaction will fall through
+ // the above logic and leave 'it_split' pointing to splits.end() which causes the remainder
+ // of this to end in an infinite loop.
+ if(it_split == splits.end()) {
+ it_split = splits.begin();
+ }
+
+ // for "loan" reports, the loan transaction gets special treatment.
+ // the splits of a loan transaction are placed on one line in the
+ // reference (loan) account (qA). however, we process the matching
+ // split entries (qS) normally.
+ bool loan_special_case = false;
+ if(m_config.queryColumns() & MyMoneyReport::eQCloan) {
+ ReportAccount splitAcc = (*it_split).accountId();
+ loan_special_case = splitAcc.isLoan();
+ }
+
+ //the account of the beginning splits
+ ReportAccount myBeginAcc = (*myBegin).accountId();
+
+ bool include_me = true;
+ bool transaction_text = false; //indicates whether a text should be considered as a match for the transaction or for a split only
+ QString a_fullname = "";
+ QString a_memo = "";
+ unsigned int pass = 1;
+
+ do {
+ MyMoneyMoney xr;
+ ReportAccount splitAcc = (* it_split).accountId();
+
+ //get fraction for account
+ int fraction = splitAcc.currency().smallestAccountFraction();
+
+ //use base currency fraction if not initialized
+ if(fraction == -1)
+ fraction = file->baseCurrency().smallestAccountFraction();
+
+ QString institution = splitAcc.institutionId();
+ QString payee = (*it_split).payeeId();
+
+ if ( m_config.isConvertCurrency() ) {
+ xr = (splitAcc.deepCurrencyPrice((*it_transaction).postDate()) * splitAcc.baseCurrencyPrice((*it_transaction).postDate())).reduce();
+ } else {
+ xr = splitAcc.deepCurrencyPrice((*it_transaction).postDate()).reduce();
+ }
+
+ //there is a bug where the price sometimes returns 1
+ //get the price from the split in that case
+ /*if(m_config.isConvertCurrency() && xr == MyMoneyMoney(1,1)) {
+ xr = (*it_split).price();
+ }*/
+
+ if (splitAcc.isInvest()) {
+
+ // use the institution of the parent for stock accounts
+ institution = splitAcc.parent().institutionId();
+ MyMoneyMoney shares = (*it_split).shares();
+
+ qA["action"] = (*it_split).action();
+ qA["shares"] = shares.isZero() ? "" : (*it_split).shares().toString();
+ qA["price"] = shares.isZero() ? "" : xr.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+
+ if (((*it_split).action() == MyMoneySplit::ActionBuyShares) && (*it_split).shares().isNegative())
+ qA["action"] = "Sell";
+
+ qA["investaccount"] = splitAcc.parent().name();
+ }
+
+ include_me = m_config.includes(splitAcc);
+ a_fullname = splitAcc.fullName();
+ a_memo = (*it_split).memo();
+
+ transaction_text = m_config.match(&(*it_split));
+
+ qA["price"] = xr.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+ qA["account"] = splitAcc.name();
+ qA["accountid"] = splitAcc.id();
+ qA["topaccount"] = splitAcc.topParentName();
+
+ qA["institution"] = institution.isEmpty()
+ ? i18n("No Institution")
+ : file->institution(institution).name();
+
+ qA["payee"] = payee.isEmpty()
+ ? i18n("[Empty Payee]")
+ : file->payee(payee).name().simplifyWhiteSpace();
+
+ qA["reconciledate"] = (*it_split).reconcileDate().toString(Qt::ISODate);
+ qA["reconcileflag"] = KMyMoneyUtils::reconcileStateToString((*it_split).reconcileFlag(), true );
+ qA["number"] = (*it_split).number();
+
+ qA["memo"] = a_memo;
+
+ qS["reconciledate"] = qA["reconciledate"];
+ qS["reconcileflag"] = qA["reconcileflag"];
+ qS["number"] = qA["number"];
+
+ qS["topcategory"] = splitAcc.topParentName();
+
+ // only include the configured accounts
+ if (include_me) {
+ // add the "summarized" split transaction
+ // this is the sub-total of the split detail
+ // convert to lowest fraction
+ qA["value"] = ((*it_split).shares() * xr).convert(fraction).toString();
+ qA["rank"] = "0";
+
+ //fill in account information
+ if (! splitAcc.isIncomeExpense() && it_split != myBegin) {
+ qA["account"] = ((*it_split).shares().isNegative()) ?
+ i18n("Transfer to %1").arg(myBeginAcc.fullName())
+ : i18n("Transfer from %1").arg(myBeginAcc.fullName());
+ } else if (it_split == myBegin ) {
+ //handle the main split
+ if((splits.count() > 2)) {
+ //if it is the main split and has multiple splits, note that
+ qA["account"] = i18n("[Split Transaction]");
+ } else {
+ //fill the account name of the second split
+ QValueList<MyMoneySplit>::const_iterator tempSplit = splits.begin();
+
+ //there are supposed to be only 2 splits if we ever get here
+ if(tempSplit == myBegin && splits.count() > 1)
+ ++tempSplit;
+
+ //show the name of the category, or "transfer to/from" if it as an account
+ ReportAccount tempSplitAcc = (*tempSplit).accountId();
+ if (! tempSplitAcc.isIncomeExpense()) {
+ qA["account"] = ((*it_split).shares().isNegative()) ?
+ i18n("Transfer to %1").arg(tempSplitAcc.fullName())
+ : i18n("Transfer from %1").arg(tempSplitAcc.fullName());
+ } else {
+ qA["account"] = tempSplitAcc.fullName();
+ }
+ }
+ } else {
+ //in any other case, fill in the account name of the main split
+ qA["account"] = myBeginAcc.fullName();
+ }
+
+ //category data is always the one of the split
+ qA ["category"] = splitAcc.fullName();
+ qA ["topcategory"] = splitAcc.topParentName();
+ qA ["categorytype"] = KMyMoneyUtils::accountTypeToString(splitAcc.accountGroup());
+
+ m_rows += qA;
+
+ // track accts that will need opening and closing balances
+ accts.insert (splitAcc.id(), splitAcc);
+ }
+ ++it_split;
+
+ // look for wrap-around
+ if (it_split == splits.end())
+ it_split = splits.begin();
+
+ //check if there have been more passes than there are splits
+ //this is to prevent infinite loops in cases of data inconsistency -- asoliverez
+ ++pass;
+ if( pass > splits.count() )
+ break;
+
+ } while (it_split != myBegin);
+
+ if (loan_special_case) {
+ m_rows += qA;
+ }
+ }
+
+ // now run through our accts list and add opening and closing balances
+
+ switch (m_config.rowType()) {
+ case MyMoneyReport::eAccount:
+ case MyMoneyReport::eTopAccount:
+ break;
+
+ // case MyMoneyReport::eCategory:
+ // case MyMoneyReport::eTopCategory:
+ // case MyMoneyReport::ePayee:
+ // case MyMoneyReport::eMonth:
+ // case MyMoneyReport::eWeek:
+ default:
+ return;
+ }
+
+ QDate startDate, endDate;
+
+ report.validDateRange(startDate, endDate);
+ QString strStartDate = startDate.toString(Qt::ISODate);
+ QString strEndDate = endDate.toString(Qt::ISODate);
+ startDate = startDate.addDays(-1);
+
+ QMap<QString, MyMoneyAccount>::const_iterator it_account, accts_end;
+ for (it_account = accts.begin(); it_account != accts.end(); ++it_account) {
+ TableRow qA;
+
+ ReportAccount account = (* it_account);
+
+ //get fraction for account
+ int fraction = account.currency().smallestAccountFraction();
+
+ //use base currency fraction if not initialized
+ if(fraction == -1)
+ fraction = file->baseCurrency().smallestAccountFraction();
+
+ QString institution = account.institutionId();
+
+ // use the institution of the parent for stock accounts
+ if (account.isInvest())
+ institution = account.parent().institutionId();
+
+ MyMoneyMoney startBalance, endBalance, startPrice, endPrice;
+ MyMoneyMoney startShares, endShares;
+
+ //get price and convert currency if necessary
+ if ( m_config.isConvertCurrency() ) {
+ startPrice = (account.deepCurrencyPrice(startDate) * account.baseCurrencyPrice(startDate)).reduce();
+ endPrice = (account.deepCurrencyPrice(endDate) * account.baseCurrencyPrice(endDate)).reduce();
+ } else {
+ startPrice = account.deepCurrencyPrice(startDate).reduce();
+ endPrice = account.deepCurrencyPrice(endDate).reduce();
+ }
+ startShares = file->balance(account.id(),startDate);
+ endShares = file->balance(account.id(),endDate);
+
+ //get starting and ending balances
+ startBalance = startShares * startPrice;
+ endBalance = endShares * endPrice;
+
+ //starting balance
+ // don't show currency if we're converting or if it's not foreign
+ qA["currency"] = (m_config.isConvertCurrency() || ! account.isForeignCurrency()) ? "" : account.currency().id();
+
+ qA["accountid"] = account.id();
+ qA["account"] = account.name();
+ qA["topaccount"] = account.topParentName();
+ qA["institution"] = institution.isEmpty() ? i18n("No Institution") : file->institution(institution).name();
+ qA["rank"] = "-2";
+
+ qA["price"] = startPrice.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+ if (account.isInvest()) {
+ qA["shares"] = startShares.toString();
+ }
+
+ qA["postdate"] = strStartDate;
+ qA["balance"] = startBalance.convert(fraction).toString();
+ qA["value"] = QString();
+ qA["id"] = "A";
+ m_rows += qA;
+
+ //ending balance
+ qA["price"] = endPrice.convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString();
+
+ if (account.isInvest()) {
+ qA["shares"] = endShares.toString();
+ }
+
+ qA["postdate"] = strEndDate;
+ qA["balance"] = endBalance.toString();
+ qA["id"] = "Z";
+ m_rows += qA;
+ }
+}
+
+}
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/querytable.h b/kmymoney2/reports/querytable.h
new file mode 100644
index 0000000..7beb3d4
--- /dev/null
+++ b/kmymoney2/reports/querytable.h
@@ -0,0 +1,142 @@
+/***************************************************************************
+ querytable.h
+ -------------------
+ begin : Fri Jul 23 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ (C) 2007 Sascha Pfau
+ email : acejones@users.sourceforge.net
+ MrPeacock@gmail.com
+ ***************************************************************************/
+
+/****************************************************************************
+ Contains code from the func_xirr and related methods of financial.cpp
+ - KOffice 1.6 by Sascha Pfau. Sascha agreed to relicense those methods under
+ GPLv2 or later.
+*****************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QUERYTABLE_H
+#define QUERYTABLE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneyreport.h"
+#include "listtable.h"
+
+namespace reports {
+
+class ReportAccount;
+
+/**
+ * Calculates a query of information about the transaction database.
+ *
+ * This is a middle-layer class, between the UI and the engine. The
+ * MyMoneyReport class holds only the CONFIGURATION parameters. This
+ * class actually does the work of retrieving the data from the engine
+ * and formatting it for the user.
+ *
+ * @author Ace Jones
+ *
+ * @short
+**/
+
+class QueryTable : public ListTable
+{
+ public:
+ QueryTable(const MyMoneyReport&);
+ void init(void);
+
+ protected:
+ void constructAccountTable(void);
+ void constructTransactionTable(void);
+ void constructPerformanceRow( const ReportAccount& account, TableRow& result ) const;
+ void constructSplitsTable(void);
+
+};
+
+//
+// Cash Flow analysis tools for investment reports
+//
+
+class CashFlowListItem
+{
+public:
+ CashFlowListItem(void) {}
+ CashFlowListItem( const QDate& _date, const MyMoneyMoney& _value ): m_date(_date), m_value(_value) {}
+ bool operator<( const CashFlowListItem _second ) const { return m_date < _second.m_date; }
+ bool operator<=( const CashFlowListItem _second ) const { return m_date <= _second.m_date; }
+ bool operator>( const CashFlowListItem _second ) const { return m_date > _second.m_date; }
+ const QDate& date( void ) const { return m_date; }
+ const MyMoneyMoney& value( void ) const { return m_value; }
+ MyMoneyMoney NPV( double _rate ) const;
+
+ static void setToday( const QDate& _today ) { m_sToday = _today; }
+ const QDate& today( void ) const { return m_sToday; }
+
+private:
+ QDate m_date;
+ MyMoneyMoney m_value;
+
+ static QDate m_sToday;
+};
+
+class CashFlowList: public QValueList<CashFlowListItem>
+{
+ public:
+ CashFlowList(void) {}
+ MyMoneyMoney NPV(double rate) const;
+ double IRR(void) const;
+ MyMoneyMoney total(void) const;
+ void dumpDebug(void) const;
+
+ /**
+ * Function: XIRR
+ *
+ * Compute the internal rate of return for a non-periodic series of cash flows.
+ *
+ * XIRR ( Values; Dates; [ Guess = 0.1 ] )
+ **/
+ double calculateXIRR ( void ) const;
+
+ protected:
+ CashFlowListItem mostRecent(void) const;
+
+ private:
+ /**
+ * helper: xirrResult
+ *
+ * args[0] = values
+ * args[1] = dates
+ **/
+ double xirrResult ( double& rate ) const;
+
+ /**
+ *
+ * helper: xirrResultDerive
+ *
+ * args[0] = values
+ * args[1] = dates
+ **/
+ double xirrResultDerive ( double& rate ) const;
+};
+
+}
+
+#endif // QUERYREPORT_H
diff --git a/kmymoney2/reports/querytabletest.cpp b/kmymoney2/reports/querytabletest.cpp
new file mode 100644
index 0000000..8b3c579
--- /dev/null
+++ b/kmymoney2/reports/querytabletest.cpp
@@ -0,0 +1,694 @@
+/***************************************************************************
+ querytabletest.cpp
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "querytabletest.h"
+#include "reportstestcommon.h"
+
+#define private public
+#include "querytable.h"
+#undef private
+
+#include "../mymoney/mymoneyaccount.h"
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyprice.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneystatement.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+
+using namespace reports;
+using namespace test;
+
+QueryTableTest::QueryTableTest()
+{
+}
+
+void QueryTableTest::setUp () {
+
+ storage = new MyMoneySeqAccessMgr;
+ file = MyMoneyFile::instance();
+ file->attachStorage(storage);
+ MyMoneyFileTransaction ft;
+ file->addCurrency(MyMoneySecurity("CAD", "Canadian Dollar", "C$"));
+ file->addCurrency(MyMoneySecurity("USD", "US Dollar", "$"));
+ file->addCurrency(MyMoneySecurity("JPY", "Japanese Yen", QChar(0x00A5), 100, 1));
+ file->addCurrency(MyMoneySecurity("GBP", "British Pound", "#"));
+ file->setBaseCurrency(file->currency("USD"));
+
+ MyMoneyPayee payeeTest("Test Payee");
+ file->addPayee(payeeTest);
+ MyMoneyPayee payeeTest2("Thomas Baumgart");
+ file->addPayee(payeeTest2);
+
+ acAsset = (MyMoneyFile::instance()->asset().id());
+ acLiability = (MyMoneyFile::instance()->liability().id());
+ acExpense = (MyMoneyFile::instance()->expense().id());
+ acIncome = (MyMoneyFile::instance()->income().id());
+ acChecking = makeAccount(QString("Checking Account"),MyMoneyAccount::Checkings,moCheckingOpen,QDate(2004,5,15),acAsset);
+ acCredit = makeAccount(QString("Credit Card"),MyMoneyAccount::CreditCard,moCreditOpen,QDate(2004,7,15),acLiability);
+ acSolo = makeAccount(QString("Solo"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acParent = makeAccount(QString("Parent"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acChild = makeAccount(QString("Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent);
+ acForeign = makeAccount(QString("Foreign"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense);
+ acTax = makeAccount(QString("Tax"), MyMoneyAccount::Expense,0,QDate(2005,1,11),acExpense, "", true);
+
+ MyMoneyInstitution i("Bank of the World","","","","","","");
+ file->addInstitution(i);
+ inBank = i.id();
+ ft.commit();
+}
+
+void QueryTableTest::tearDown ()
+{
+ file->detachStorage(storage);
+ delete storage;
+}
+
+void QueryTableTest::testQueryBasics()
+{
+ try
+ {
+ TransactionHelper t1q1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q1( QDate(2004,2,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q1( QDate(2004,3,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4y1( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ TransactionHelper t1q2( QDate(2004,4,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q2( QDate(2004,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q2( QDate(2004,6,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4q2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ TransactionHelper t1y2( QDate(2005,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y2( QDate(2005,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y2( QDate(2005,9,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4y2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ unsigned cols;
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eCategory );
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ filter.setName("Transactions by Category");
+ XMLandback(filter);
+ QueryTable qtbl_1(filter);
+
+ writeTabletoHTML(qtbl_1,"Transactions by Category.html");
+
+ QValueList<ListTable::TableRow> rows = qtbl_1.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 12);
+ CPPUNIT_ASSERT(rows[0]["categorytype"]=="Expense");
+ CPPUNIT_ASSERT(rows[0]["category"]=="Parent");
+ CPPUNIT_ASSERT(rows[0]["postdate"]=="2004-02-01");
+ CPPUNIT_ASSERT(rows[11]["categorytype"]=="Expense");
+ CPPUNIT_ASSERT(rows[11]["category"]=="Solo");
+ CPPUNIT_ASSERT(rows[11]["postdate"]=="2005-01-01");
+
+ QString html = qtbl_1.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Parent") == -(moParent1 + moParent2) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Parent: Child") == -(moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Solo") == -(moSolo) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Expense") == -(moParent1 + moParent2 + moSolo + moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == -(moParent1 + moParent2 + moSolo + moChild) * 3 + moCheckingOpen + moCreditOpen );
+ filter.setRowType( MyMoneyReport::eTopCategory );
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ filter.setName("Transactions by Top Category");
+ XMLandback(filter);
+ QueryTable qtbl_2(filter);
+
+ writeTabletoHTML(qtbl_2,"Transactions by Top Category.html");
+
+ rows = qtbl_2.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 12);
+ CPPUNIT_ASSERT(rows[0]["categorytype"]=="Expense");
+ CPPUNIT_ASSERT(rows[0]["topcategory"]=="Parent");
+ CPPUNIT_ASSERT(rows[0]["postdate"]=="2004-02-01");
+ CPPUNIT_ASSERT(rows[8]["categorytype"]=="Expense");
+ CPPUNIT_ASSERT(rows[8]["topcategory"]=="Parent");
+ CPPUNIT_ASSERT(rows[8]["postdate"]=="2005-09-01");
+ CPPUNIT_ASSERT(rows[11]["categorytype"]=="Expense");
+ CPPUNIT_ASSERT(rows[11]["topcategory"]=="Solo");
+ CPPUNIT_ASSERT(rows[11]["postdate"]=="2005-01-01");
+
+ html = qtbl_2.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Parent") == -(moParent1 + moParent2 + moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Solo") == -(moSolo) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Expense") == -(moParent1 + moParent2 + moSolo + moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == -(moParent1 + moParent2 + moSolo + moChild) * 3 + moCheckingOpen + moCreditOpen);
+
+ filter.setRowType( MyMoneyReport::eAccount );
+ filter.setName("Transactions by Account");
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ XMLandback(filter);
+ QueryTable qtbl_3(filter);
+
+ writeTabletoHTML(qtbl_3,"Transactions by Account.html");
+
+ rows = qtbl_3.rows();
+
+#if 1
+ CPPUNIT_ASSERT(rows.count() == 16);
+ CPPUNIT_ASSERT(rows[1]["account"]=="Checking Account");
+ CPPUNIT_ASSERT(rows[1]["category"]=="Solo");
+ CPPUNIT_ASSERT(rows[1]["postdate"]=="2004-01-01");
+ CPPUNIT_ASSERT(rows[14]["account"]=="Credit Card");
+ CPPUNIT_ASSERT(rows[14]["category"]=="Parent");
+ CPPUNIT_ASSERT(rows[14]["postdate"]=="2005-09-01");
+#else
+ CPPUNIT_ASSERT(rows.count() == 12);
+ CPPUNIT_ASSERT(rows[0]["account"]=="Checking Account");
+ CPPUNIT_ASSERT(rows[0]["category"]=="Solo");
+ CPPUNIT_ASSERT(rows[0]["postdate"]=="2004-01-01");
+ CPPUNIT_ASSERT(rows[11]["account"]=="Credit Card");
+ CPPUNIT_ASSERT(rows[11]["category"]=="Parent");
+ CPPUNIT_ASSERT(rows[11]["postdate"]=="2005-09-01");
+#endif
+
+ html = qtbl_3.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Checking Account") == -(moSolo) * 3 + moCheckingOpen);
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Credit Card") == -(moParent1 + moParent2 + moChild) * 3 + moCreditOpen );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == -(moParent1 + moParent2 + moSolo + moChild) * 3 + moCheckingOpen + moCreditOpen);
+
+ filter.setRowType( MyMoneyReport::ePayee );
+ filter.setName("Transactions by Payee");
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCmemo | MyMoneyReport::eQCcategory;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ XMLandback(filter);
+ QueryTable qtbl_4(filter);
+
+ writeTabletoHTML(qtbl_4,"Transactions by Payee.html");
+
+ rows = qtbl_4.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 12);
+ CPPUNIT_ASSERT(rows[0]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[0]["category"]=="Solo");
+ CPPUNIT_ASSERT(rows[0]["postdate"]=="2004-01-01");
+ CPPUNIT_ASSERT(rows[8]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[8]["category"]=="Parent: Child");
+ CPPUNIT_ASSERT(rows[8]["postdate"]=="2004-11-07");
+ CPPUNIT_ASSERT(rows[11]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[11]["category"]=="Parent");
+ CPPUNIT_ASSERT(rows[11]["postdate"]=="2005-09-01");
+
+ html = qtbl_4.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Test Payee") == -(moParent1 + moParent2 + moSolo + moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == -(moParent1 + moParent2 + moSolo + moChild) * 3 + moCheckingOpen + moCreditOpen);
+
+ filter.setRowType( MyMoneyReport::eMonth );
+ filter.setName("Transactions by Month");
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ XMLandback(filter);
+ QueryTable qtbl_5(filter);
+
+ writeTabletoHTML(qtbl_5,"Transactions by Month.html");
+
+ rows = qtbl_5.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 12);
+ CPPUNIT_ASSERT(rows[0]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[0]["category"]=="Solo");
+ CPPUNIT_ASSERT(rows[0]["postdate"]=="2004-01-01");
+ CPPUNIT_ASSERT(rows[8]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[8]["category"]=="Parent: Child");
+ CPPUNIT_ASSERT(rows[8]["postdate"]=="2004-11-07");
+ CPPUNIT_ASSERT(rows[11]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[11]["category"]=="Parent");
+ CPPUNIT_ASSERT(rows[11]["postdate"]=="2005-09-01");
+
+ html = qtbl_5.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Month of 2004-01-01") == -moSolo );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Month of 2004-11-01") == -(moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Month of 2004-05-01") == -moParent1 + moCheckingOpen );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == -(moParent1 + moParent2 + moSolo + moChild) * 3 + moCheckingOpen + moCreditOpen);
+
+ filter.setRowType( MyMoneyReport::eWeek );
+ filter.setName("Transactions by Week");
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ XMLandback(filter);
+ QueryTable qtbl_6(filter);
+
+ writeTabletoHTML(qtbl_6,"Transactions by Week.html");
+
+ rows = qtbl_6.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 12);
+ CPPUNIT_ASSERT(rows[0]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[0]["category"]=="Solo");
+ CPPUNIT_ASSERT(rows[0]["postdate"]=="2004-01-01");
+ CPPUNIT_ASSERT(rows[11]["payee"]=="Test Payee");
+ CPPUNIT_ASSERT(rows[11]["category"]=="Parent");
+ CPPUNIT_ASSERT(rows[11]["postdate"]=="2005-09-01");
+
+ html = qtbl_6.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Week of 2003-12-29") == -moSolo );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Week of 2004-11-01") == -(moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" Week of 2005-08-29") == -moParent2 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == -(moParent1 + moParent2 + moSolo + moChild) * 3 + moCheckingOpen + moCreditOpen);
+ }
+ catch(MyMoneyException *e)
+ {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+
+ // Test querytable::TableRow::operator> and operator==
+
+ QueryTable::TableRow low;
+ low["first"] = "A";
+ low["second"] = "B";
+ low["third"] = "C";
+
+ QueryTable::TableRow high;
+ high["first"] = "A";
+ high["second"] = "C";
+ high["third"] = "B";
+
+ QueryTable::TableRow::setSortCriteria("first,second,third");
+ CPPUNIT_ASSERT( low < high );
+ CPPUNIT_ASSERT( low <= high );
+ CPPUNIT_ASSERT( high > low );
+ CPPUNIT_ASSERT( high <= high );
+ CPPUNIT_ASSERT( high == high );
+}
+
+void QueryTableTest::testCashFlowAnalysis()
+{
+ //
+ // Test IRR calculations
+ //
+
+ CashFlowList list;
+
+ list += CashFlowListItem( QDate(2004,5,3),1000.0 );
+ list += CashFlowListItem( QDate(2004,5,20),59.0 );
+ list += CashFlowListItem( QDate(2004,6,3),14.0 );
+ list += CashFlowListItem( QDate(2004,6,24),92.0 );
+ list += CashFlowListItem( QDate(2004,7,6),63.0 );
+ list += CashFlowListItem( QDate(2004,7,25),15.0 );
+ list += CashFlowListItem( QDate(2004,8,5),92.0 );
+ list += CashFlowListItem( QDate(2004,9,2),18.0 );
+ list += CashFlowListItem( QDate(2004,9,21),5.0 );
+ list += CashFlowListItem( QDate(2004,10,16),-2037.0 );
+
+ MyMoneyMoney IRR(list.IRR(),1000);
+
+ CPPUNIT_ASSERT( IRR == MyMoneyMoney(1676,1000) );
+
+ list.pop_back();
+ list += CashFlowListItem( QDate(2004,10,16),-1358.0 );
+
+ IRR = MyMoneyMoney( list.IRR(), 1000 );
+
+ CPPUNIT_ASSERT( IRR.isZero() );
+}
+
+void QueryTableTest::testAccountQuery()
+{
+ try
+ {
+ QString htmlcontext = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"html/kmymoney2.css\"></head><body>\n%1\n</body></html>\n");
+
+ //
+ // No transactions, opening balances only
+ //
+
+ MyMoneyReport filter;
+ filter.setRowType( MyMoneyReport::eInstitution );
+ filter.setName("Accounts by Institution (No transactions)");
+ XMLandback(filter);
+ QueryTable qtbl_1(filter);
+
+ writeTabletoHTML(qtbl_1,"Accounts by Institution (No transactions).html");
+
+ QValueList<ListTable::TableRow> rows = qtbl_1.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 2);
+ CPPUNIT_ASSERT(rows[0]["account"]=="Checking Account");
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["value"])==moCheckingOpen);
+ CPPUNIT_ASSERT(rows[0]["equitytype"].isEmpty());
+ CPPUNIT_ASSERT(rows[1]["account"]=="Credit Card");
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["value"])==moCreditOpen);
+ CPPUNIT_ASSERT(rows[1]["equitytype"].isEmpty());
+
+ QString html = qtbl_1.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" None") == moCheckingOpen+moCreditOpen );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == moCheckingOpen+moCreditOpen );
+
+ //
+ // Adding in transactions
+ //
+
+ TransactionHelper t1q1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q1( QDate(2004,2,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q1( QDate(2004,3,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4y1( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ TransactionHelper t1q2( QDate(2004,4,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q2( QDate(2004,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q2( QDate(2004,6,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4q2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ TransactionHelper t1y2( QDate(2005,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y2( QDate(2005,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y2( QDate(2005,9,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4y2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ filter.setRowType( MyMoneyReport::eInstitution );
+ filter.setName("Accounts by Institution (With Transactions)");
+ XMLandback(filter);
+ QueryTable qtbl_2(filter);
+
+ rows = qtbl_2.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 2);
+ CPPUNIT_ASSERT(rows[0]["account"]=="Checking Account");
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["value"])==(moCheckingOpen-moSolo*3));
+ CPPUNIT_ASSERT(rows[1]["account"]=="Credit Card");
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["value"])==(moCreditOpen-(moParent1 + moParent2 + moChild) * 3));
+
+ html = qtbl_2.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == moCheckingOpen+moCreditOpen-(moParent1 + moParent2 + moSolo + moChild) * 3 );
+
+ //
+ // Account TYPES
+ //
+
+ filter.setRowType( MyMoneyReport::eAccountType );
+ filter.setName("Accounts by Type");
+ XMLandback(filter);
+ QueryTable qtbl_3(filter);
+
+ rows = qtbl_3.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 2);
+ CPPUNIT_ASSERT(rows[0]["account"]=="Checking Account");
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["value"])==(moCheckingOpen-moSolo*3));
+ CPPUNIT_ASSERT(rows[1]["account"]=="Credit Card");
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["value"])==(moCreditOpen-(moParent1 + moParent2 + moChild) * 3));
+
+ html = qtbl_3.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" "+i18n("Checking")) == moCheckingOpen-moSolo*3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total")+" "+i18n("Credit Card")) == moCreditOpen-(moParent1 + moParent2 + moChild) * 3 );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == moCheckingOpen+moCreditOpen-(moParent1 + moParent2 + moSolo + moChild) * 3 );
+ }
+ catch(MyMoneyException *e)
+ {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+}
+
+void QueryTableTest::testInvestment(void)
+{
+ try
+ {
+ // Equities
+ eqStock1 = makeEquity("Stock1","STK1");
+ eqStock2 = makeEquity("Stock2","STK2");
+
+ // Accounts
+ acInvestment = makeAccount("Investment",MyMoneyAccount::Investment,moZero,QDate(2004,1,1),acAsset);
+ acStock1 = makeAccount("Stock 1",MyMoneyAccount::Stock,moZero,QDate(2004,1,1),acInvestment,eqStock1);
+ acStock2 = makeAccount("Stock 2",MyMoneyAccount::Stock,moZero,QDate(2004,1,1),acInvestment,eqStock2);
+ acDividends = makeAccount("Dividends",MyMoneyAccount::Income,moZero,QDate(2004,1,1),acIncome);
+ acInterest = makeAccount("Interest",MyMoneyAccount::Income,moZero,QDate(2004,1,1),acIncome);
+
+ // Transactions
+ // Date Action Shares Price Stock Asset Income
+ InvTransactionHelper s1b1( QDate(2004,2,1), MyMoneySplit::ActionBuyShares, 1000.00, 100.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1b2( QDate(2004,3,1), MyMoneySplit::ActionBuyShares, 1000.00, 110.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1s1( QDate(2004,4,1), MyMoneySplit::ActionBuyShares, -200.00, 120.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1s2( QDate(2004,5,1), MyMoneySplit::ActionBuyShares, -200.00, 100.00, acStock1, acChecking, QString() );
+ InvTransactionHelper s1r1( QDate(2004,6,1), MyMoneySplit::ActionReinvestDividend, 50.00, 100.00, acStock1, QString(), acDividends );
+ InvTransactionHelper s1r2( QDate(2004,7,1), MyMoneySplit::ActionReinvestDividend, 50.00, 80.00, acStock1, QString(), acDividends );
+ InvTransactionHelper s1c1( QDate(2004,8,1), MyMoneySplit::ActionDividend, 10.00, 100.00, acStock1, acChecking, acDividends );
+ InvTransactionHelper s1c2( QDate(2004,9,1), MyMoneySplit::ActionDividend, 10.00, 120.00, acStock1, acChecking, acDividends );
+ InvTransactionHelper s1y1( QDate(2004,9,15), MyMoneySplit::ActionYield, 10.00, 110.00, acStock1, acChecking, acInterest );
+
+ makeEquityPrice( eqStock1, QDate(2004,10,1), 100.00 );
+
+ //
+ // Investment Transactions Report
+ //
+
+ MyMoneyReport invtran_r(
+ MyMoneyReport::eTopAccount,
+ MyMoneyReport::eQCaction|MyMoneyReport::eQCshares|MyMoneyReport::eQCprice,
+ MyMoneyTransactionFilter::userDefined,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Transactions"),
+ i18n("Test Report")
+ );
+ invtran_r.setDateFilter(QDate(2004,1,1),QDate(2004,12,31));
+ invtran_r.setInvestmentsOnly(true);
+ XMLandback(invtran_r);
+ QueryTable invtran(invtran_r);
+
+#if 1
+ writeTabletoHTML(invtran,"investment_transactions_test.html");
+
+ QValueList<ListTable::TableRow> rows = invtran.rows();
+
+ CPPUNIT_ASSERT(rows.count()==17);
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["value"])==MyMoneyMoney(100000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[2]["value"])==MyMoneyMoney(110000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[3]["value"])==MyMoneyMoney(-24000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[4]["value"])==MyMoneyMoney(-20000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[5]["value"])==MyMoneyMoney( 5000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[6]["value"])==MyMoneyMoney( 4000.00));
+ // need to fix these... fundamentally different from the original test
+ //CPPUNIT_ASSERT(MyMoneyMoney(invtran.m_rows[8]["value"])==MyMoneyMoney( -1000.00));
+ //CPPUNIT_ASSERT(MyMoneyMoney(invtran.m_rows[11]["value"])==MyMoneyMoney( -1200.00));
+ //CPPUNIT_ASSERT(MyMoneyMoney(invtran.m_rows[14]["value"])==MyMoneyMoney( -1100.00));
+
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["price"])==MyMoneyMoney(100.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[3]["price"])==MyMoneyMoney(120.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[5]["price"])==MyMoneyMoney(100.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[7]["price"])==MyMoneyMoney(100.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[10]["price"])==MyMoneyMoney(120.00));
+
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[2]["shares"])==MyMoneyMoney(1000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[4]["shares"])==MyMoneyMoney(-200.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[6]["shares"])==MyMoneyMoney( 50.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[8]["shares"])==MyMoneyMoney( 0.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[11]["shares"])==MyMoneyMoney( 0.00));
+
+ CPPUNIT_ASSERT(rows[1]["action"]=="Buy");
+ CPPUNIT_ASSERT(rows[3]["action"]=="Sell");
+ CPPUNIT_ASSERT(rows[5]["action"]=="Reinvest");
+ CPPUNIT_ASSERT(rows[7]["action"]=="Dividend");
+ CPPUNIT_ASSERT(rows[13]["action"]=="Yield");
+#else
+ CPPUNIT_ASSERT(rows.count()==9);
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["value"])==MyMoneyMoney(100000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["value"])==MyMoneyMoney(110000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[2]["value"])==MyMoneyMoney(-24000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[3]["value"])==MyMoneyMoney(-20000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[4]["value"])==MyMoneyMoney( 5000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[5]["value"])==MyMoneyMoney( 4000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[6]["value"])==MyMoneyMoney( -1000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[7]["value"])==MyMoneyMoney( -1200.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[8]["value"])==MyMoneyMoney( -1100.00));
+
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["price"])==MyMoneyMoney(100.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[2]["price"])==MyMoneyMoney(120.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[4]["price"])==MyMoneyMoney(100.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[6]["price"])==MyMoneyMoney( 0.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[8]["price"])==MyMoneyMoney( 0.00));
+
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["shares"])==MyMoneyMoney(1000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[3]["shares"])==MyMoneyMoney(-200.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[5]["shares"])==MyMoneyMoney( 50.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[7]["shares"])==MyMoneyMoney( 0.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[8]["shares"])==MyMoneyMoney( 0.00));
+
+ CPPUNIT_ASSERT(rows[0]["action"]=="Buy");
+ CPPUNIT_ASSERT(rows[2]["action"]=="Sell");
+ CPPUNIT_ASSERT(rows[4]["action"]=="Reinvest");
+ CPPUNIT_ASSERT(rows[6]["action"]=="Dividend");
+ CPPUNIT_ASSERT(rows[8]["action"]=="Yield");
+#endif
+
+ QString html = invtran.renderHTML();
+#if 1
+ // i think this is the correct amount. different treatment of dividend and yield
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total Stock 1")) == MyMoneyMoney(175000.00) );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == MyMoneyMoney(175000.00) );
+#else
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Total Stock 1")) == MyMoneyMoney(171700.00) );
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == MyMoneyMoney(171700.00) );
+#endif
+
+ //
+ // Investment Performance Report
+ //
+
+ MyMoneyReport invhold_r(
+ MyMoneyReport::eAccountByTopAccount,
+ MyMoneyReport::eQCperformance,
+ MyMoneyTransactionFilter::userDefined,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Performance by Account"),
+ i18n("Test Report")
+ );
+ invhold_r.setDateFilter(QDate(2004,1,1),QDate(2004,10,1));
+ invhold_r.setInvestmentsOnly(true);
+ XMLandback(invhold_r);
+ QueryTable invhold(invhold_r);
+
+ writeTabletoHTML(invhold,"Investment Performance by Account.html");
+
+ rows = invhold.rows();
+
+ CPPUNIT_ASSERT(rows.count()==2);
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["return"])==MyMoneyMoney("669/10000"));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["buys"])==MyMoneyMoney(210000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["sells"])==MyMoneyMoney(-44000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["reinvestincome"])==MyMoneyMoney(9000.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["cashincome"])==MyMoneyMoney(3300.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["shares"])==MyMoneyMoney(1700.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[0]["price"])==MyMoneyMoney(100.00));
+ CPPUNIT_ASSERT(MyMoneyMoney(rows[1]["return"]).isZero());
+
+ html = invhold.renderHTML();
+ CPPUNIT_ASSERT( searchHTML(html,i18n("Grand Total")) == MyMoneyMoney(170000.00) );
+
+#if 0
+ // Dump file & reports
+ QFile g( "investmentkmy.xml" );
+ g.open( IO_WriteOnly );
+ MyMoneyStorageXML xml;
+ IMyMoneyStorageFormat& interface = xml;
+ interface.writeFile(&g, dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()));
+ g.close();
+
+ invtran.dump("invtran.html","<html><head></head><body>%1</body></html>");
+ invhold.dump("invhold.html","<html><head></head><body>%1</body></html>");
+#endif
+
+ }
+ catch(MyMoneyException *e)
+ {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+}
+ //this is to prevent me from making mistakes again when modifying balances - asoliverez
+ //this case tests only the opening and ending balance of the accounts
+ void QueryTableTest::testBalanceColumn()
+ {
+ try
+ {
+ TransactionHelper t1q1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q1( QDate(2004,2,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q1( QDate(2004,3,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4y1( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ TransactionHelper t1q2( QDate(2004,4,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q2( QDate(2004,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3q2( QDate(2004,6,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4q2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ TransactionHelper t1y2( QDate(2005,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2y2( QDate(2005,5,1), MyMoneySplit::ActionWithdrawal, moParent1, acCredit, acParent );
+ TransactionHelper t3y2( QDate(2005,9,1), MyMoneySplit::ActionWithdrawal, moParent2, acCredit, acParent );
+ TransactionHelper t4y2( QDate(2004,11,7), MyMoneySplit::ActionWithdrawal, moChild, acCredit, acChild );
+
+ unsigned cols;
+
+ MyMoneyReport filter;
+
+ filter.setRowType( MyMoneyReport::eAccount );
+ filter.setName("Transactions by Account");
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory | MyMoneyReport::eQCbalance;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) ); //
+ XMLandback(filter);
+ QueryTable qtbl_3(filter);
+
+ writeTabletoHTML(qtbl_3,"Transactions by Account.html");
+
+ QString html = qtbl_3.renderHTML();
+
+ QValueList<ListTable::TableRow> rows = qtbl_3.rows();
+
+ CPPUNIT_ASSERT(rows.count() == 16);
+
+ //this is to make sure that the dates of closing and opening balances and the balance numbers are ok
+ QString openingDate = KGlobal::locale()->formatDate(QDate(2004,1,1), true);
+ QString closingDate = KGlobal::locale()->formatDate(QDate(2005,9,1), true);
+ CPPUNIT_ASSERT( html.find(openingDate + "</td><td class=\"left\"></td><td class=\"left\">"+i18n("Opening Balance")) > 0);
+ CPPUNIT_ASSERT( html.find(closingDate + "</td><td class=\"left\"></td><td class=\"left\">"+i18n("Closing Balance")+"</td><td class=\"left\"></td><td class=\"value\"></td><td>&nbsp;-702.36</td></tr>") > 0);
+ CPPUNIT_ASSERT( html.find(closingDate + "</td><td class=\"left\"></td><td class=\"left\">"+i18n("Closing Balance")+"</td><td class=\"left\"></td><td class=\"value\"></td><td>&nbsp;-705.69</td></tr>") > 0);
+
+ }
+ catch(MyMoneyException *e)
+ {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+
+ }
+
+void QueryTableTest::testTaxReport()
+{
+ try {
+ TransactionHelper t1q1( QDate(2004,1,1), MyMoneySplit::ActionWithdrawal, moSolo, acChecking, acSolo );
+ TransactionHelper t2q1( QDate(2004,2,1), MyMoneySplit::ActionWithdrawal, moParent1, acChecking, acTax );
+
+ unsigned cols;
+ MyMoneyReport filter;
+
+ filter.setRowType( MyMoneyReport::eCategory );
+ filter.setName("Tax Transactions");
+ cols = MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount;
+ filter.setQueryColumns( static_cast<MyMoneyReport::EQueryColumns>(cols) );
+ filter.setTax(true);
+
+ XMLandback(filter);
+ QueryTable qtbl_3(filter);
+
+ writeTabletoHTML(qtbl_3,"Tax Transactions.html");
+
+ QValueList<ListTable::TableRow> rows = qtbl_3.rows();
+
+ QString html = qtbl_3.renderHTML();
+ CPPUNIT_ASSERT(rows.count() == 1);
+ } catch(MyMoneyException *e) {
+ CPPUNIT_FAIL(e->what());
+ delete e;
+ }
+}
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/querytabletest.h b/kmymoney2/reports/querytabletest.h
new file mode 100644
index 0000000..36f3075
--- /dev/null
+++ b/kmymoney2/reports/querytabletest.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ querytabletest.h
+ -------------------
+ copyright : (C) 2002 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.jones@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QUERYTABLETEST_H
+#define QUERYTABLETEST_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+class QueryTableTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(QueryTableTest);
+ CPPUNIT_TEST(testQueryBasics);
+ CPPUNIT_TEST(testCashFlowAnalysis);
+ CPPUNIT_TEST(testAccountQuery);
+ CPPUNIT_TEST(testInvestment);
+ CPPUNIT_TEST(testBalanceColumn);
+ CPPUNIT_TEST(testTaxReport);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ MyMoneyAccount *m;
+
+ MyMoneySeqAccessMgr* storage;
+ MyMoneyFile* file;
+
+public:
+ QueryTableTest();
+ void setUp ();
+ void tearDown ();
+ void testQueryBasics();
+ void testCashFlowAnalysis();
+ void testAccountQuery();
+ void testInvestment();
+ void testBalanceColumn();
+ void testTaxReport();
+};
+
+#endif
diff --git a/kmymoney2/reports/reportaccount.cpp b/kmymoney2/reports/reportaccount.cpp
new file mode 100644
index 0000000..5f7e7f8
--- /dev/null
+++ b/kmymoney2/reports/reportaccount.cpp
@@ -0,0 +1,355 @@
+/***************************************************************************
+ reportaccount.cpp
+ -------------------
+ begin : Mon May 17 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+// This is just needed for i18n(). Once I figure out how to handle i18n
+// without using this macro directly, I'll be freed of KDE dependency. This
+// is a minor problem because we use these terms when rendering to HTML,
+// and a more major problem because we need it to translate account types
+// (e.g. MyMoneyAccount::Checkings) into their text representation. We also
+// use that text representation in the core data structure of the report. (Ace)
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneysecurity.h"
+#include "reportdebug.h"
+#include "reportaccount.h"
+
+namespace reports {
+
+ReportAccount::ReportAccount( void )
+{
+}
+
+ReportAccount::ReportAccount( const ReportAccount& copy ):
+ MyMoneyAccount( copy ), m_nameHierarchy( copy.m_nameHierarchy )
+{
+ // NOTE: I implemented the copy constructor solely for debugging reasons
+
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+}
+
+ReportAccount::ReportAccount( const QString& accountid ):
+ MyMoneyAccount( MyMoneyFile::instance()->account(accountid) )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ DEBUG_OUTPUT(QString("Account %1").arg(accountid));
+ calculateAccountHierarchy();
+}
+
+ReportAccount::ReportAccount( const MyMoneyAccount& account ):
+ MyMoneyAccount( account )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+ DEBUG_OUTPUT(QString("Account %1").arg(account.id()));
+ calculateAccountHierarchy();
+}
+
+void ReportAccount::calculateAccountHierarchy( void )
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString resultid = id();
+ QString parentid = parentAccountId();
+
+#ifdef DEBUG_HIDE_SENSITIVE
+ m_nameHierarchy.prepend(file->account(resultid).id());
+#else
+ m_nameHierarchy.prepend(file->account(resultid).name());
+#endif
+ while (!file->isStandardAccount(parentid))
+ {
+ // take on the identity of our parent
+ resultid = parentid;
+
+ // and try again
+ parentid = file->account(resultid).parentAccountId();
+#ifdef DEBUG_HIDE_SENSITIVE
+ m_nameHierarchy.prepend(file->account(resultid).id());
+#else
+ m_nameHierarchy.prepend(file->account(resultid).name());
+#endif
+ }
+}
+
+MyMoneyMoney ReportAccount::deepCurrencyPrice( const QDate& date ) const
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ MyMoneyMoney result(1, 1);
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MyMoneySecurity undersecurity = file->security( currencyId() );
+ if ( ! undersecurity.isCurrency() )
+ {
+ MyMoneyPrice price = file->price(undersecurity.id(),undersecurity.tradingCurrency(),date);
+ if ( price.isValid() )
+ {
+ result = price.rate(undersecurity.tradingCurrency());
+
+ DEBUG_OUTPUT(QString("Converting under %1 to deep %2, price on %3 is %4")
+ .arg(undersecurity.name())
+ .arg(file->security(undersecurity.tradingCurrency()).name())
+ .arg(date.toString())
+ .arg(result.toDouble()));
+ }
+ else
+ {
+ DEBUG_OUTPUT(QString("No price to convert under %1 to deep %2 on %3")
+ .arg(undersecurity.name())
+ .arg(file->security(undersecurity.tradingCurrency()).name())
+ .arg(date.toString()));
+ }
+ }
+
+ return result;
+}
+
+MyMoneyMoney ReportAccount::baseCurrencyPrice( const QDate& date ) const
+{
+ // Note that whether or not the user chooses to convert to base currency, all the values
+ // for a given account/category are converted to the currency for THAT account/category
+ // The "Convert to base currency" tells the report to convert from the account/category
+ // currency to the file's base currency.
+ //
+ // An example where this matters is if Category 'C' and account 'U' are in USD, but
+ // Account 'J' is in JPY. Say there are two transactions, one is US$100 from U to C,
+ // the other is JPY10,000 from J to C. Given a JPY price of USD$0.01, this means
+ // C will show a balance of $200 NO MATTER WHAT the user chooses for 'convert to base
+ // currency. This confused me for a while, which is why I wrote this comment.
+ // --acejones
+
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ MyMoneyMoney result(1, 1);
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if(isForeignCurrency())
+ {
+ result = foreignCurrencyPrice(file->baseCurrency().id(), date);
+ }
+
+ return result;
+}
+
+MyMoneyMoney ReportAccount::foreignCurrencyPrice( const QString foreignCurrency, const QDate& date ) const
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ MyMoneyPrice price;
+ MyMoneyMoney result(1, 1);
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneySecurity security = file->security(foreignCurrency);
+
+ //check whether it is a currency or a commodity. In the latter case case, get the trading currency
+ QString tradingCurrency;
+ if(security.isCurrency()) {
+ tradingCurrency = foreignCurrency;
+ } else {
+ tradingCurrency = security.tradingCurrency();
+ }
+
+ //It makes no sense to get the price if both currencies are the same
+ if(currency().id() != tradingCurrency) {
+ price = file->price(currency().id(), tradingCurrency, date);
+
+ if(price.isValid())
+ {
+ result = price.rate(tradingCurrency);
+ DEBUG_OUTPUT(QString("Converting deep %1 to currency %2, price on %3 is %4")
+ .arg(file->currency(currency().id()).name())
+ .arg(file->currency(foreignCurrency).name())
+ .arg(date.toString())
+ .arg(result.toDouble()));
+ }
+ else
+ {
+ DEBUG_OUTPUT(QString("No price to convert deep %1 to currency %2 on %3")
+ .arg(file->currency(currency().id()).name())
+ .arg(file->currency(foreignCurrency).name())
+ .arg(date.toString()));
+ }
+ }
+ return result;
+}
+
+/**
+ * Fetch the trading currency of this account's currency
+ *
+ * @return The account's currency trading currency
+ */
+MyMoneySecurity ReportAccount::currency( void ) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // First, get the deep currency
+ MyMoneySecurity deepcurrency = file->security( currencyId() );
+ if ( ! deepcurrency.isCurrency() )
+ deepcurrency = file->security( deepcurrency.tradingCurrency() );
+
+ // Return the deep currency's ID
+ return deepcurrency;
+}
+
+/**
+ * Determine if this account's deep currency is different from the file's
+ * base currency
+ *
+ * @return bool True if this account is in a foreign currency
+ */
+bool ReportAccount::isForeignCurrency( void ) const
+{
+ return ( currency().id() != MyMoneyFile::instance()->baseCurrency().id() );
+}
+
+bool ReportAccount::operator<(const ReportAccount& second) const
+{
+// DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ bool result = false;
+ bool haveresult = false;
+ QStringList::const_iterator it_first = m_nameHierarchy.begin();
+ QStringList::const_iterator it_second = second.m_nameHierarchy.begin();
+ while ( it_first != m_nameHierarchy.end() )
+ {
+ // The first string is longer than the second, but otherwise identical
+ if ( it_second == second.m_nameHierarchy.end() )
+ {
+ result = false;
+ haveresult = true;
+ break;
+ }
+
+ if ( (*it_first) < (*it_second) )
+ {
+ result = true;
+ haveresult = true;
+ break;
+ }
+ else if ( (*it_first) > (*it_second) )
+ {
+ result = false;
+ haveresult = true;
+ break;
+ }
+
+ ++it_first;
+ ++it_second;
+ }
+
+ // The second string is longer than the first, but otherwise identical
+ if ( !haveresult && ( it_second != second.m_nameHierarchy.end() ) )
+ result = true;
+
+// DEBUG_OUTPUT(QString("%1 < %2 is %3").arg(debugName(),second.debugName()).arg(result));
+ return result;
+}
+
+/**
+ * The name of only this account. No matter how deep the hierarchy, this
+ * method only returns the last name in the list, which is the engine name]
+ * of this account.
+ *
+ * @return QString The account's name
+ */
+QString ReportAccount::name( void ) const
+{
+ return m_nameHierarchy.back();
+}
+
+// MyMoneyAccount:fullHierarchyDebug()
+QString ReportAccount::debugName( void ) const
+{
+ return m_nameHierarchy.join("|");
+}
+
+// MyMoneyAccount:fullHierarchy()
+QString ReportAccount::fullName( void ) const
+{
+ return m_nameHierarchy.join(": ");
+}
+
+// MyMoneyAccount:isTopCategory()
+bool ReportAccount::isTopLevel( void ) const
+{
+ return ( m_nameHierarchy.size() == 1 );
+}
+
+// MyMoneyAccount:hierarchyDepth()
+unsigned ReportAccount::hierarchyDepth( void ) const
+{
+ return ( m_nameHierarchy.size() );
+}
+
+ReportAccount ReportAccount::parent( void ) const
+{
+ return ReportAccount( parentAccountId() );
+}
+
+ReportAccount ReportAccount::topParent( void ) const
+{
+ DEBUG_ENTER(__PRETTY_FUNCTION__);
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString resultid = id();
+ QString parentid = parentAccountId();
+
+ while (!file->isStandardAccount(parentid))
+ {
+ // take on the identity of our parent
+ resultid = parentid;
+
+ // and try again
+ parentid = file->account(resultid).parentAccountId();
+ }
+
+ return ReportAccount( resultid );
+}
+
+QString ReportAccount::topParentName( void ) const
+{
+ return m_nameHierarchy.first();
+}
+
+bool ReportAccount::isLiquidAsset( void ) const
+{
+ return accountType() == MyMoneyAccount::Cash ||
+ accountType() == MyMoneyAccount::Checkings ||
+ accountType() == MyMoneyAccount::Savings;
+}
+
+
+bool ReportAccount::isLiquidLiability( void ) const
+{
+ return accountType() == MyMoneyAccount::CreditCard;
+
+}
+
+
+
+
+} // end namespace reports
diff --git a/kmymoney2/reports/reportaccount.h b/kmymoney2/reports/reportaccount.h
new file mode 100644
index 0000000..e07f9b1
--- /dev/null
+++ b/kmymoney2/reports/reportaccount.h
@@ -0,0 +1,238 @@
+/***************************************************************************
+ reportaccount.h
+ -------------------
+ begin : Sat May 22 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REPORTACCOUNT_H
+#define REPORTACCOUNT_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../mymoney/mymoneyaccount.h"
+
+namespace reports {
+
+/**
+ * This is a MyMoneyAccount as viewed from the reporting engine.
+ *
+ * All reporting methods should use ReportAccount INSTEAD OF
+ * MyMoneyAccount at all times.
+ *
+ * The primary functionality this provides is a full chain of account
+ * hierarchy that is easy to traverse. It's needed because the PivotTable
+ * grid needs to store and sort by the full account hierarchy, while still
+ * having access to the account itself for currency conversion.
+ *
+ * In addition, several other convenience functions are provided that may
+ * be worth moving into MyMoneyAccount at some point.
+ *
+ * @author Ace Jones
+ *
+ * @short
+**/
+class ReportAccount: public MyMoneyAccount
+{
+private:
+ QStringList m_nameHierarchy;
+
+public:
+ /**
+ * Default constructor
+ *
+ * Needed to allow this object to be stored in a QMap.
+ */
+ ReportAccount( void );
+
+ /**
+ * Copy constructor
+ *
+ * Needed to allow this object to be stored in a QMap.
+ */
+ ReportAccount( const ReportAccount& );
+
+ /**
+ * Regular constructor
+ *
+ * @param accountid Account which this account descriptor should be based off of
+ */
+ ReportAccount( const QString& accountid );
+
+ /**
+ * Regular constructor
+ *
+ * @param accountid Account which this account descriptor should be based off of
+ */
+ ReportAccount( const MyMoneyAccount& accountid );
+
+ /**
+ * @param right The object to compare against
+ * @return bool True if this account's fully-qualified hierarchy name
+ * is less than that of the given qccount
+ */
+ bool operator<( const ReportAccount& right ) const;
+
+ /**
+ * Returns the price of this account's underlying currency on the indicated date,
+ * translated into the account's deep currency
+ *
+ * There are three different currencies in play with a single Account:
+ * - The underlying currency: What currency the account itself is denominated in
+ * - The deep currency: The underlying currency's own underlying currency. This
+ * is only a factor if the underlying currency of this account IS NOT a
+ * currency itself, but is some other kind of security. In that case, the
+ * underlying security has its own currency. The deep currency is the
+ * currency of the underlying security. On the other hand, if the account
+ * has a currency itself, then the deep currency == the underlying currency,
+ * and this function will return 1.0.
+ * - The base currency: The base currency of the user's overall file
+ *
+ * @param date The date in question
+ * @return MyMoneyMoney The value of the account's currency on that date
+ */
+ MyMoneyMoney deepCurrencyPrice( const QDate& date ) const;
+
+ /**
+ * Returns the price of this account's deep currency on the indicated date,
+ * translated into the base currency
+ *
+ * @param date The date in question
+ * @return MyMoneyMoney The value of the account's currency on that date
+ */
+ MyMoneyMoney baseCurrencyPrice( const QDate& date ) const;
+
+ /**
+ * Returns the price of this account's deep currency on the indicated date,
+ * translated into the base currency
+ *
+ * @param foreignCurrency The currency on which the price will be returned
+ * @param date The date in question
+ * @return MyMoneyMoney The value of the account's currency on that date
+ */
+ MyMoneyMoney foreignCurrencyPrice( const QString foreignCurrency, const QDate& date ) const;
+
+ /**
+ * Fetch the trading symbol of this account's deep currency
+ *
+ * @return The account's currency trading currency object
+ */
+ MyMoneySecurity currency( void ) const;
+
+ /**
+ * Determine if this account's deep currency is different from the file's
+ * base currency
+ *
+ * @return bool True if this account is in a foreign currency
+ */
+ bool isForeignCurrency( void ) const;
+
+ /**
+ * The name of only this account. No matter how deep the hierarchy, this
+ * method only returns the last name in the list, which is the engine name]
+ * of this account.
+ *
+ * @return QString The account's name
+ */
+ QString name( void ) const;
+
+ /**
+ * The entire hierarchy of this account descriptor
+ * This is similiar to debugName(), however debugName() is not guaranteed
+ * to always look pretty, while fullName() is. So if the user is ever
+ * going to see the results, use fullName().
+ *
+ * @return QString The account's full hierarchy
+ */
+ QString fullName( void ) const;
+
+ /**
+ * The entire hierarchy of this account descriptor, suitable for displaying
+ * in debugging output
+ *
+ * @return QString The account's full hierarchy (suitable for debugging)
+ */
+ QString debugName( void ) const;
+
+ /**
+ * Whether this account is a 'top level' parent account. This means that
+ * it's parent is an account class, like asset, liability, expense or income
+ *
+ * @return bool True if this account is a top level parent account
+ */
+ /*inline*/ bool isTopLevel( void ) const;
+
+ /**
+ * Returns the name of the top level parent account
+ *
+ * (See isTopLevel for a definition of 'top level parent')
+ *
+ * @return QString The name of the top level parent account
+ */
+ /*inline*/ QString topParentName( void ) const;
+
+ /**
+ * Returns a report account containing the top parent account
+ *
+ * @return ReportAccount The account of the top parent
+ */
+ ReportAccount topParent( void ) const;
+
+ /**
+ * Returns a report account containing the immediate parent account
+ *
+ * @return ReportAccount The account of the immediate parent
+ */
+ ReportAccount parent( void ) const;
+
+ /**
+ * Returns the number of accounts in this account's hierarchy. If this is a
+ * Top Category, it returns 1. If it's parent is a Top Category, returns 2,
+ * etc.
+ *
+ * @return unsigned Hierarchy depth
+ */
+ unsigned hierarchyDepth( void ) const;
+
+ /**
+ * Returns whether this account is a liquid asset
+ *
+ */
+ bool isLiquidAsset( void ) const;
+
+ /**
+ * Returns whether this account is a liquid liability
+ *
+ */
+ bool isLiquidLiability( void ) const;
+
+protected:
+ /**
+ * Calculates the full account hierarchy of this account
+ */
+ void calculateAccountHierarchy( void );
+
+};
+
+} // end namespace reports
+
+#endif // REPORTACCOUNT_H
diff --git a/kmymoney2/reports/reportdebug.h b/kmymoney2/reports/reportdebug.h
new file mode 100644
index 0000000..3a95465
--- /dev/null
+++ b/kmymoney2/reports/reportdebug.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ reportdebug.h
+ -------------------
+ begin : Sat May 22 2004
+ copyright : (C) 2004-2005 by Ace Jones
+ email : <ace.j@hotpop.com>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REPORTDEBUG_H
+#define REPORTDEBUG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+namespace reports {
+
+// define to enable massive debug logging to stderr
+#undef DEBUG_REPORTS
+// #define DEBUG_REPORTS
+
+#define DEBUG_ENABLED_BY_DEFAULT false
+
+#ifdef DEBUG_REPORTS
+
+// define to filter out account names & transaction amounts
+// DO NOT check into CVS with this defined!! It breaks all
+// unit tests.
+#undef DEBUG_HIDE_SENSITIVE
+
+#define DEBUG_ENTER(x) Debug ___DEBUG(x)
+#define DEBUG_OUTPUT(x) ___DEBUG.output(x)
+#define DEBUG_OUTPUT_IF(x,y) { if (x) ___DEBUG.output(y); }
+#define DEBUG_ENABLE(x) Debug::enable(x)
+#define DEBUG_ENABLE_KEY(x) Debug::setEnableKey(x)
+#ifdef DEBUG_HIDE_SENSITIVE
+#define DEBUG_SENSITIVE(x) QString("hidden")
+#else
+#define DEBUG_SENSITIVE(x) (x)
+#endif
+
+#else
+
+#define DEBUG_ENTER(x)
+#define DEBUG_OUTPUT(x)
+#define DEBUG_OUTPUT_IF(x,y)
+#define DEBUG_ENABLE(x)
+#define DEBUG_SENSITIVE(x)
+#endif
+
+class Debug
+{
+ QString m_methodName;
+ static QString m_sTabs;
+ static bool m_sEnabled;
+ bool m_enabled;
+ static QString m_sEnableKey;
+public:
+ Debug( const QString& _name );
+ ~Debug();
+ void output( const QString& _text );
+ static void enable( bool _e ) { m_sEnabled = _e; }
+ static void setEnableKey( const QString& _s ) { m_sEnableKey = _s; }
+};
+
+} // end namespace reports
+
+#endif // REPORTDEBUG_H
diff --git a/kmymoney2/reports/reportstestcommon.cpp b/kmymoney2/reports/reportstestcommon.cpp
new file mode 100644
index 0000000..31e6c1d
--- /dev/null
+++ b/kmymoney2/reports/reportstestcommon.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+ reportstestcommon.cpp
+ -------------------
+ copyright : (C) 2002-2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qdom.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "kreportsviewtest.h"
+
+#define private public
+#include "pivottable.h"
+#include "querytable.h"
+#undef private
+using namespace reports;
+
+#include "../mymoney/mymoneysecurity.h"
+#include "../mymoney/mymoneyprice.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+#include "../mymoney/mymoneyreport.h"
+#include "../mymoney/mymoneystatement.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+#include "reportstestcommon.h"
+
+namespace test {
+
+const MyMoneyMoney moCheckingOpen(0.0);
+const MyMoneyMoney moCreditOpen(-0.0);
+const MyMoneyMoney moConverterCheckingOpen(1418.0);
+const MyMoneyMoney moConverterCreditOpen(-418.0);
+const MyMoneyMoney moZero(0.0);
+const MyMoneyMoney moSolo(234.12);
+const MyMoneyMoney moParent1(88.01);
+const MyMoneyMoney moParent2(133.22);
+const MyMoneyMoney moParent(moParent1+moParent2);
+const MyMoneyMoney moChild(14.00);
+const MyMoneyMoney moThomas(5.11);
+const MyMoneyMoney moNoPayee(8944.70);
+
+QString acAsset;
+QString acLiability;
+QString acExpense;
+QString acIncome;
+QString acChecking;
+QString acCredit;
+QString acSolo;
+QString acParent;
+QString acChild;
+QString acSecondChild;
+QString acGrandChild1;
+QString acGrandChild2;
+QString acForeign;
+QString acCanChecking;
+QString acJpyChecking;
+QString acCanCash;
+QString acJpyCash;
+QString inBank;
+QString eqStock1;
+QString eqStock2;
+QString acInvestment;
+QString acStock1;
+QString acStock2;
+QString acDividends;
+QString acInterest;
+QString acTax;
+QString acCash;
+
+TransactionHelper::TransactionHelper( const QDate& _date, const QString& _action, MyMoneyMoney _value, const QString& _accountid, const QString& _categoryid, const QString& _currencyid, const QString& _payee )
+{
+ // _currencyid is the currency of the transaction, and of the _value
+ // both the account and category can have their own currency (athough the category having
+ // a foreign currency is not yet supported by the program, the reports will still allow it,
+ // so it must be tested.)
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ bool haspayee = ! _payee.isEmpty();
+ MyMoneyPayee payeeTest = file->payeeByName(_payee);
+
+ MyMoneyFileTransaction ft;
+ setPostDate(_date);
+
+ QString currencyid = _currencyid;
+ if ( currencyid.isEmpty() )
+ currencyid=MyMoneyFile::instance()->baseCurrency().id();
+ setCommodity(currencyid);
+
+ MyMoneyMoney price;
+ MyMoneySplit splitLeft;
+ if ( haspayee )
+ splitLeft.setPayeeId(payeeTest.id());
+ splitLeft.setAction(_action);
+ splitLeft.setValue(-_value);
+ price = MyMoneyFile::instance()->price(currencyid, file->account(_accountid).currencyId(),_date).rate(file->account(_accountid).currencyId());
+ splitLeft.setShares(-_value * price);
+ splitLeft.setAccountId(_accountid);
+ addSplit(splitLeft);
+
+ MyMoneySplit splitRight;
+ if ( haspayee )
+ splitRight.setPayeeId(payeeTest.id());
+ splitRight.setAction(_action);
+ splitRight.setValue(_value);
+ price = MyMoneyFile::instance()->price(currencyid, file->account(_categoryid).currencyId(),_date).rate(file->account(_categoryid).currencyId());
+ splitRight.setShares(_value * price );
+ splitRight.setAccountId(_categoryid);
+ addSplit(splitRight);
+
+ MyMoneyFile::instance()->addTransaction(*this);
+ ft.commit();
+}
+
+TransactionHelper::~TransactionHelper()
+{
+ MyMoneyFileTransaction ft;
+ MyMoneyFile::instance()->removeTransaction(*this);
+ ft.commit();
+}
+
+void TransactionHelper::update(void)
+{
+ MyMoneyFileTransaction ft;
+ MyMoneyFile::instance()->modifyTransaction(*this);
+ ft.commit();
+}
+
+InvTransactionHelper::InvTransactionHelper( const QDate& _date, const QString& _action, MyMoneyMoney _shares, MyMoneyMoney _price, const QString& _stockaccountid, const QString& _transferid, const QString& _categoryid )
+{
+ init(_date, _action, _shares, _price, _stockaccountid, _transferid, _categoryid);
+}
+
+void InvTransactionHelper::init( const QDate& _date, const QString& _action, MyMoneyMoney _shares, MyMoneyMoney _price, const QString& _stockaccountid, const QString& _transferid, const QString& _categoryid )
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount stockaccount = file->account(_stockaccountid);
+ MyMoneyMoney value = _shares * _price;
+
+ setPostDate(_date);
+
+ setCommodity("USD");
+ MyMoneySplit s1;
+ s1.setValue(value);
+ s1.setAccountId(_stockaccountid);
+
+ if ( _action == MyMoneySplit::ActionReinvestDividend )
+ {
+ s1.setShares(_shares);
+ s1.setAction(MyMoneySplit::ActionReinvestDividend);
+
+ MyMoneySplit s2;
+ s2.setAccountId(_categoryid);
+ s2.setShares(-value);
+ s2.setValue(-value);
+ addSplit(s2);
+ }
+ else if ( _action == MyMoneySplit::ActionDividend || _action == MyMoneySplit::ActionYield )
+ {
+ s1.setAccountId(_categoryid);
+ s1.setShares(-value);
+ s1.setValue(-value);
+
+ // Split 2 will be the zero-amount investment split that serves to
+ // mark this transaction as a cash dividend and note which stock account
+ // it belongs to.
+ MyMoneySplit s2;
+ s2.setValue(0);
+ s2.setShares(0);
+ s2.setAction(_action);
+ s2.setAccountId(_stockaccountid);
+ addSplit(s2);
+
+ MyMoneySplit s3;
+ s3.setAccountId(_transferid);
+ s3.setShares(value);
+ s3.setValue(value);
+ addSplit(s3);
+ }
+ else if ( _action == MyMoneySplit::ActionBuyShares )
+ {
+ s1.setShares(_shares);
+ s1.setAction(MyMoneySplit::ActionBuyShares);
+
+ MyMoneySplit s3;
+ s3.setAccountId(_transferid);
+ s3.setShares(-value);
+ s3.setValue(-value);
+ addSplit(s3);
+ }
+ addSplit(s1);
+
+ //kdDebug(2) << "created transaction, now adding..." << endl;
+
+ MyMoneyFileTransaction ft;
+ file->addTransaction(*this);
+
+ //kdDebug(2) << "updating price..." << endl;
+
+ // update the price, while we're here
+ QString stockid = stockaccount.currencyId();
+ QString basecurrencyid = file->baseCurrency().id();
+ MyMoneyPrice price = file->price( stockid, basecurrencyid, _date, true );
+ if ( !price.isValid() )
+ {
+ MyMoneyPrice newprice( stockid, basecurrencyid, _date, _price, "test" );
+ file->addPrice(newprice);
+ }
+ ft.commit();
+ //kdDebug(2) << "successfully added " << id() << endl;
+}
+
+QString makeAccount( const QString& _name, MyMoneyAccount::accountTypeE _type, MyMoneyMoney _balance, const QDate& _open, const QString& _parent, QString _currency, bool _taxReport )
+{
+ MyMoneyAccount info;
+ MyMoneyFileTransaction ft;
+
+ info.setName(_name);
+ info.setAccountType(_type);
+ info.setOpeningDate(_open);
+ if ( _currency != "" )
+ info.setCurrencyId(_currency);
+ else
+ info.setCurrencyId(MyMoneyFile::instance()->baseCurrency().id());
+
+ if(_taxReport)
+ info.setValue("Tax", "Yes");
+
+ MyMoneyAccount parent = MyMoneyFile::instance()->account(_parent);
+ MyMoneyFile::instance()->addAccount( info, parent );
+ // create the opening balance transaction if any
+ if(!_balance.isZero()) {
+ MyMoneySecurity sec = MyMoneyFile::instance()->currency(info.currencyId());
+ MyMoneyFile::instance()->openingBalanceAccount(sec);
+ MyMoneyFile::instance()->createOpeningBalanceTransaction(info, _balance);
+ }
+ ft.commit();
+
+ return info.id();
+}
+
+void makePrice(const QString& _currencyid, const QDate& _date, const MyMoneyMoney& _price )
+{
+ MyMoneyFileTransaction ft;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneySecurity curr = file->currency(_currencyid);
+ MyMoneyPrice price(_currencyid, file->baseCurrency().id(), _date, _price, "test");
+ file->addPrice(price);
+ ft.commit();
+}
+
+QString makeEquity(const QString& _name, const QString& _symbol )
+{
+ MyMoneySecurity equity;
+ MyMoneyFileTransaction ft;
+
+ equity.setName( _name );
+ equity.setTradingSymbol( _symbol );
+ equity.setSmallestAccountFraction( 1000 );
+ equity.setSecurityType( MyMoneySecurity::SECURITY_NONE /*MyMoneyEquity::ETYPE_STOCK*/ );
+ MyMoneyFile::instance()->addSecurity( equity );
+ ft.commit();
+
+ return equity.id();
+}
+
+void makeEquityPrice(const QString& _id, const QDate& _date, const MyMoneyMoney& _price )
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyFileTransaction ft;
+ QString basecurrencyid = file->baseCurrency().id();
+ MyMoneyPrice price = file->price( _id, basecurrencyid, _date, true );
+ if ( !price.isValid() )
+ {
+ MyMoneyPrice newprice( _id, basecurrencyid, _date, _price, "test" );
+ file->addPrice(newprice);
+ }
+ ft.commit();
+}
+
+void writeRCFtoXMLDoc( const MyMoneyReport& filter, QDomDocument* doc )
+{
+ QDomProcessingInstruction instruct = doc->createProcessingInstruction(QString("xml"), QString("version=\"1.0\" encoding=\"utf-8\""));
+ doc->appendChild(instruct);
+
+ QDomElement root = doc->createElement("KMYMONEY-FILE");
+ doc->appendChild(root);
+
+ QDomElement reports = doc->createElement("REPORTS");
+ root.appendChild(reports);
+
+ QDomElement report = doc->createElement("REPORT");
+ filter.write(report,doc);
+ reports.appendChild(report);
+
+}
+
+void writeTabletoHTML( const PivotTable& table, const QString& _filename )
+{
+ static unsigned filenumber = 1;
+ QString filename = _filename;
+ if ( filename.isEmpty() )
+ {
+ filename = QString("report-%1%2.html").arg((filenumber<10)?"0":"").arg(filenumber);
+ ++filenumber;
+ }
+
+ QFile g( filename );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << table.renderHTML();
+ g.close();
+
+}
+
+void writeTabletoHTML( const QueryTable& table, const QString& _filename )
+{
+ static unsigned filenumber = 1;
+ QString filename = _filename;
+ if ( filename.isEmpty() )
+ {
+ filename = QString("report-%1%2.html").arg((filenumber<10)?"0":"").arg(filenumber);
+ ++filenumber;
+ }
+
+ QFile g( filename );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << table.renderHTML();
+ g.close();
+}
+
+void writeTabletoCSV( const PivotTable& table, const QString& _filename )
+{
+ static unsigned filenumber = 1;
+ QString filename = _filename;
+ if ( filename.isEmpty() )
+ {
+ filename = QString("report-%1%2.csv").arg((filenumber<10)?"0":"").arg(filenumber);
+ ++filenumber;
+ }
+
+ QFile g( filename );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << table.renderCSV();
+ g.close();
+
+}
+
+void writeTabletoCSV( const QueryTable& table, const QString& _filename )
+{
+ static unsigned filenumber = 1;
+ QString filename = _filename;
+ if ( filename.isEmpty() )
+ {
+ filename = QString("qreport-%1%2.csv").arg((filenumber<10)?"0":"").arg(filenumber);
+ ++filenumber;
+ }
+
+ QFile g( filename );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << table.renderCSV();
+ g.close();
+
+}
+
+void writeRCFtoXML( const MyMoneyReport& filter, const QString& _filename )
+{
+ static unsigned filenum = 1;
+ QString filename = _filename;
+ if ( filename.isEmpty() ) {
+ filename = QString("report-%1%2.xml").arg(QString::number(filenum).rightJustify(2, '0'));
+ ++filenum;
+ }
+
+ QDomDocument* doc = new QDomDocument("KMYMONEY-FILE");
+ Q_CHECK_PTR(doc);
+
+ writeRCFtoXMLDoc(filter,doc);
+
+ QFile g( filename );
+ g.open( IO_WriteOnly );
+
+ QTextStream stream(&g);
+#if KDE_IS_VERSION(3,2,0)
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << doc->toString();
+#else
+ //stream.setEncoding(QTextStream::Locale);
+ QString temp = doc->toString();
+ stream << temp.data();
+#endif
+ g.close();
+
+ delete doc;
+}
+
+bool readRCFfromXMLDoc( QValueList<MyMoneyReport>& list, QDomDocument* doc )
+{
+ bool result = false;
+
+ QDomElement rootElement = doc->documentElement();
+ if(!rootElement.isNull())
+ {
+ QDomNode child = rootElement.firstChild();
+ while(!child.isNull() && child.isElement())
+ {
+ QDomElement childElement = child.toElement();
+ if("REPORTS" == childElement.tagName())
+ {
+ result = true;
+ QDomNode subchild = child.firstChild();
+ while(!subchild.isNull() && subchild.isElement())
+ {
+ MyMoneyReport filter;
+ if ( filter.read(subchild.toElement()))
+ {
+ list += filter;
+ }
+ subchild = subchild.nextSibling();
+ }
+ }
+ child = child.nextSibling();
+ }
+ }
+ return result;
+}
+
+bool readRCFfromXML( QValueList<MyMoneyReport>& list, const QString& filename )
+{
+ int result = false;
+ QFile f( filename );
+ f.open( IO_ReadOnly );
+ QDomDocument* doc = new QDomDocument;
+ if(doc->setContent(&f, FALSE))
+ {
+ result = readRCFfromXMLDoc(list,doc);
+ }
+ delete doc;
+
+ return result;
+
+}
+
+void XMLandback( MyMoneyReport& filter )
+{
+ // this function writes the filter to XML, and then reads
+ // it back from XML overwriting the original filter;
+ // in all cases, the result should be the same if the read
+ // & write methods are working correctly.
+
+ QDomDocument* doc = new QDomDocument("KMYMONEY-FILE");
+ Q_CHECK_PTR(doc);
+
+ writeRCFtoXMLDoc(filter,doc);
+ QValueList<MyMoneyReport> list;
+ if ( readRCFfromXMLDoc(list,doc) && list.count() > 0 )
+ filter = list[0];
+ else
+ throw new MYMONEYEXCEPTION("Failed to load report from XML");
+
+ delete doc;
+
+}
+
+MyMoneyMoney searchHTML(const QString& _html, const QString& _search)
+{
+ QRegExp re(QString("%1[<>/td]*([\\-.0-9,]*)").arg(_search));
+ re.search(_html);
+ QString found = re.cap(1);
+ found.remove(',');
+
+ return MyMoneyMoney(found.toDouble());
+}
+
+} // end namespace test
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/reportstestcommon.h b/kmymoney2/reports/reportstestcommon.h
new file mode 100644
index 0000000..6f4826e
--- /dev/null
+++ b/kmymoney2/reports/reportstestcommon.h
@@ -0,0 +1,133 @@
+/***************************************************************************
+ reportstestcommon.h
+ -------------------
+ copyright : (C) 2002-2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REPORTSTESTCOMMON_H
+#define REPORTSTESTCOMMON_H
+
+#include <qvaluelist.h>
+class QDomDocument;
+
+#include "../mymoney/mymoneyaccount.h"
+#include "../mymoney/mymoneytransaction.h"
+#include "../mymoney/mymoneymoney.h"
+class MyMoneyReport;
+
+namespace reports {
+class PivotTable;
+class QueryTable;
+}
+
+namespace test {
+
+extern const MyMoneyMoney moCheckingOpen;
+extern const MyMoneyMoney moCreditOpen;
+extern const MyMoneyMoney moConverterCheckingOpen;
+extern const MyMoneyMoney moConverterCreditOpen;
+extern const MyMoneyMoney moZero;
+extern const MyMoneyMoney moSolo;
+extern const MyMoneyMoney moParent1;
+extern const MyMoneyMoney moParent2;
+extern const MyMoneyMoney moParent;
+extern const MyMoneyMoney moChild;
+extern const MyMoneyMoney moThomas;
+extern const MyMoneyMoney moNoPayee;
+
+extern QString acAsset;
+extern QString acLiability;
+extern QString acExpense;
+extern QString acIncome;
+extern QString acChecking;
+extern QString acCredit;
+extern QString acSolo;
+extern QString acParent;
+extern QString acChild;
+extern QString acSecondChild;
+extern QString acGrandChild1;
+extern QString acGrandChild2;
+extern QString acForeign;
+extern QString acCanChecking;
+extern QString acJpyChecking;
+extern QString acCanCash;
+extern QString acJpyCash;
+extern QString inBank;
+extern QString eqStock1;
+extern QString eqStock2;
+extern QString acInvestment;
+extern QString acStock1;
+extern QString acStock2;
+extern QString acDividends;
+extern QString acInterest;
+extern QString acTax;
+extern QString acCash;
+
+class TransactionHelper: public MyMoneyTransaction
+{
+private:
+ QString m_id;
+public:
+ TransactionHelper( const QDate& _date, const QString& _action, MyMoneyMoney _value, const QString& _accountid, const QString& _categoryid, const QString& _currencyid = QString(), const QString& _payee="Test Payee" );
+ ~TransactionHelper();
+ void update(void);
+protected:
+ TransactionHelper(void) {}
+};
+
+class InvTransactionHelper: public TransactionHelper
+{
+public:
+ InvTransactionHelper( const QDate& _date, const QString& _action, MyMoneyMoney _shares, MyMoneyMoney _value, const QString& _stockaccountid, const QString& _transferid, const QString& _categoryid );
+ void init( const QDate& _date, const QString& _action, MyMoneyMoney _shares, MyMoneyMoney _value, const QString& _stockaccountid, const QString& _transferid, const QString& _categoryid );
+};
+
+class BudgetEntryHelper
+{
+private:
+ QDate m_date;
+ QString m_categoryid;
+ bool m_applytosub;
+ MyMoneyMoney m_amount;
+
+public:
+ BudgetEntryHelper( void ): m_applytosub(false) {}
+ BudgetEntryHelper( const QDate& _date, const QString& _categoryid, bool _applytosub, const MyMoneyMoney& _amount ): m_date(_date), m_categoryid(_categoryid), m_applytosub(_applytosub), m_amount(_amount) {}
+};
+
+class BudgetHelper: public QValueList<BudgetEntryHelper>
+{
+ MyMoneyMoney budgetAmount( const QDate& _date, const QString& _categoryid, bool& _applytosub );
+};
+
+extern QString makeAccount( const QString& _name, MyMoneyAccount::accountTypeE _type, MyMoneyMoney _balance, const QDate& _open, const QString& _parent, QString _currency="", bool _taxReport = false );
+extern void makePrice(const QString& _currencyid, const QDate& _date, const MyMoneyMoney& _price );
+QString makeEquity(const QString& _name, const QString& _symbol );
+extern void makeEquityPrice(const QString& _id, const QDate& _date, const MyMoneyMoney& _price );
+extern void writeRCFtoXMLDoc( const MyMoneyReport& filter, QDomDocument* doc );
+extern void writeTabletoHTML( const reports::PivotTable& table, const QString& _filename = QString() );
+extern void writeTabletoHTML( const reports::QueryTable& table, const QString& _filename = QString() );
+extern void writeTabletoCSV( const reports::PivotTable& table, const QString& _filename = QString() );
+extern void writeTabletoCSV( const reports::QueryTable& table, const QString& _filename = QString() );
+extern void writeRCFtoXML( const MyMoneyReport& filter, const QString& _filename = QString() );
+extern bool readRCFfromXMLDoc( QValueList<MyMoneyReport>& list, QDomDocument* doc );
+extern bool readRCFfromXML( QValueList<MyMoneyReport>& list, const QString& filename );
+extern void XMLandback( MyMoneyReport& filter );
+extern MyMoneyMoney searchHTML(const QString& _html, const QString& _search);
+
+} // end namespace test
+
+#endif // REPORTSTESTCOMMON_H
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/reports/reporttable.h b/kmymoney2/reports/reporttable.h
new file mode 100644
index 0000000..3bab330
--- /dev/null
+++ b/kmymoney2/reports/reporttable.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ reporttable.h
+ -------------------
+ begin : Mon May 7 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REPORTTABLE_H
+#define REPORTTABLE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+namespace reports {
+
+class KReportChartView;
+
+/**
+ * This class serves as interface definition for both a pivottable
+ * and a querytable object
+ */
+class ReportTable
+{
+protected:
+ ReportTable() {}
+public:
+ virtual ~ReportTable() {}
+ virtual QString renderHTML(void) const = 0;
+ virtual QString renderCSV(void) const = 0;
+ virtual void drawChart(KReportChartView& view) const = 0;
+ virtual void dump(const QString& file, const QString& context=QString()) const = 0;
+};
+
+}
+#endif
+// REPORTTABLE_H
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/templates/C/Makefile.am b/kmymoney2/templates/C/Makefile.am
new file mode 100644
index 0000000..3d9f42b
--- /dev/null
+++ b/kmymoney2/templates/C/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/C
+
+template_DATA = homeown.kmt full.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt old-default_accounts.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt checkbook.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt default_categories-template.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/C/brokerage.kmt b/kmymoney2/templates/C/brokerage.kmt
new file mode 100644
index 0000000..40dc265
--- /dev/null
+++ b/kmymoney2/templates/C/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Investment Accounts</title>
+ <shortdesc>Brokerage account with related investment accounts (stock, bond, mutual fund, index fund, interest, dividend)</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have investments (stock, bond, mutual fund, index fund, interest, dividend).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Commissions"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividend Income"/>
+ <account type="12" name="Interest Income">
+ <account type="12" name="Bond Interest"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investments">
+ <account type="7" name="Brokerage Account"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/business.kmt b/kmymoney2/templates/C/business.kmt
new file mode 100644
index 0000000..387de38
--- /dev/null
+++ b/kmymoney2/templates/C/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Business Accounts</title>
+ <shortdesc>Full chart of accounts for a business.</shortdesc>
+ <longdesc>Users running a business want to select this instead of other choices. This includes all the accounts you need to run a most businesses, including Payables, Receivables, Income, and Expenses.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="Credit Card"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Retained Earnings"/>
+ <account type="16" name="Opening Balances"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Equipment Rental"/>
+ <account type="13" name="Miscellaneous"/>
+ <account type="13" name="Repairs">
+ <account type="13" name="Equipment Repairs"/>
+ <account type="13" name="Building Repairs"/>
+ <account type="13" name="Computer Repairs"/>
+ <account type="13" name="Janitorial Expenses"/>
+ </account>
+ <account type="13" name="Postage and Delivery"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Depreciation"/>
+ <account type="13" name="Office Supplies"/>
+ <account type="13" name="Professional Fees">
+ <account type="13" name="Legal Fees"/>
+ <account type="13" name="Accounting"/>
+ </account>
+ <account type="13" name="Printing and Reproduction"/>
+ <account type="13" name="Dining"/>
+ <account type="13" name="Dues and Subscriptions"/>
+ <account type="13" name="Licenses and Permits"/>
+ <account type="13" name="Cash Discounts"/>
+ <account type="13" name="Payroll Expenses"/>
+ <account type="13" name="Outside Services"/>
+ <account type="13" name="Adjustment"/>
+ <account type="13" name="Travel and Entertainment">
+ <account type="13" name="Meals"/>
+ <account type="13" name="Travel"/>
+ <account type="13" name="Entertainment"/>
+ </account>
+ <account type="13" name="Charity"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Repair and Maintenance"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Fees"/>
+ </account>
+ <account type="13" name="Rent"/>
+ <account type="13" name="Utilities">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Garbage collection"/>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Cell Phone"/>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Electric"/>
+ <account type="13" name="Water"/>
+ <account type="13" name="Phone"/>
+ </account>
+ <account type="13" name="Insurance">
+ <account type="13" name="Disability Insurance"/>
+ <account type="13" name="Workers Comp"/>
+ <account type="13" name="Liability Insurance"/>
+ </account>
+ <account type="13" name="Bank Service Charge"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Federal"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="Property"/>
+ <account type="13" name="Local"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="Other Tax"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="FUTA"/>
+ </account>
+ <account type="13" name="Books"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Interest Income"/>
+ <account type="12" name="Sales"/>
+ <account type="12" name="Other Income"/>
+ <account type="12" name="Reimbursed Expenses"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Savings Account"/>
+ <account type="3" name="Petty Cash"/>
+ <account type="1" name="Checking Account"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/carloan.kmt b/kmymoney2/templates/C/carloan.kmt
new file mode 100644
index 0000000..d9f1ea0
--- /dev/null
+++ b/kmymoney2/templates/C/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Car Loan</title>
+ <shortdesc>Accounts for car loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a car loan (car loan, car loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Vehicle Loan Interest"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Loans">
+ <account type="10" name="Vehicle Loan"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/cdmoneymkt.kmt b/kmymoney2/templates/C/cdmoneymkt.kmt
new file mode 100644
index 0000000..2987894
--- /dev/null
+++ b/kmymoney2/templates/C/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD and Money Market</title>
+ <shortdesc>Accounts for CD and money market investments</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have CDs or money market accounts (CD, CD interest, money market, money market interest).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Interest Income">
+ <account type="12" name="CD Interest"/>
+ <account type="12" name="Money Market Interest"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Money Market"/>
+ <account type="1" name="Bank CD"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/checkbook.kmt b/kmymoney2/templates/C/checkbook.kmt
new file mode 100644
index 0000000..c22a353
--- /dev/null
+++ b/kmymoney2/templates/C/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>A Simple Checkbook</title>
+ <shortdesc>The minimal set of accounts to use GnuCash.</shortdesc>
+ <longdesc>Use this if you just want to balance your checkbook. Later on, you can start tracking income and expenses in more detail if you feel the need.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Opening Balances"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Checking Account"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/childcare.kmt b/kmymoney2/templates/C/childcare.kmt
new file mode 100644
index 0000000..f7df804
--- /dev/null
+++ b/kmymoney2/templates/C/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Childcare Expenses</title>
+ <shortdesc>An account for tracking childcare costs</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have childcare expenses.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Childcare"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/common.kmt b/kmymoney2/templates/C/common.kmt
new file mode 100644
index 0000000..ead6d29
--- /dev/null
+++ b/kmymoney2/templates/C/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Common Accounts</title>
+ <shortdesc>A basic set of accounts most commonly used</shortdesc>
+ <longdesc>Most users will want to select this set of accounts. It includes most commonly used accounts (checking, savings, cash, credit card, income, common expenses).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Other Income"/>
+ <account type="12" name="Gifts Received"/>
+ <account type="12" name="Salary"/>
+ <account type="12" name="Interest Income">
+ <account type="12" name="Other Interest"/>
+ <account type="12" name="Savings Interest"/>
+ <account type="12" name="Checking Interest"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Opening Balances"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Checking Account"/>
+ <account type="3" name="Cash in Wallet"/>
+ <account type="1" name="Savings Account"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Entertainment">
+ <account type="13" name="Music/Movies"/>
+ <account type="13" name="Travel"/>
+ <account type="13" name="Recreation"/>
+ </account>
+ <account type="13" name="Books"/>
+ <account type="13" name="Dining"/>
+ <account type="13" name="Gifts"/>
+ <account type="13" name="Medical Expenses"/>
+ <account type="13" name="Charity"/>
+ <account type="13" name="Public Transportation"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Repair and Maintenance"/>
+ <account type="13" name="Fees"/>
+ </account>
+ <account type="13" name="Bank Service Charge"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Utilities">
+ <account type="13" name="Water"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Garbage collection"/>
+ <account type="13" name="Electric"/>
+ </account>
+ <account type="13" name="Supplies"/>
+ <account type="13" name="Clothes"/>
+ <account type="13" name="Subscriptions"/>
+ <account type="13" name="Phone"/>
+ <account type="13" name="Insurance">
+ <account type="13" name="Auto Insurance"/>
+ <account type="13" name="Life Insurance"/>
+ <account type="13" name="Health Insurance"/>
+ </account>
+ <account type="13" name="Online Services"/>
+ <account type="13" name="Adjustment"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Social Security"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Federal"/>
+ <account type="13" name="Medicare"/>
+ <account type="13" name="Other Tax"/>
+ </account>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Laundry/Dry Cleaning"/>
+ <account type="13" name="Miscellaneous"/>
+ <account type="13" name="Groceries"/>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Hobbies"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Credit Card"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/default_categories-template.kmt b/kmymoney2/templates/C/default_categories-template.kmt
new file mode 100644
index 0000000..03a13df
--- /dev/null
+++ b/kmymoney2/templates/C/default_categories-template.kmt
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 default</title>
+ <shortdesc/>
+ <longdesc/>
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Employment" >
+ <account type="12" name="Benefits" />
+ <account type="12" name="Bonus" />
+ <account type="12" name="Other employment income" />
+ <account type="12" name="Pension" />
+ <account type="12" name="Wages &amp; Salary" />
+ </account>
+ <account type="12" name="Investment Income" >
+ <account type="12" name="Short-Term Capital Gains" />
+ <account type="12" name="Long-Term Capital Gains" />
+ <account type="12" name="Dividends" />
+ <account type="12" name="Interest" />
+ <account type="12" name="Tax-Exempt Interest" />
+ </account>
+ <account type="12" name="Banking" >
+ <account type="12" name="Interest Earned" />
+ <account type="12" name="Loan Principal Received" />
+ </account>
+ <account type="12" name="Other Income" >
+ <account type="12" name="Alimony" />
+ <account type="12" name="Child Support" />
+ <account type="12" name="Disability" />
+ <account type="12" name="Gifts Received" />
+ <account type="12" name="Lottery or Premium Bond Prizes" />
+ <account type="12" name="Tax Refund" />
+ <account type="12" name="Unemployment Benefit" />
+ </account>
+ <account type="12" name="Retirement Income" />
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Bills &amp; monthly payments" >
+ <account type="13" name="Utilities" >
+ <account type="13" name="Electricity" />
+ <account type="13" name="Fuel Oil" />
+ <account type="13" name="Natural Gas" />
+ <account type="13" name="Water &amp; Sewage" />
+ <account type="13" name="Garbage &amp; Recycling" />
+ </account>
+ <account type="13" name="Telephone" >
+ <account type="13" name="Local" />
+ <account type="13" name="Long Distance" />
+ <account type="13" name="Wireless" />
+ </account>
+ <account type="13" name="Rent" />
+ <account type="13" name="Mortgage" >
+ <account type="13" name="Interest" />
+ <account type="13" name="Principal" />
+ </account>
+ <account type="13" name="Cable / Satelite TV" />
+ <account type="13" name="Internet" />
+ </account>
+ <account type="13" name="Bank Charges" >
+ <account type="13" name="Interest Paid" />
+ <account type="13" name="Service Charges" />
+ <account type="13" name="Insufficient Funds fee" />
+ </account>
+ <account type="13" name="Cash Withdrawal" />
+ <account type="13" name="Child Care/Sitters" />
+ <account type="13" name="Clothing" />
+ <account type="13" name="Education" >
+ <account type="13" name="Books" />
+ <account type="13" name="Fees" />
+ <account type="13" name="Tuition" />
+ <account type="13" name="Loans" />
+ </account>
+ <account type="13" name="Food" >
+ <account type="13" name="Dining Out" />
+ <account type="13" name="Groceries" />
+ </account>
+ <account type="13" name="Home Maintainance" >
+ <account type="13" name="Repairs" />
+ <account type="13" name="Improvements" />
+ <account type="13" name="Yard &amp; Garden" />
+ </account>
+ <account type="13" name="Home Furnishing" >
+ <account type="13" name="Furniture" />
+ <account type="13" name="Decorating" />
+ </account>
+ <account type="13" name="Gifts" />
+ <account type="13" name="Healthcare" >
+ <account type="13" name="Dental" />
+ <account type="13" name="Doctor" />
+ <account type="13" name="Hospital" />
+ <account type="13" name="Prescriptions" />
+ <account type="13" name="Chiropractic" />
+ <account type="13" name="Other" />
+ </account>
+ <account type="13" name="Personal Care" />
+ <account type="13" name="Vacation &amp; Holiday" >
+ <account type="13" name="Accomodations" />
+ <account type="13" name="Travel" />
+ <account type="13" name="Other" />
+ <account type="13" name="Meals" />
+ </account>
+ <account type="13" name="Insurance" >
+ <account type="13" name="Home and Contents" />
+ <account type="13" name="Life" />
+ <account type="13" name="Medical" />
+ <account type="13" name="Auto" />
+ <account type="13" name="Disability" />
+ </account>
+ <account type="13" name="Job Expense" >
+ <account type="13" name="Non-Reimbursed" />
+ <account type="13" name="Reimbursed" />
+ </account>
+ <account type="13" name="Recreation &amp; Leisure" >
+ <account type="13" name="Entertainment" />
+ <account type="13" name="Hobbies" />
+ <account type="13" name="Sports" />
+ </account>
+ <account type="13" name="Legal Fees" />
+ <account type="13" name="Other Misc. Expenses" />
+ <account type="13" name="Pet Care" >
+ <account type="13" name="Food" />
+ <account type="13" name="Supplies" />
+ <account type="13" name="Vet's Bills" />
+ </account>
+ <account type="13" name="Retirement Accounts" />
+ <account type="13" name="Taxes" />
+ <account type="13" name="Transportation" >
+ <account type="13" name="Car / Auto" >
+ <account type="13" name="Fuel" />
+ <account type="13" name="Service" />
+ <account type="13" name="Insurance" />
+ <account type="13" name="Lease" />
+ <account type="13" name="Loan" />
+ <account type="13" name="Registration" />
+ </account>
+ <account type="13" name="Public Transportation" />
+ </account>
+ <account type="13" name="Household" />
+ <account type="13" name="Charity" />
+ <account type="13" name="Accountant &amp; Tax Preparation" />
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/eduloan.kmt b/kmymoney2/templates/C/eduloan.kmt
new file mode 100644
index 0000000..a9afd5f
--- /dev/null
+++ b/kmymoney2/templates/C/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Education Loan</title>
+ <shortdesc>Accounts for school loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have an educational loan (education loan, education loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Education Loan Interest"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Loans">
+ <account type="10" name="Education Loan"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/fixedassets.kmt b/kmymoney2/templates/C/fixedassets.kmt
new file mode 100644
index 0000000..598d392
--- /dev/null
+++ b/kmymoney2/templates/C/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Fixed Assets</title>
+ <shortdesc>Accounts for tracking large fixed assets</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have large fixed assets (house, vehicle, vacation home, other assets).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Fixed Assets">
+ <account type="9" name="Vehicle"/>
+ <account type="9" name="Other Asset"/>
+ <account type="9" name="House"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/full.kmt b/kmymoney2/templates/C/full.kmt
new file mode 100644
index 0000000..3d00bb4
--- /dev/null
+++ b/kmymoney2/templates/C/full.kmt
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_full.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Full Chart</title>
+ <shortdesc>Full chart of accounts contains all default accounts.</shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Interest Income">
+ <account type="12" name="Savings Interest"/>
+ <account type="12" name="Money Market Interest"/>
+ <account type="12" name="Checking Interest"/>
+ <account type="12" name="CD Interest"/>
+ <account type="12" name="Other Interest"/>
+ <account type="12" name="Bond Interest"/>
+ </account>
+ <account type="12" name="Other Income"/>
+ <account type="12" name="Gifts Received"/>
+ <account type="12" name="Dividend Income"/>
+ <account type="12" name="Salary (Spouse)"/>
+ <account type="12" name="Salary"/>
+ <account type="12" name="Bonus"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Line of Credit"/>
+ <account type="10" name="Loans">
+ <account type="10" name="Vehicle Loan"/>
+ <account type="10" name="Mortgage Loan"/>
+ <account type="10" name="Other Loan"/>
+ <account type="10" name="Education Loan"/>
+ </account>
+ <account type="4" name="Credit Card"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Commissions"/>
+ <account type="13" name="Clothes"/>
+ <account type="13" name="Adjustment"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Dining"/>
+ <account type="13" name="Supplies"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Repair and Maintenance"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Fees"/>
+ </account>
+ <account type="13" name="Entertainment">
+ <account type="13" name="Music/Movies"/>
+ <account type="13" name="Recreation"/>
+ <account type="13" name="Travel"/>
+ </account>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Childcare"/>
+ <account type="13" name="Laundry/Dry Cleaning"/>
+ <account type="13" name="Bank Service Charge"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Property Tax"/>
+ <account type="13" name="Other Tax"/>
+ <account type="13" name="Social Security"/>
+ <account type="13" name="Federal"/>
+ <account type="13" name="Medicare"/>
+ </account>
+ <account type="13" name="Insurance">
+ <account type="13" name="Home Insurance"/>
+ <account type="13" name="Life Insurance"/>
+ <account type="13" name="Auto Insurance"/>
+ <account type="13" name="Health Insurance"/>
+ <account type="13" name="Rental Insurance"/>
+ </account>
+ <account type="13" name="Charity"/>
+ <account type="13" name="Home Repair"/>
+ <account type="13" name="Groceries"/>
+ <account type="13" name="Online Services"/>
+ <account type="13" name="Rent"/>
+ <account type="13" name="Taxes (Spouse)">
+ <account type="13" name="Social Security"/>
+ <account type="13" name="Other Tax"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Medicare"/>
+ <account type="13" name="Federal"/>
+ </account>
+ <account type="13" name="Interest">
+ <account type="13" name="Mortgage Interest"/>
+ <account type="13" name="Other Interest"/>
+ <account type="13" name="Education Loan Interest"/>
+ <account type="13" name="Vehicle Loan Interest"/>
+ </account>
+ <account type="13" name="Miscellaneous"/>
+ <account type="13" name="Subscriptions"/>
+ <account type="13" name="Public Transportation"/>
+ <account type="13" name="Medical Expenses"/>
+ <account type="13" name="Hobbies"/>
+ <account type="13" name="Gifts"/>
+ <account type="13" name="Books"/>
+ <account type="13" name="Utilities">
+ <account type="13" name="Water"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Garbage collection"/>
+ <account type="13" name="Electric"/>
+ </account>
+ <account type="13" name="Phone"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Fixed Assets">
+ <account type="9" name="House"/>
+ <account type="9" name="Other Asset"/>
+ <account type="9" name="Vehicle"/>
+ </account>
+ <account type="9" name="Current Assets">
+ <account type="1" name="Bank CD"/>
+ <account type="1" name="Money Market"/>
+ <account type="3" name="Cash in Wallet"/>
+ <account type="1" name="Savings Account"/>
+ <account type="1" name="Checking Account"/>
+ </account>
+ <account type="9" name="Investments">
+ <account type="7" name="Retirement"/>
+ <account type="7" name="Brokerage Account"/>
+ <account type="7" name="Spouse Retirement"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Opening Balances"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/homeloan.kmt b/kmymoney2/templates/C/homeloan.kmt
new file mode 100644
index 0000000..bd0a7c4
--- /dev/null
+++ b/kmymoney2/templates/C/homeloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Home Mortgage Loan</title>
+ <shortdesc>Accounts for home loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a home loan (mortgage loan, mortgage interest).</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Mortgage Loan"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Mortgage Interest"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/homeown.kmt b/kmymoney2/templates/C/homeown.kmt
new file mode 100644
index 0000000..d483238
--- /dev/null
+++ b/kmymoney2/templates/C/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Homeowner Expenses</title>
+ <shortdesc>Expenses associated with owning a home</shortdesc>
+ <longdesc>You would want to select this set of accounts if you own a home. This set provides a group of accounts to track home expenses (insurance, taxes, home repair).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Insurance">
+ <account type="13" name="Home Insurance"/>
+ </account>
+ <account type="13" name="Taxes">
+ <account type="13" name="Property Tax"/>
+ </account>
+ <account type="13" name="Home Repair"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/old-default_accounts.kmt b/kmymoney2/templates/C/old-default_accounts.kmt
new file mode 100644
index 0000000..7ccb476
--- /dev/null
+++ b/kmymoney2/templates/C/old-default_accounts.kmt
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title></title>
+ <shortdesc></shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Bills" type="13">
+ <account name="Telephone" type="13"/>
+ <account name="Rent" type="13"/>
+ <account name="Electricity" type="13"/>
+ <account name="TV" type="13"/>
+ <account name="SKY" type="13"/>
+ <account name="Council Tax" type="13"/>
+ <account name="Fuel Oil" type="13"/>
+ <account name="Gas" type="13"/>
+ <account name="Mortgage Interest" type="13"/>
+ <account name="Water &amp; Sewage" type="13"/>
+ </account>
+ <account name="Bank Charges" type="13">
+ <account name="Interest Paid" type="13"/>
+ <account name="Service Charge" type="13"/>
+ </account>
+ <account name="Car" type="13">
+ <account name="Car Maintenance" type="13"/>
+ <account name="Petrol" type="13"/>
+ </account>
+ <account name="Cash Withdrawal" type="13"/>
+ <account name="Charity" type="13">
+ <account name="Covenants" type="13"/>
+ <account name="Donations" type="13"/>
+ <account name="Settlements" type="13"/>
+ </account>
+ <account name="Child Care" type="13"/>
+ <account name="Christmas" type="13"/>
+ <account name="Clothing" type="13"/>
+ <account name="Education" type="13">
+ <account name="Books" type="13"/>
+ <account name="Fees" type="13"/>
+ <account name="Tuition" type="13"/>
+ </account>
+ <account name="Food" type="13">
+ <account name="Dining Out" type="13"/>
+ <account name="Groceries" type="13"/>
+ </account>
+ <account name="Gardening" type="13"/>
+ <account name="Healthcare" type="13">
+ <account name="Dental" type="13"/>
+ <account name="Doctor" type="13"/>
+ <account name="Hospital" type="13"/>
+ <account name="Optician" type="13"/>
+ <account name="Prescriptions" type="13"/>
+ </account>
+ <account name="Holidays" type="13">
+ <account name="Accomodation" type="13"/>
+ <account name="Travel" type="13"/>
+ </account>
+ <account name="Household" type="13">
+ <account name="Furnishings" type="13"/>
+ </account>
+ <account name="Insurance" type="13">
+ <account name="Home and Contents" type="13"/>
+ <account name="Life" type="13"/>
+ <account name="Medical" type="13"/>
+ <account name="Motor" type="13"/>
+ </account>
+ <account name="Job Expense" type="13">
+ <account name="Non-Reimbursed" type="13"/>
+ <account name="Reimbursed" type="13"/>
+ </account>
+ <account name="Leisure" type="13">
+ <account name="Books &amp; Magazines" type="13"/>
+ <account name="Entertaining" type="13"/>
+ <account name="Films &amp; Video Rentals" type="13"/>
+ <account name="Sporting Events" type="13"/>
+ <account name="Sports Goods" type="13"/>
+ <account name="Tapes &amp; CDs" type="13"/>
+ <account name="Theatre &amp; Concerts etc" type="13"/>
+ <account name="Toys &amp; Games" type="13"/>
+ </account>
+ <account name="Loan" type="13">
+ <account name="Loan Interest" type="13"/>
+ </account>
+ <account name="Motor" type="13">
+ <account name="Fuel" type="13"/>
+ <account name="Loan" type="13"/>
+ <account name="Service" type="13"/>
+ </account>
+ <account name="Other Expense" type="13">
+ <account name="Unknown" type="13"/>
+ </account>
+ <account name="Pet Care" type="13">
+ <account name="Food" type="13"/>
+ <account name="Supplies" type="13"/>
+ <account name="Vet's Bills" type="13"/>
+ </account>
+ <account name="Recreation" type="13"/>
+ <account name="Taxes" type="13">
+ <account name="1st option" type="13"/>
+ <account name="Foreign savings" type="13"/>
+ <account name="Income Tax" type="13"/>
+ <account name="Interest" type="13"/>
+ <account name="Local Tax" type="13"/>
+ <account name="Nat Ins" type="13"/>
+ <account name="Other Invest" type="13"/>
+ <account name="Other Tax" type="13"/>
+ <account name="Unit trust" type="13"/>
+ </account>
+ <account name="Utilities" type="13">
+ <account name="Electricity" type="13"/>
+ <account name="Gas" type="13"/>
+ <account name="Telephone" type="13"/>
+ <account name="Water" type="13"/>
+ </account>
+ </account>
+ <account name="" type="12">
+ <account name="Alimony" type="12"/>
+ <account name="Bonus" type="12"/>
+ <account name="Capital gains" type="12"/>
+ <account name="Child Benefit" type="12"/>
+ <account name="Div Income" type="12">
+ <account name="Ord dividend" type="12"/>
+ <account name="Stock dividend" type="12"/>
+ </account>
+ <account name="Employment" type="12">
+ <account name="Benefits" type="12"/>
+ <account name="Foreign" type="12"/>
+ <account name="Lump sums" type="12"/>
+ <account name="Other employ" type="12"/>
+ <account name="Salary &amp; wages" type="12"/>
+ </account>
+ <account name="Gift Received" type="12"/>
+ <account name="Int Inc" type="12">
+ <account name="Bank Interest" type="12"/>
+ <account name="Gross" type="12"/>
+ <account name="Net" type="12"/>
+ <account name="Other savings" type="12"/>
+ </account>
+ <account name="Invest. income" type="12">
+ <account name="1st option" type="12"/>
+ <account name="Dividend" type="12"/>
+ <account name="Foreign" type="12"/>
+ <account name="Other savings" type="12"/>
+ <account name="Other trusts" type="12"/>
+ <account name="Other trusts#Capital" type="12"/>
+ <account name="Other trusts#Dist. rec'd" type="12"/>
+ <account name="Other trusts#Estate" type="12"/>
+ <account name="UK other" type="12"/>
+ <account name="UK other#Unit trusts" type="12"/>
+ </account>
+ <account name="Investment Income" type="12">
+ <account name="Capital Gains" type="12"/>
+ <account name="Dividends" type="12"/>
+ <account name="Interest" type="12"/>
+ <account name="Tax-Exempt Interest" type="12"/>
+ </account>
+ <account name="Nat. Savings" type="12">
+ <account name="Capital bonds" type="12"/>
+ <account name="Deposit bonds" type="12"/>
+ <account name="Income bonds" type="12"/>
+ <account name="Invest. account" type="12"/>
+ <account name="Ord. account" type="12"/>
+ </account>
+ <account name="Old Age Pension" type="12">
+ <account name="Employer" type="12"/>
+ <account name="State" type="12"/>
+ </account>
+ <account name="Other Income" type="12">
+ <account name="Student loan" type="12"/>
+ <account name="Child Support" type="12"/>
+ <account name="Employee Share Option" type="12"/>
+ <account name="Gifts Received" type="12"/>
+ <account name="Loan Principal Received" type="12"/>
+ <account name="Lottery or Premium Bond Prizes" type="12"/>
+ <account name="Tax Refund" type="12"/>
+ <account name="Unemployment Benefit" type="12"/>
+ </account>
+ <account name="Retirement Income" type="12">
+ <account name="Pensions &amp; Annuities" type="12"/>
+ <account name="State Pension Benefits" type="12"/>
+ </account>
+ <account name="Social security" type="12">
+ <account name="Industrial" type="12"/>
+ <account name="Invalid" type="12"/>
+ <account name="Widowed" type="12"/>
+ </account>
+ <account name="Wages &amp; Salary" type="12">
+ <account name="Bonus" type="12"/>
+ <account name="Commission" type="12"/>
+ <account name="Employer Pension Contributions" type="12"/>
+ <account name="Gross Pay" type="12"/>
+ <account name="Net Pay" type="12"/>
+ <account name="Overtime" type="12"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/otherloan.kmt b/kmymoney2/templates/C/otherloan.kmt
new file mode 100644
index 0000000..b5ff4bb
--- /dev/null
+++ b/kmymoney2/templates/C/otherloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Other Loans</title>
+ <shortdesc>Accounts for tracking other loans and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have something other than a home loan (other loan, other loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Other Interest"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ <account type="10" name="">
+ <account type="10" name="Other Loan"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/renter.kmt b/kmymoney2/templates/C/renter.kmt
new file mode 100644
index 0000000..5252106
--- /dev/null
+++ b/kmymoney2/templates/C/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Renter Expenses</title>
+ <shortdesc>Expenses associated with renting a home</shortdesc>
+ <longdesc>You would want to select this set of accounts if you rent a home or apartment (rent, renter's insurance).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Rent"/>
+ <account type="13" name="Insurance">
+ <account type="13" name="Rental Insurance"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/retiremt.kmt b/kmymoney2/templates/C/retiremt.kmt
new file mode 100644
index 0000000..d2b1ee5
--- /dev/null
+++ b/kmymoney2/templates/C/retiremt.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Retirement Accounts</title>
+ <shortdesc>Retirement account with related investment subaccounts</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have retirement accounts (stock, bond, mutual fund, index fund).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="Retirement"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/spouseinc.kmt b/kmymoney2/templates/C/spouseinc.kmt
new file mode 100644
index 0000000..f034f5e
--- /dev/null
+++ b/kmymoney2/templates/C/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Spouse Income</title>
+ <shortdesc>Accounts for tracking spouse's income separately</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a working spouse (salary (spouse), taxes (spouse)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Salary (Spouse)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Taxes (Spouse)">
+ <account type="13" name="Social Security"/>
+ <account type="13" name="Medicare"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Federal"/>
+ <account type="13" name="Other Tax"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/C/spouseretire.kmt b/kmymoney2/templates/C/spouseretire.kmt
new file mode 100644
index 0000000..d026dc1
--- /dev/null
+++ b/kmymoney2/templates/C/spouseretire.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Spouse Retirement Accounts</title>
+ <shortdesc>Retirement account with related investment accounts for spouse</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have investments in a spouse's name (stock, bond, mutual fund, index fund, interest, dividend).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="Spouse Retirement"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/CMakeLists.txt b/kmymoney2/templates/CMakeLists.txt
new file mode 100644
index 0000000..11f53f1
--- /dev/null
+++ b/kmymoney2/templates/CMakeLists.txt
@@ -0,0 +1,11 @@
+########### install files ###############
+
+INSTALL(DIRECTORY
+ C de_AT de_CH de_DE dk el_GR en_GB en_US es_AR es_ES es_MX fr_CA
+ fr_CH fr_FR gl_ES hu_HU it jp nl_NL pt_BR pt_PT ro_RO ru_RU sk tr_TR
+ zh_CN zh_HK zh_TW
+ DESTINATION share/apps/kmymoney2/templates
+ PATTERN "CVS" EXCLUDE
+ PATTERN ".cvsignore" EXCLUDE
+ PATTERN "*Make*" EXCLUDE
+ )
diff --git a/kmymoney2/templates/Makefile.am b/kmymoney2/templates/Makefile.am
new file mode 100644
index 0000000..b10565a
--- /dev/null
+++ b/kmymoney2/templates/Makefile.am
@@ -0,0 +1,3 @@
+templatedir=$(kde_datadir)/kmymoney2/templates
+
+SUBDIRS = C de_AT de_CH de_DE dk el_GR en_GB en_US es_AR es_ES es_MX fr_CA fr_CH fr_FR gl_ES hu_HU it jp nl_NL pt_BR pt_PT ro_RO ru_RU sk tr_TR zh_CN zh_HK zh_TW
diff --git a/kmymoney2/templates/cpp_template b/kmymoney2/templates/cpp_template
new file mode 100644
index 0000000..6bca001
--- /dev/null
+++ b/kmymoney2/templates/cpp_template
@@ -0,0 +1,31 @@
+/***************************************************************************
+ |FILENAME| - description
+ -------------------
+ begin : |DATE|
+ copyright : (C) 2000-|YEAR| by |AUTHOR|
+ email : |EMAIL|
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
diff --git a/kmymoney2/templates/de_AT/Makefile.am b/kmymoney2/templates/de_AT/Makefile.am
new file mode 100644
index 0000000..eee2ea5
--- /dev/null
+++ b/kmymoney2/templates/de_AT/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/de_AT
+
+template_DATA = houseown.kmt kids.kmt investment.kmt autoloan.kmt common.kmt brokerage.kmt business.kmt auto.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/de_AT/auto.kmt b/kmymoney2/templates/de_AT/auto.kmt
new file mode 100644
index 0000000..cb09691
--- /dev/null
+++ b/kmymoney2/templates/de_AT/auto.kmt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_auto.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Autobesitz</title>
+ <shortdesc>Ausgaben von Autobesitzern</shortdesc>
+ <longdesc>Diese Auswahl erstellt Konten, die Ausgaben für ein Auto repräsentieren.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Auto">
+ <account type="13" name="Versicherungen"/>
+ <account type="13" name="Abgaben"/>
+ <account type="13" name="Benzin"/>
+ <account type="13" name="Reparaturen"/>
+ <account type="13" name="Parkgebühren"/>
+ </account>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Auto"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/autoloan.kmt b/kmymoney2/templates/de_AT/autoloan.kmt
new file mode 100644
index 0000000..1a02110
--- /dev/null
+++ b/kmymoney2/templates/de_AT/autoloan.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_autoloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kredit Auto</title>
+ <shortdesc>Kredit für Autokauf</shortdesc>
+ <longdesc>Falls Sie einen Kredit zum Autokauf besitzen, können Sie mit dieser Auswahl die passenden Konten bekommen.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Auto">
+ <account type="13" name="Kreditzinsen"/>
+ </account>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="Auto"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/brokerage.kmt b/kmymoney2/templates/de_AT/brokerage.kmt
new file mode 100644
index 0000000..bf9d427
--- /dev/null
+++ b/kmymoney2/templates/de_AT/brokerage.kmt
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Aktienhandel</title>
+ <shortdesc>Konten zum Handel mit Aktien und Fonds</shortdesc>
+ <longdesc>Mit dieser Auswahl werden Konten zum Handel mit Aktien und Aktienfonds erstellt.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Komissionen"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividenden"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Geldanlagen">
+ <account type="9" name="Aktiendepot">
+ <account type="9" name="Bond"/>
+ <account type="9" name="Aktienfond"/>
+ <account type="9" name="Aktie"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/business.kmt b/kmymoney2/templates/de_AT/business.kmt
new file mode 100644
index 0000000..0ae0692
--- /dev/null
+++ b/kmymoney2/templates/de_AT/business.kmt
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kleinunternehmen</title>
+ <shortdesc>Grundlegende Konten für Kleinunternehmen</shortdesc>
+ <longdesc>Kleinunternehmer können diesen Kontorahmen anstelle der anderen Kontorahmen verwenden. Sie finden hier die grundlegenden Konten für ein Kleinunternehmen wie Forderungen, Verbindlichkeiten, Steuer, Aufwendungen und Erträge.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Barverbindlichkeiten">
+ <account type="4" name="Kreditkarte"/>
+ </account>
+ <account type="10" name="Umsatzsteuer"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Sonstiges"/>
+ <account type="12" name="Zurückerstattete Aufwendungen"/>
+ <account type="12" name="Zinsen">
+ <account type="12" name="Girokonto"/>
+ <account type="12" name="Sonstige"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Vorsteuer"/>
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Sonstige"/>
+ </account>
+ <account type="9" name="Barvermögen">
+ <account type="1" name="Girokonto"/>
+ <account type="3" name="Bargeld"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Postgebühren"/>
+ <account type="13" name="Büro">
+ <account type="13" name="Nebenkosten">
+ <account type="13" name="Strom"/>
+ <account type="13" name="Rundfunkgebühren"/>
+ <account type="13" name="Hausverwaltung"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Wasser"/>
+ <account type="13" name="Abfall"/>
+ </account>
+ <account type="13" name="Miete"/>
+ <account type="13" name="Möbel"/>
+ </account>
+ <account type="13" name="Abschreibungen"/>
+ <account type="13" name="Beratungskosten">
+ <account type="13" name="Rechtskosten"/>
+ <account type="13" name="Steuerberatung"/>
+ <account type="13" name="Buchhaltung"/>
+ </account>
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Netzkarten"/>
+ <account type="13" name="Fahrkarten"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Parkgebühren"/>
+ <account type="13" name="Abgaben"/>
+ <account type="13" name="Wartung und Reparaturen"/>
+ <account type="13" name="Treibstoff"/>
+ </account>
+ </account>
+ <account type="13" name="Steuern">
+ <account type="13" name="Sonstige"/>
+ <account type="13" name="Einkommenssteuer"/>
+ <account type="13" name="Körperschaftssteuer"/>
+ <account type="13" name="Umsatzsteuer Zahllast"/>
+ </account>
+ <account type="13" name="Interessensvertretung"/>
+ <account type="13" name="Lohnkosten"/>
+ <account type="13" name="Druck- und Kopierkosten"/>
+ <account type="13" name="EDV">
+ <account type="13" name="Software"/>
+ <account type="13" name="Hardware"/>
+ </account>
+ <account type="13" name="Fachliteratur"/>
+ <account type="13" name="Sonstiges"/>
+ <account type="13" name="Spenden"/>
+ <account type="13" name="Büromaterialien"/>
+ <account type="13" name="Restaurant"/>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Haftpflichtversicherung"/>
+ <account type="13" name="Sozialversicherung"/>
+ </account>
+ <account type="13" name="Telekommunikation">
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Online-Dienste"/>
+ </account>
+ </account>
+ <account type="16" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/common.kmt b/kmymoney2/templates/de_AT/common.kmt
new file mode 100644
index 0000000..919c158
--- /dev/null
+++ b/kmymoney2/templates/de_AT/common.kmt
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Allgemeine Konten</title>
+ <shortdesc>Grundlegende Kontenstruktur</shortdesc>
+ <longdesc>Die meisten Anwender benötigen diese grundlegende Kontenstruktur. Sie finden hier die allgemein üblichen Konten wie Giro-, Sparkonto, Bargeld, Kreditkarte, Erträge und verschiedene Ausgaben.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Barverbindlichkeiten">
+ <account type="4" name="Kreditkarte"/>
+ </account>
+ </account>
+ <account type="16" name=""/>
+ <account type="13" name="">
+ <account type="13" name="Spenden"/>
+ <account type="13" name="Körperpflege"/>
+ <account type="13" name="Lebensmittel"/>
+ <account type="13" name="Unterhaltung">
+ <account type="13" name="Reisen"/>
+ <account type="13" name="Ausgehen"/>
+ <account type="13" name="Sport"/>
+ <account type="13" name="Musik/Kino/Theater"/>
+ </account>
+ <account type="13" name="Hobbies"/>
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Netzkarten"/>
+ <account type="13" name="Fahrkarten"/>
+ </account>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Haftpflicht"/>
+ <account type="13" name="Krankenversicherung"/>
+ </account>
+ <account type="13" name="Geschenke"/>
+ <account type="13" name="Bildung">
+ <account type="13" name="Büroartikel"/>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Bücher"/>
+ <account type="13" name="Zeitungen"/>
+ </account>
+ <account type="13" name="Telekommunikation">
+ <account type="13" name="Online-Dienste"/>
+ <account type="13" name="Rundfunk"/>
+ <account type="13" name="Telefon"/>
+ </account>
+ <account type="13" name="Gesundheit">
+ <account type="13" name="Medikamente"/>
+ </account>
+ <account type="13" name="EDV"/>
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Bankgebühren"/>
+ <account type="13" name="Sonstiges"/>
+ </account>
+ <account type="13" name="Kleidung"/>
+ <account type="13" name="Steuern">
+ <account type="13" name="Sozialversicherung"/>
+ <account type="13" name="Einkommenssteuer"/>
+ <account type="13" name="Sonstige"/>
+ </account>
+ <account type="13" name="Wohnen">
+ <account type="13" name="Ausstattung"/>
+ <account type="13" name="Miete"/>
+ <account type="13" name="Nebenkosten">
+ <account type="13" name="Wasser"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Hausverwaltung"/>
+ <account type="13" name="Abfall"/>
+ <account type="13" name="Strom"/>
+ </account>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Barvermögen">
+ <account type="1" name="Sparkonto"/>
+ <account type="1" name="Girokonto"/>
+ <account type="3" name="Bargeld"/>
+ <account type="3" name="Quick"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Sonstiges"/>
+ <account type="12" name="Gehalt">
+ <account type="12" name="Zulagen"/>
+ <account type="12" name="Gehalt"/>
+ </account>
+ <account type="12" name="Glücksspiel"/>
+ <account type="12" name="Geschenke"/>
+ <account type="12" name="Zinsen">
+ <account type="12" name="Sonstige"/>
+ <account type="12" name="Girokonto"/>
+ <account type="12" name="Sparkonto"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/houseown.kmt b/kmymoney2/templates/de_AT/houseown.kmt
new file mode 100644
index 0000000..f79116d
--- /dev/null
+++ b/kmymoney2/templates/de_AT/houseown.kmt
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_houseown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hausbesitz</title>
+ <shortdesc>Konten für Hausbesitzer/innen</shortdesc>
+ <longdesc>Konten für Hausbesitzer/innen</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Wohnen">
+ <account type="13" name="Reparaturen"/>
+ <account type="13" name="Grundsteuer"/>
+ <account type="13" name="Bausparvertrag"/>
+ </account>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Hausrat"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="Bausparvertrag"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Haus"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/investment.kmt b/kmymoney2/templates/de_AT/investment.kmt
new file mode 100644
index 0000000..e3df375
--- /dev/null
+++ b/kmymoney2/templates/de_AT/investment.kmt
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_investment.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Geldanlagen</title>
+ <shortdesc>Konten für Geldanlagen</shortdesc>
+ <longdesc>Konten für Investitionen in Geldanlagen: Bausparvertrag, Lebensversicherung, Festgeld, Investmentfonds.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Lebensversicherung"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Zinsen">
+ <account type="12" name="Investmentfonds"/>
+ <account type="12" name="Bausparvertrag"/>
+ <account type="12" name="Festgeld"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Geldanlagen">
+ <account type="9" name="Festgeld"/>
+ <account type="9" name="Investmentfonds"/>
+ <account type="9" name="Bausparvertrag"/>
+ <account type="9" name="Lebensversicherung"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_AT/kids.kmt b/kmymoney2/templates/de_AT/kids.kmt
new file mode 100644
index 0000000..800bfeb
--- /dev/null
+++ b/kmymoney2/templates/de_AT/kids.kmt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_AT/acctchrt_kids.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kinder</title>
+ <shortdesc>Konten im Zusammenhang mit Kindern</shortdesc>
+ <longdesc>Kindergeld, Kindergarten</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kindergarten"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Gehalt">
+ <account type="12" name="Kindergeld"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_CH/Makefile.am b/kmymoney2/templates/de_CH/Makefile.am
new file mode 100644
index 0000000..fb2982c
--- /dev/null
+++ b/kmymoney2/templates/de_CH/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/de_CH
+
+template_DATA = otherasset.kmt kids.kmt chkmu.kmt common.kmt brokerage.kmt otherloan.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/de_CH/brokerage.kmt b/kmymoney2/templates/de_CH/brokerage.kmt
new file mode 100644
index 0000000..f7df104
--- /dev/null
+++ b/kmymoney2/templates/de_CH/brokerage.kmt
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_CH/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Aktienhandel</title>
+ <shortdesc>Konten zum Handel mit Aktien und Fonds</shortdesc>
+ <longdesc>Mit dieser Auswahl werden Konten zum Handel mit Aktien und Aktienfonds erstellt.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Komissionen"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividenden"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Geldanlagen">
+ <account type="9" name="Aktiendepot">
+ <account type="9" name="Bond"/>
+ <account type="9" name="Aktienfond"/>
+ <account type="9" name="Aktie"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_CH/chkmu.kmt b/kmymoney2/templates/de_CH/chkmu.kmt
new file mode 100644
index 0000000..50963c1
--- /dev/null
+++ b/kmymoney2/templates/de_CH/chkmu.kmt
@@ -0,0 +1,512 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_CH/acctchrt_chkmu.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMU Kontenrahmen</title>
+ <shortdesc>Kontenrahmen fuer Schweizer KMU</shortdesc>
+ <longdesc>Kontenrahmen fuer Schweizer KMU gem Walher Sterchi publiziert vom schweizerischen Gewerbeverband</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Finanzerfolg">
+ <account type="13" name="Finanzertrag">
+ <account type="13" name="Erträge aus F'anlagen bei Konzernges."/>
+ <account type="13" name="Erträge aus fl. Mitteln u. Wertschriften"/>
+ <account type="13" name="Erträge aud F'anlagen bei Aktionären"/>
+ <account type="13" name="Erträge aus Finanzanlagen"/>
+ <account type="13" name="Übriger Finanzertrag"/>
+ </account>
+ <account type="13" name="Finanzaufwand">
+ <account type="13" name="Zinsaufw. aus F'verb. ggn. Aktionären"/>
+ <account type="13" name="Zinsaufw. aus F'verb. ggn. Dritten"/>
+ <account type="13" name="Zinsaufw. aus F'verb. ggn. Konzernges."/>
+ <account type="13" name="Übriger Finanzaufwand"/>
+ <account type="13" name="Zinsaufw. F'verb. ggn. Vorsorgeeinr."/>
+ </account>
+ </account>
+ <account type="13" name="Sachvers., Abgaben, Gebühren, Bewillig.">
+ <account type="13" name="Abgaben, Gebühren, Bewilligungen">
+ <account type="13" name="Abgaben und Gebühren"/>
+ <account type="13" name="Bewilligungen und Gewerbepatente"/>
+ </account>
+ <account type="13" name="Sachversicherungen">
+ <account type="13" name="V'präm. f. Betriebsunterbrechung"/>
+ <account type="13" name="V'präm. f. Elementarsch., Glasbr., Einb."/>
+ <account type="13" name="Kreditverischerungsprämien"/>
+ <account type="13" name="V'präm. f. Betriebshaftpf. u. Garantie"/>
+ </account>
+ </account>
+ <account type="13" name="Übriger Betriebsaufwand">
+ <account type="13" name="Forschung und Entwicklung"/>
+ <account type="13" name="Wirtschaftsauskünfte, Betreibungen"/>
+ <account type="13" name="Betriebssicherheit und Bewachung"/>
+ </account>
+ <account type="13" name="Verwaltungs- und Informatikaufwand">
+ <account type="13" name="Informatik">
+ <account type="13" name="Lizenzen und Wartung"/>
+ <account type="13" name="Beratung und Entwicklung"/>
+ <account type="13" name="Leasing und Miete Hard- und Software"/>
+ </account>
+ <account type="13" name="Verwaltungsaufwand">
+ <account type="13" name="Beiträge, Spenden, Vergabungen, Trinkgelder"/>
+ <account type="13" name="Buchführungs- und Beratungsaufwand"/>
+ <account type="13" name="Telefon, Telefax, Internet, Porti"/>
+ <account type="13" name="Verwaltungsrat, GV, Revisionsstellen"/>
+ <account type="13" name="Privatanteile Verwaltungsaufwand"/>
+ <account type="13" name="Büromat., Drucksach., Fotokop., Fachlit."/>
+ </account>
+ </account>
+ <account type="13" name="Raumaufwand">
+ <account type="13" name="Nebenkosten"/>
+ <account type="13" name="Leasing Immobilien"/>
+ <account type="13" name="Fremdmieten Geschäftslokalitäten"/>
+ <account type="13" name="Reinigung"/>
+ <account type="13" name="Unterhalt Geschäftsräume"/>
+ <account type="13" name="Eigenmiete Geschäftslokalitäten"/>
+ <account type="13" name="Privatanteile Raumaufwand"/>
+ </account>
+ <account type="13" name="Fahrzeug- und Transportaufwand">
+ <account type="13" name="Fahrzeugaufwand">
+ <account type="13" name="Versicherungen"/>
+ <account type="13" name="Reparaturen, Service und Reinigung Fz"/>
+ <account type="13" name="Fahrzeugleasing, Fahrzeugmieten"/>
+ <account type="13" name="Privatanteil Fahrzeugaufwand"/>
+ <account type="13" name="Betriebsstoffe"/>
+ <account type="13" name="Verkehrsabgaben, Beiträge, Gebühren"/>
+ </account>
+ <account type="13" name="Transportaufwand">
+ <account type="13" name="Frachten, Spediteur, Cargo Domizil"/>
+ </account>
+ </account>
+ <account type="13" name="Werbeaufwand">
+ <account type="13" name="Werbeberatung, Marktanalysen"/>
+ <account type="13" name="Werbeinserate, elektronische Medien"/>
+ <account type="13" name="Werbedrucks., -mat., Reklameart., Muster"/>
+ <account type="13" name="Öffentlichkeitsarbeit / Public Relation"/>
+ <account type="13" name="Schaufen., Dekoration, Fachmes., Ausstell."/>
+ <account type="13" name="Reisespesen, Kundenbetreuung"/>
+ <account type="13" name="Werbebeiträge, Sponsoring"/>
+ </account>
+ <account type="13" name="URE / Leasingaufwand mobile Sachanlagen">
+ <account type="13" name="Unterhalt, Reparaturen, Ersatz (URE)">
+ <account type="13" name="URE von Büroeinrichtungen"/>
+ <account type="13" name="URE von Verkaufseinrichtungen"/>
+ <account type="13" name="URE von Produktionsanlagen"/>
+ <account type="13" name="URE von Personaleinrichtungen"/>
+ <account type="13" name="URE von Lagereinrichtungen"/>
+ </account>
+ <account type="13" name="Leasingaufwand mobile Sachanlagen">
+ <account type="13" name="Leasingaufwand mobile Sachanlagen"/>
+ </account>
+ </account>
+ <account type="13" name="Energie- und Entsorgungsaufwand">
+ <account type="13" name="Energieaufwand">
+ <account type="13" name="Wasser"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Brennstoffe, Heizmaterial"/>
+ <account type="13" name="Elektrizität"/>
+ </account>
+ <account type="13" name="Entsorgungsaufwand">
+ <account type="13" name="Entsorgungsaufwand"/>
+ </account>
+ </account>
+ <account type="13" name="Abschreibungen">
+ <account type="13" name="Auf Finanzanlagen"/>
+ <account type="13" name="auf aktiviertem Aufwand"/>
+ <account type="13" name="auf immateriellen Anlagen"/>
+ <account type="13" name="auf mobilen Sachanlagen"/>
+ <account type="13" name="auf immobilen Sachanlagen"/>
+ <account type="13" name="auf Beteiligungen an Konzernges."/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Personalaufwand Verwaltung">
+ <account type="13" name="Lohnaufwand Verwaltung"/>
+ <account type="13" name="Sozialversicherungsaufwand Verwaltung"/>
+ <account type="13" name="Übriger Personalaufwand Verwaltung"/>
+ <account type="13" name="Arbeitsleistung Dritter Verwaltung"/>
+ </account>
+ <account type="13" name="Personalaufwand Handel">
+ <account type="13" name="Arbeitsleistungen Dritter Handel"/>
+ <account type="13" name="Sozialversicherungsaufwand Handel"/>
+ <account type="13" name="Lohnaufwand Handel Bereich A"/>
+ <account type="13" name="Lohnaufwand Handel Bereich B"/>
+ <account type="13" name="Lohnaufwand Handel Bereich C"/>
+ <account type="13" name="Übriger Personalaufwand Handel"/>
+ </account>
+ <account type="13" name="Sozialversicherungsaufwand">
+ <account type="13" name="Quellensteuer"/>
+ <account type="13" name="AHV, IV, EO, ALV"/>
+ <account type="13" name="Berufliche Vorsorge"/>
+ <account type="13" name="Unfallversicherung"/>
+ <account type="13" name="FAK"/>
+ <account type="13" name="Krankentaggeldversicherung"/>
+ </account>
+ <account type="13" name="Personalaufwand Produktion">
+ <account type="13" name="Übriger Personalaufwand Produktion"/>
+ <account type="13" name="Lohnaufwand Produktion Bereich C"/>
+ <account type="13" name="Lohnaufwand Produktion Bereich B"/>
+ <account type="13" name="Sozialversicherungsaufwand Produktion"/>
+ <account type="13" name="Lohnaufwand Produktion Bereich A"/>
+ <account type="13" name="Arbeitsleistungen Dritter Produktion"/>
+ </account>
+ <account type="13" name="Personalaufwand Dienstleistungen">
+ <account type="13" name="Arbeitsleistungen Dritter DL"/>
+ <account type="13" name="Lohnaufwand DL Bereich A"/>
+ <account type="13" name="Lohnaufwand DL Bereich B"/>
+ <account type="13" name="Übriger Personalaufwand DL"/>
+ <account type="13" name="Sozialversicherungsaufwand DL"/>
+ <account type="13" name="Lohnaufwand DL Bereich C"/>
+ </account>
+ <account type="13" name="Arbeitsleistungen Dritter">
+ <account type="13" name="Arbeitsleistungen Dritter"/>
+ </account>
+ <account type="13" name="Übriger Personalaufwand">
+ <account type="13" name="Spesenentschädigungen pauschal"/>
+ <account type="13" name="Privatanteile Personalaufwand"/>
+ <account type="13" name="Spesenentschädigungen effektiv"/>
+ <account type="13" name="Sonstiger Personalaufwand"/>
+ <account type="13" name="Personalkantine"/>
+ <account type="13" name="Aus- und Weiterbildung"/>
+ <account type="13" name="Personalbeschaffung"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dienstleistungsertrag">
+ <account type="12" name="Dienstleistungsertrag Bereich A"/>
+ <account type="12" name="Dienstleistungsertrag Bereich B"/>
+ <account type="12" name="D'ertrag aus Leistungen an Konzerngesell."/>
+ <account type="12" name="B'änderungen angefangene und fertige DL"/>
+ <account type="12" name="Dienstleistungsertrag Bereich C"/>
+ <account type="12" name="Ertragsminderungen Dienstleistungen"/>
+ </account>
+ <account type="12" name="Produktionsertrag">
+ <account type="12" name="Ertragsminderung Produktion"/>
+ <account type="12" name="Produktionsertrag Bereich B"/>
+ <account type="12" name="Produktionsertrag Bereich C"/>
+ <account type="12" name="Produktionsertrag Bereich A"/>
+ <account type="12" name="Aus Leistungen an Konzerngesellschaften"/>
+ <account type="12" name="B'änderung angef./fert. Arb. Produktion"/>
+ </account>
+ <account type="12" name="B'änderungen angef./fert. Arb. aus P/DL">
+ <account type="12" name="B'änderungen angef./fert. Arbeiten DL"/>
+ <account type="12" name="B'änderungen angef./fertig. Arbeiten Prod."/>
+ </account>
+ <account type="12" name="Handelsertrag">
+ <account type="12" name="H'ertrag aus Leistungen an Konzerngesell."/>
+ <account type="12" name="Handelsertrag Bereich A"/>
+ <account type="12" name="Handelsertrag Bereich B"/>
+ <account type="12" name="Ertragsminderungen Handel"/>
+ <account type="12" name="Handelsertrag Bereich C"/>
+ </account>
+ <account type="12" name="Übriger Ertrag">
+ <account type="12" name="Ertragsminderung auf übrigem Ertrag"/>
+ <account type="12" name="Ertrag aus Personalausleihung"/>
+ <account type="12" name="Erträge aus Lizenzen, Patenten etc."/>
+ <account type="12" name="Nebenertrag aus Lieferung und Leistung"/>
+ <account type="12" name="Sonstiger Ertrag aus Liefer./Leistungen"/>
+ <account type="12" name="Übriger Ertrag aus Leist. an Konzernges."/>
+ </account>
+ <account type="12" name="Eigenleistungen und Eigenverbrauch">
+ <account type="12" name="Eigenverbrauch an Handelswaren"/>
+ <account type="12" name="Eigenverbrauch an Dienstleistungen"/>
+ <account type="12" name="E'verbrauch an selbstherges. Produkten"/>
+ <account type="12" name="Eigenleistungen"/>
+ </account>
+ <account type="12" name="E'minderungen aus P.-, H.- und DL-Ertr.">
+ <account type="12" name="Ertragsminderungen"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Betriebsfremde Verbindlichkeiten">
+ <account type="10" name="Betriebsfremde Verbindlichkeiten">
+ <account type="10" name="Andere langfristige Verbindlichkeiten"/>
+ <account type="10" name="Langfristige Finanzverbindlichkeiten"/>
+ <account type="10" name="Kurzfristige Finanzverbindlichkeiten"/>
+ <account type="10" name="Rückstellungen"/>
+ <account type="10" name="Andere kurzfristige Verbindlichkeiten"/>
+ <account type="10" name="Kurzfr. Verbindlichkeiten aus Leistungen"/>
+ <account type="10" name="Passive Rechnungsabgr., kurzfr. Rückstell."/>
+ </account>
+ </account>
+ <account type="10" name="Fremdkapital Langfristig">
+ <account type="10" name="Rückstellungen lanfgristig">
+ <account type="10" name="für betriebliche Umstrukturierung"/>
+ <account type="10" name="für Altersvorsorge"/>
+ <account type="10" name="für Steuern (langfristig)"/>
+ <account type="10" name="für Umweltschutzmassnahmen"/>
+ <account type="10" name="für Reparatur, Sanierung und Erneuerung"/>
+ <account type="10" name="für Forschung und Entwicklung"/>
+ <account type="10" name="aus Lieferung und Leistung (langfristig)"/>
+ <account type="10" name="Übrige Rückstellungen"/>
+ </account>
+ <account type="10" name="Andere langfristige Verbindlichkeiten">
+ <account type="10" name="Langf. Verbindl. ggn. Aktionären"/>
+ <account type="10" name="Langf. Verbindl. ggn. Konzerngesellschaft"/>
+ <account type="10" name="Langf. Verbindl. ggn Vorsorgeeinrichtung"/>
+ <account type="10" name="Langfr. Darlehensverbindl. bei Dritten"/>
+ </account>
+ <account type="10" name="Langfristige Finanzverbindlichkeiten">
+ <account type="10" name="Obligationenanleihen"/>
+ <account type="10" name="Bankverbindlichkeiten langfristig"/>
+ <account type="10" name="Leasingverbindlichkeiten"/>
+ <account type="10" name="Hypothekarverbindlichkeiten"/>
+ </account>
+ </account>
+ <account type="10" name="Eigenkapital">
+ <account type="10" name="Reserven, Bilanzgewinn">
+ <account type="10" name="Reserven"/>
+ <account type="10" name="Bilanzgewinn / Bilanzverlust"/>
+ </account>
+ <account type="10" name="Kapital / Privat">
+ <account type="10" name="Kapital"/>
+ <account type="10" name="Privat für Einzelfirmen und Personenges."/>
+ </account>
+ </account>
+ <account type="10" name="Fremdkapital kurzfristig">
+ <account type="10" name="Passive Rechnungsabgr. kurzfr. Rücktell.">
+ <account type="10" name="Passive Rechnungsabgrenzung"/>
+ <account type="10" name="Kurzfristige Rückstellungen"/>
+ </account>
+ <account type="10" name="Kurzf. Verbindlichkeiten aus Lief/Leist">
+ <account type="10" name="Verbindl. aus L/L ggn. Aktionären"/>
+ <account type="10" name="Verbindlichkeiten aus Lief/Leistungen"/>
+ <account type="10" name="Verbindl. aus L/L ggn. Konzerngesellsch."/>
+ <account type="10" name="Anzahlungen von Kunden"/>
+ </account>
+ <account type="10" name="Kurzfristige Finanzverbindlichkeiten">
+ <account type="10" name="Kurzf. Finanzverb. ggn. Aktionären"/>
+ <account type="10" name="Postscheck- und WIR-Verbindlichkeiten"/>
+ <account type="10" name="Bankverbindlichkeiten kurzfristig"/>
+ <account type="10" name="Kurzf. Finanzverg. ggn. Vorsorgestiftungen"/>
+ <account type="10" name="Kurzf. fälliger Teil v. langf. Fi'zverb."/>
+ <account type="10" name="Wechselverpflichtungen"/>
+ <account type="10" name="Sonstige kurzf. Finanzverb. ggn. Dritten"/>
+ <account type="10" name="Kurzf. Finanzverb. ggn. Konzerngesell."/>
+ </account>
+ <account type="10" name="Andere kurzfristige Verbindlichkeiten">
+ <account type="10" name="Fällige Dividenden u. Obligationenzinsen"/>
+ <account type="10" name="Verbindl. ggn. staatlichen Stellen"/>
+ <account type="10" name="Fällige Obligationenanleihen"/>
+ <account type="10" name="Andere kurzf. Verbindl. ggn. Aktionären"/>
+ <account type="10" name="Andere kurzfr. Verbindl. ggn. Dritten"/>
+ <account type="10" name="Andere kurzf. Verbindl. ggn. Konzerngesell."/>
+ <account type="10" name="Andere kurzf. Verbindl. ggn. Vorsorgeein."/>
+ </account>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Aufwand für Drittleistungen">
+ <account type="13" name="Aufwand für Drittleistungen Bereich C"/>
+ <account type="13" name="Aufwandminderungen für Drittleistu. (DL)"/>
+ <account type="13" name="Aufwand für Drittleistungen Bereich A"/>
+ <account type="13" name="Aufwand für Drittleistungen Bereich B"/>
+ <account type="13" name="Direkte Spesen für Drittleistungen"/>
+ </account>
+ <account type="13" name="Übriger Aufwand">
+ <account type="13" name="Übriger Aufwand für Drittleistungen"/>
+ <account type="13" name="Aufwand für Verpackung"/>
+ <account type="13" name="Übriger Materialaufwand Handel"/>
+ <account type="13" name="Übriger Materialaufwand Produktion"/>
+ </account>
+ <account type="13" name="Handelswarenaufwand">
+ <account type="13" name="Handelswarenaufwand Bereich C"/>
+ <account type="13" name="Einkaufspreisminderungen Handel"/>
+ <account type="13" name="B'veränderungen Warenverluste Handelswa."/>
+ <account type="13" name="Handelswarenaufwand Bereich B"/>
+ <account type="13" name="Direkte Einkaufsspesen Handel"/>
+ <account type="13" name="Handelswarenaufwand Bereich A"/>
+ </account>
+ <account type="13" name="Aufwandminderung">
+ <account type="13" name="Aufwandminderungen"/>
+ </account>
+ <account type="13" name="B'veränderungen, Mat.- u. Warenverluste">
+ <account type="13" name="Bestandesveränderungen Handelswaren"/>
+ <account type="13" name="Bestandesveränderungen Produktionsmat."/>
+ </account>
+ <account type="13" name="Energieaufwand zur Leistungserstellung">
+ <account type="13" name="Brennstoffe"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Wasser"/>
+ <account type="13" name="Elektrizität"/>
+ <account type="13" name="Betriebsstoffe"/>
+ </account>
+ <account type="13" name="Direkte Einkaufsspesen">
+ <account type="13" name="Direkte Einkaufsspesen"/>
+ </account>
+ <account type="13" name="Materialaufwand">
+ <account type="13" name="Bestandesveränderungen, Materialverluste"/>
+ <account type="13" name="Direkte Einkaufsspesen"/>
+ <account type="13" name="Fremdarbeiten"/>
+ <account type="13" name="Materialaufwand Bereich C"/>
+ <account type="13" name="Materialaufwand Bereich A"/>
+ <account type="13" name="Materialaufwand Bereich B"/>
+ <account type="13" name="Einkaufspreisminderungen Produktion"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Sammel- und Fehlbuchungen">
+ <account type="12" name="Fehlbuchungen"/>
+ <account type="12" name="Sammelbuchungen"/>
+ </account>
+ <account type="12" name="Erfolgsrechnung">
+ <account type="12" name="Erfolgsrechnung"/>
+ </account>
+ <account type="12" name="Bilanz">
+ <account type="12" name="Bilanz"/>
+ </account>
+ <account type="12" name="Gewinnverwendung">
+ <account type="12" name="Hilfskonten Gewinnverwendung"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Betriebsfremder Erfolg">
+ <account type="12" name="Sonstiger betriebsfremder Erfolg">
+ <account type="12" name="Sonstiger betriebsfremder Aufwand"/>
+ <account type="12" name="Sonstiger betriebsfremder Ertrag"/>
+ </account>
+ <account type="12" name="Minderheitsanteile am Ergebnis"/>
+ <account type="12" name="Erfolg betriebsfremde Finanzanlagen">
+ <account type="12" name="Ertrag betriebsfremde Finanzanlagen"/>
+ <account type="12" name="Aufwand betriebsfremde Finanzanlagen"/>
+ </account>
+ <account type="12" name="Erfolg betriebsfremder Unternehmensteil">
+ <account type="12" name="Erfolg betriebsfr. Unternehmensteil 2"/>
+ <account type="12" name="Erfolg betriebsfr. Unternehmensteil 1"/>
+ </account>
+ <account type="12" name="Erfolg betriebsfremde Liegenschaften">
+ <account type="12" name="Erfolg betriebsfremde Liegenschaft 1"/>
+ <account type="12" name="Erfolg betriebsfremde Liegenschaft 2"/>
+ </account>
+ </account>
+ <account type="12" name="Steuern"/>
+ <account type="12" name="Ausserordentlicher Erfolg">
+ <account type="12" name="Ausserordentlicher Ertrag"/>
+ <account type="12" name="Ausserordentlicher Aufwand"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Erfolg aus Nebenbetrieben">
+ <account type="12" name="Erfolg aus Nebenbetrieben">
+ <account type="12" name="Erfolg aus Nebenbetrieb 1"/>
+ <account type="12" name="Erfolg aus Nebenbetrieb 2"/>
+ </account>
+ </account>
+ <account type="12" name="Erfolg aus Finanzanlagen">
+ <account type="12" name="Aufwand aus Finanzanlagen"/>
+ <account type="12" name="Ertrag aus Finanzalnlagen"/>
+ </account>
+ <account type="12" name="Gew. aus Veräusserung v. betr. Anlagever.">
+ <account type="12" name="Gewinne aus Finanzanlagen"/>
+ <account type="12" name="Gewinne aus immobilen Sachanlagen"/>
+ <account type="12" name="Gewinne aus immateriellen Anlagen"/>
+ <account type="12" name="Gewinne aus mobilen Sachanlagen"/>
+ </account>
+ <account type="12" name="Erfolg betriebliche Liegenschaften">
+ <account type="12" name="Erfolg betriebliche Liegenschaft 2">
+ <account type="12" name="Etrag betriebliche Liegenschaft 2"/>
+ <account type="12" name="Aufwand betriebliche Liegenschaft 2 "/>
+ </account>
+ <account type="12" name="Erfolg betriebliche Liegenschaft 1">
+ <account type="12" name="Ertrag betriebliche Liegenschaft 1"/>
+ <account type="12" name="Aufwand betriebliche Liegenschaft 1"/>
+ </account>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Umlaufvermögen">
+ <account type="9" name="Flüssige Mittel und Wertschriften">
+ <account type="9" name="Checks, Besitzwechsel (diskontfähig)"/>
+ <account type="9" name="Andere kurzfristige Anlagen"/>
+ <account type="9" name="Transferkonto"/>
+ <account type="3" name="Kasse"/>
+ <account type="1" name="Bankguthaben"/>
+ <account type="1" name="Postcheckguthaben"/>
+ <account type="9" name="Wertschriften kurzfristig realisierbar"/>
+ <account type="9" name="Eigene Aktien"/>
+ <account type="9" name="Kurzfristige Geldanlagen"/>
+ </account>
+ <account type="9" name="Forderungen"/>
+ <account type="9" name="Aktive Rechnungsabgrenzung">
+ <account type="9" name="Aktive Rechnungsabgr. (Transitorische A)"/>
+ </account>
+ <account type="9" name="Vorräte und angefangene Arbeiten">
+ <account type="9" name="Halbfabrikate"/>
+ <account type="9" name="Vorräte Werkstoffe"/>
+ <account type="9" name="Pflichtlager"/>
+ <account type="9" name="Vorräte Handelswaren"/>
+ <account type="9" name="Waren in Konsignation"/>
+ <account type="9" name="Fertigfabrikate"/>
+ <account type="9" name="Angefangene Arbeiten"/>
+ <account type="9" name="Vorräte Rohstoffe"/>
+ <account type="9" name="Vorräte Hilfs- und Verbrauchsmaterial"/>
+ </account>
+ </account>
+ <account type="9" name="Betriebsfremde Aktiven">
+ <account type="9" name="Betriebsfremde Aktiven">
+ <account type="9" name="Finanzanlagen"/>
+ <account type="9" name="Vorräte und angefangene Arbeiten"/>
+ <account type="9" name="frei Bilanzverlust unter 299"/>
+ <account type="9" name="Mobile Sachanlagen"/>
+ <account type="9" name="Immobile Sachanlagen"/>
+ <account type="9" name="Flüssige Mittel und Wertschriften"/>
+ <account type="9" name="Aktivierter Aufwand"/>
+ <account type="9" name="Kurzfristige Forderungen"/>
+ <account type="9" name="Immaterielle Anlagen"/>
+ <account type="9" name="Aktive Rechnungsabgrenzung"/>
+ </account>
+ </account>
+ <account type="9" name="Anlagevermögen">
+ <account type="9" name="Finanzanlagen">
+ <account type="9" name="Eigene Aktien"/>
+ <account type="9" name="Langf. F'gen ggn. Konzernges."/>
+ <account type="9" name="Langfristige Forderungen ggn. Dritten"/>
+ <account type="9" name="Andere Finanzanlagen"/>
+ <account type="9" name="Wertpapiere des Anlagevermögens"/>
+ <account type="9" name="Langf. F'gen ggn. Aktionären"/>
+ <account type="9" name="Beteiligungen"/>
+ </account>
+ <account type="9" name="Immaterielle Anlagen">
+ <account type="9" name="Patente, Know-How, Rezepte"/>
+ <account type="9" name="Marken, Muster, Modelle, Pläne"/>
+ <account type="9" name="Goodwill"/>
+ <account type="9" name="Lizenzen, Konzessionen, Nutzungsrechte"/>
+ <account type="9" name="Übrige immaterielle Anlagen"/>
+ <account type="9" name="Urheber-, Verlags-, Vertragsrechte"/>
+ </account>
+ <account type="9" name="Immobile Sachanlagen">
+ <account type="9" name="Fabrikgebäude"/>
+ <account type="9" name="Lagergebäude"/>
+ <account type="9" name="Werkstattgebäude, Atelier"/>
+ <account type="9" name="Ausstellungs- und Verkaufsgebäude"/>
+ <account type="9" name="Unbebaute Grundstücke"/>
+ <account type="9" name="Büro- und Verwaltungsgebäude"/>
+ <account type="9" name="Geschäftsliegenschaften"/>
+ <account type="9" name="Wohnhäuser"/>
+ </account>
+ <account type="9" name="Mobile Sachanlagen">
+ <account type="9" name="Maschinen und Apparate Produktion"/>
+ <account type="9" name="Lagereinrichtungen"/>
+ <account type="9" name="Übrige mobile Sachanlagen"/>
+ <account type="9" name="Büromaschinen, EDV-Anlage, Kommunikation"/>
+ <account type="9" name="Feste Einrichtungen und Installationen"/>
+ <account type="9" name="Mobiliar Einrichtungen"/>
+ <account type="9" name="Werkzeuge und Geräte"/>
+ <account type="9" name="Fahrzeuge"/>
+ </account>
+ </account>
+ <account type="9" name="Aktivierter Aufw. &amp; akt. Berichtigung">
+ <account type="9" name="Aktivierter Aufwand &amp; akt. Berichtigung">
+ <account type="9" name="Gründungs-, Kapitalerh'gs- &amp; Org.Aufwand"/>
+ <account type="9" name="Aktive Berichtigungsposten"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_CH/common.kmt b/kmymoney2/templates/de_CH/common.kmt
new file mode 100644
index 0000000..3f043ca
--- /dev/null
+++ b/kmymoney2/templates/de_CH/common.kmt
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_CH/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Allgemeine Konten</title>
+ <shortdesc>Grundlegende Kontenstruktur</shortdesc>
+ <longdesc>Die meisten Anwender benötigen diese grundlegende Kontenstruktur. Sie finden hier die allgemein üblichen Konten wie Giro-, Sparkonto, Bargeld, Kreditkarte, Erträge und verschiedene Ausgaben.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Barverbindlichkeiten">
+ <account type="4" name="Kreditkarte"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Barvermögen">
+ <account type="1" name="Girokonto"/>
+ <account type="1" name="Sparkonto"/>
+ <account type="3" name="Bargeld"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Telekommunikation">
+ <account type="13" name="Online-Dienste"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Fernsehen"/>
+ </account>
+ <account type="13" name="Lebensmittel"/>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Krankenversicherung"/>
+ <account type="13" name="Haftpflicht"/>
+ </account>
+ <account type="13" name="Hobbies"/>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Geschenke"/>
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Fahrkarten"/>
+ </account>
+ <account type="13" name="Wohnen">
+ <account type="13" name="Miete"/>
+ <account type="13" name="Nebenkosten">
+ <account type="13" name="Strom"/>
+ <account type="13" name="Abfall"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Wasser"/>
+ </account>
+ </account>
+ <account type="13" name="Steuern">
+ <account type="13" name="Sozialabgaben"/>
+ <account type="13" name="Solidarzuschlag"/>
+ <account type="13" name="Pflegeversicherung"/>
+ <account type="13" name="Einkommenssteuer"/>
+ <account type="13" name="Rentenversicherung"/>
+ <account type="13" name="Sonstige"/>
+ </account>
+ <account type="13" name="Medikamente"/>
+ <account type="13" name="Kleidung"/>
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Bankgebühren"/>
+ <account type="13" name="Sonstiges"/>
+ </account>
+ <account type="13" name="Bildung">
+ <account type="13" name="Büroartikel"/>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Zeitungen"/>
+ <account type="13" name="Bücher"/>
+ </account>
+ <account type="13" name="Spenden"/>
+ <account type="13" name="Unterhaltung">
+ <account type="13" name="Musik/Kino"/>
+ <account type="13" name="Reisen"/>
+ <account type="13" name="Ausgehen"/>
+ <account type="13" name="Sport"/>
+ </account>
+ </account>
+ <account type="16" name=""/>
+ <account type="12" name="">
+ <account type="12" name="Gehalt">
+ <account type="12" name="Zulagen"/>
+ <account type="12" name="Gehalt"/>
+ </account>
+ <account type="12" name="Sonstiges"/>
+ <account type="12" name="Zinsen">
+ <account type="12" name="Girokonto"/>
+ <account type="12" name="Sparkonto"/>
+ <account type="12" name="Sonstige"/>
+ </account>
+ <account type="12" name="Geschenke"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_CH/kids.kmt b/kmymoney2/templates/de_CH/kids.kmt
new file mode 100644
index 0000000..e904479
--- /dev/null
+++ b/kmymoney2/templates/de_CH/kids.kmt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_CH/acctchrt_kids.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kinder</title>
+ <shortdesc>Konten im Zusammenhang mit Kindern</shortdesc>
+ <longdesc>Kindergeld, Kindergarten</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kindergarten"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Gehalt">
+ <account type="12" name="Kindergeld"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_CH/otherasset.kmt b/kmymoney2/templates/de_CH/otherasset.kmt
new file mode 100644
index 0000000..56669ab
--- /dev/null
+++ b/kmymoney2/templates/de_CH/otherasset.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_CH/acctchrt_otherasset.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Sonstige Sachanlage</title>
+ <shortdesc>Sonstige Sachanlagen</shortdesc>
+ <longdesc>Sonstige Sachanlagen</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Sonstige"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_CH/otherloan.kmt b/kmymoney2/templates/de_CH/otherloan.kmt
new file mode 100644
index 0000000..d2ca698
--- /dev/null
+++ b/kmymoney2/templates/de_CH/otherloan.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_CH/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Sonstiger Kredit</title>
+ <shortdesc>Sonstige Kredite</shortdesc>
+ <longdesc>Weitere Kredite</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="Sonstige"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/Makefile.am b/kmymoney2/templates/de_DE/Makefile.am
new file mode 100644
index 0000000..f2dbe98
--- /dev/null
+++ b/kmymoney2/templates/de_DE/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/de_DE
+
+template_DATA = houseown.kmt otherasset.kmt kids.kmt full.kmt default_accounts.kmt investment.kmt autoloan.kmt studium.kmt common.kmt brokerage.kmt skr04.kmt otherloan.kmt auto.kmt skr03.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/de_DE/auto.kmt b/kmymoney2/templates/de_DE/auto.kmt
new file mode 100644
index 0000000..a7f6368
--- /dev/null
+++ b/kmymoney2/templates/de_DE/auto.kmt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_auto.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Autobesitz</title>
+ <shortdesc>Ausgaben von Autobesitzern</shortdesc>
+ <longdesc>Diese Auswahl erstellt Konten, die Ausgaben für ein Auto repräsentieren.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Auto">
+ <account type="13" name="Versicherungen"/>
+ <account type="13" name="Abgaben"/>
+ <account type="13" name="Benzin"/>
+ <account type="13" name="Reparaturen"/>
+ <account type="13" name="Parkgebühren"/>
+ </account>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Auto"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/autoloan.kmt b/kmymoney2/templates/de_DE/autoloan.kmt
new file mode 100644
index 0000000..930eb71
--- /dev/null
+++ b/kmymoney2/templates/de_DE/autoloan.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_autoloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kredit Auto</title>
+ <shortdesc>Kredit für Autokauf</shortdesc>
+ <longdesc>Falls Sie einen Kredit zum Autokauf besitzen, können Sie mit dieser Auswahl die passenden Konten bekommen.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Auto">
+ <account type="13" name="Kreditzinsen"/>
+ </account>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="Auto"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/brokerage.kmt b/kmymoney2/templates/de_DE/brokerage.kmt
new file mode 100644
index 0000000..2f2bc99
--- /dev/null
+++ b/kmymoney2/templates/de_DE/brokerage.kmt
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Aktienhandel</title>
+ <shortdesc>Konten zum Handel mit Aktien und Fonds</shortdesc>
+ <longdesc>Mit dieser Auswahl werden Konten zum Handel mit Aktien und Aktienfonds erstellt.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Komissionen"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividenden"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Geldanlagen">
+ <account type="9" name="Aktiendepot">
+ <account type="9" name="Bond"/>
+ <account type="9" name="Aktienfond"/>
+ <account type="9" name="Aktie"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/common.kmt b/kmymoney2/templates/de_DE/common.kmt
new file mode 100644
index 0000000..be9424d
--- /dev/null
+++ b/kmymoney2/templates/de_DE/common.kmt
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Allgemeine Konten</title>
+ <shortdesc>Grundlegende Kontenstruktur</shortdesc>
+ <longdesc>Die meisten Anwender benötigen diese grundlegende Kontenstruktur. Sie finden hier die allgemein üblichen Konten wie Giro-, Sparkonto, Bargeld, Kreditkarte, Erträge und verschiedene Ausgaben. Wenn Sie aber einen SKR verwenden wollen, brauchen Sie sie nicht.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Barverbindlichkeiten">
+ <account type="4" name="Kreditkarte"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Barvermögen">
+ <account type="1" name="Girokonto"/>
+ <account type="1" name="Sparkonto"/>
+ <account type="3" name="Bargeld"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Telekommunikation">
+ <account type="13" name="Online-Dienste"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Fernsehen"/>
+ </account>
+ <account type="13" name="Lebensmittel"/>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Krankenversicherung"/>
+ <account type="13" name="Haftpflicht"/>
+ </account>
+ <account type="13" name="Hobbies"/>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Geschenke"/>
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Fahrkarten"/>
+ </account>
+ <account type="13" name="Wohnen">
+ <account type="13" name="Miete"/>
+ <account type="13" name="Nebenkosten">
+ <account type="13" name="Strom"/>
+ <account type="13" name="Abfall"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Wasser"/>
+ </account>
+ </account>
+ <account type="13" name="Steuern">
+ <account type="13" name="Sozialabgaben"/>
+ <account type="13" name="Solidarzuschlag"/>
+ <account type="13" name="Pflegeversicherung"/>
+ <account type="13" name="Einkommenssteuer"/>
+ <account type="13" name="Rentenversicherung"/>
+ <account type="13" name="Sonstige"/>
+ </account>
+ <account type="13" name="Medikamente"/>
+ <account type="13" name="Kleidung"/>
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Bankgebühren"/>
+ <account type="13" name="Sonstiges"/>
+ </account>
+ <account type="13" name="Spenden"/>
+ <account type="13" name="Unterhaltung">
+ <account type="13" name="Musik/Kino"/>
+ <account type="13" name="Reisen"/>
+ <account type="13" name="Ausgehen"/>
+ <account type="13" name="Sport"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Büroartikel"/>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Zeitungen"/>
+ <account type="13" name="Bücher"/>
+ </account>
+ <account type="16" name=""/>
+ <account type="12" name="">
+ <account type="12" name="Gehalt">
+ <account type="12" name="Zulagen"/>
+ <account type="12" name="Gehalt"/>
+ </account>
+ <account type="12" name="Sonstiges"/>
+ <account type="12" name="Zinsen">
+ <account type="12" name="Girokonto"/>
+ <account type="12" name="Sparkonto"/>
+ <account type="12" name="Sonstige"/>
+ </account>
+ <account type="12" name="Geschenke"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/default_accounts.kmt b/kmymoney2/templates/de_DE/default_accounts.kmt
new file mode 100644
index 0000000..7add875
--- /dev/null
+++ b/kmymoney2/templates/de_DE/default_accounts.kmt
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 Standardvorlage</title>
+ <shortdesc></shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account name="" type="12">
+ <account name="Eigenverbrauch" type="12">
+ <account name="Eigenverbrauch 16%" type="12"/>
+ <account name="Eigenverbrauch 7%" type="12"/>
+ <account name="Eigenverbrauch steuerfrei" type="12"/>
+ </account>
+ <account name="Einkünfte aus Kapitalanlagen" type="12">
+ <account name="Dividenden" type="12"/>
+ <account name="Kapitalgewinne" type="12"/>
+ <account name="Zinsen" type="12"/>
+ <account name="Zinsen (steuerfrei)" type="12"/>
+ </account>
+ <account name="Lohn und Gehalt" type="12">
+ <account name="Arbeitgeberanteil" type="12"/>
+ <account name="Bonus" type="12"/>
+ <account name="Bruttovergütung" type="12"/>
+ <account name="Dienstwagen" type="12"/>
+ <account name="Direktversicherung" type="12"/>
+ <account name="Geldwerte Vorteile" type="12"/>
+ <account name="Kindergeld" type="12"/>
+ <account name="Nettovergütung" type="12"/>
+ <account name="Provision" type="12"/>
+ <account name="Steuerfreie Einkünfte" type="12"/>
+ <account name="Überstundenvergütung" type="12"/>
+ <account name="Vermögenswirksame Leistungen" type="12"/>
+ </account>
+ <account name="Renten" type="12">
+ <account name="Betriebsrente" type="12"/>
+ <account name="Gesetzliche Rente" type="12"/>
+ <account name="Private Altersvorsorge" type="12"/>
+ </account>
+ <account name="Sonstige Einkünfte" type="12">
+ <account name="Aktienoptionsrecht" type="12"/>
+ <account name="Arbeitslosengeld" type="12"/>
+ <account name="Erhaltene Geschenke" type="12"/>
+ <account name="Erhaltene Tilgungszahlungen" type="12"/>
+ <account name="Lottogewinne" type="12"/>
+ <account name="Steuererstattung" type="12"/>
+ <account name="Unterhalt für Kinder" type="12"/>
+ </account>
+ <account name="Umsatzerlöse" type="12">
+ <account name="Erlöse 0%" type="12"/>
+ <account name="Erlöse 16%" type="12"/>
+ <account name="Erlöse 7%" type="12"/>
+ <account name="Erlöse aus Anlagenverkäufen 16%" type="12"/>
+ <account name="Provisionserlöse" type="12"/>
+ </account>
+ <account name="Umsatzsteuer" type="12">
+ <account name="Vorjahr" type="12"/>
+ <account name="Vorauszahlung" type="12"/>
+ </account>
+ <account name="Zinsertrag" type="12">
+ <account name="Sonstige Zinsen und ähnliche Erträge" type="12"/>
+ </account>
+ </account>
+ <account name="" type="13">
+ <account name="Abschreibungen" type="13">
+ <account name="Abschr. auf geringwertige Güter" type="13"/>
+ <account name="Abschr. auf Sachanlagen" type="13"/>
+ </account>
+ <account name="Anlagenabgänge" type="13">
+ <account name="Anlagenabgänge bei Buchgewinn" type="13"/>
+ <account name="Anlagenabgänge bei Buchverlust" type="13"/>
+ </account>
+ <account name="Anlagevermögen" type="13">
+ <account name="Andere Anlagen" type="13"/>
+ <account name="Betriebsausstattung" type="13"/>
+ <account name="Büroeinrichtung" type="13"/>
+ <account name="EDV-Software" type="13"/>
+ <account name="Geringwertige Wirtschaftsgüter" type="13"/>
+ <account name="Geschäftsausstattung" type="13"/>
+ <account name="Geschäftsbauten" type="13"/>
+ <account name="Maschinen" type="13"/>
+ <account name="Pkw" type="13"/>
+ <account name="Sonst. Betr.- u. Gesch.-Ausstat." type="13"/>
+ <account name="Technische Anlagen und Maschinen" type="13"/>
+ <account name="Werkzeuge" type="13"/>
+ </account>
+ <account name="Ausbildung" type="13">
+ <account name="Fachbücher" type="13"/>
+ <account name="Nachhilfe" type="13"/>
+ <account name="Schulgeld" type="13"/>
+ </account>
+ <account name="Auto" type="13">
+ <account name="Kraftstoff" type="13"/>
+ <account name="Wartung" type="13"/>
+ </account>
+ <account name="Bankgebühren" type="13">
+ <account name="Kontoführungsgebühren" type="13"/>
+ <account name="Sollzinsen" type="13"/>
+ </account>
+ <account name="Barentnahme" type="13"/>
+ <account name="Beiträge und Vers." type="13">
+ <account name="Beiträge" type="13"/>
+ <account name="Sonstige Abgaben" type="13"/>
+ <account name="Versicherungen" type="13"/>
+ </account>
+ <account name="Bürobedarf" type="13">
+ <account name="Porto" type="13"/>
+ <account name="Telefax" type="13"/>
+ <account name="Telefon" type="13"/>
+ <account name="Internet" type="13"/>
+ </account>
+ <account name="Essen" type="13">
+ <account name="Lebensmittel" type="13"/>
+ <account name="Restaurants" type="13"/>
+ </account>
+ <account name="Freizeit" type="13">
+ <account name="Bücher/Zeitschriften" type="13"/>
+ <account name="Film-/Videoverleihgebühren" type="13"/>
+ <account name="Gästebewirtung" type="13"/>
+ <account name="Kassetten/CDs/DVDs" type="13"/>
+ <account name="Spielzeug/Spiele" type="13"/>
+ <account name="Sportartikel" type="13"/>
+ <account name="Sportveranstaltungen" type="13"/>
+ <account name="Theater/Oper" type="13"/>
+ </account>
+ <account name="Geldwerte Vorteile" type="13">
+ <account name="Dienstwagen" type="13"/>
+ <account name="Sonstige" type="13"/>
+ </account>
+ <account name="Geschenke" type="13"/>
+ <account name="Gesundheit" type="13">
+ <account name="Arzneimittel" type="13"/>
+ <account name="Krankengymnastik" type="13"/>
+ <account name="Krankenhaus" type="13"/>
+ <account name="Sehhilfe" type="13"/>
+ <account name="Zahnbehandlung/Zahnersatz" type="13"/>
+ </account>
+ <account name="Haushalt" type="13">
+ <account name="Einrichtung" type="13"/>
+ </account>
+ <account name="Haustiere" type="13">
+ <account name="Futter" type="13"/>
+ <account name="Sonstiges" type="13"/>
+ <account name="Tierarzt" type="13"/>
+ </account>
+ <account name="Kfz-Kosten" type="13">
+ <account name="Fremdfahrzeuge" type="13"/>
+ <account name="Garagenmiete" type="13"/>
+ <account name="Kfz-Steuern" type="13"/>
+ <account name="Kfz-Versicherungen" type="13"/>
+ <account name="Lfd. Kfz-Betriebskosten" type="13"/>
+ <account name="Sonstige Kfz-Kosten" type="13"/>
+ </account>
+ <account name="Kinderbetreuung" type="13"/>
+ <account name="Kleidung" type="13"/>
+ <account name="Körperpflege" type="13"/>
+ <account name="Kredit" type="13">
+ <account name="Kreditzinsen" type="13"/>
+ </account>
+ <account name="Personalkosten" type="13">
+ <account name="Aushilfslöhne" type="13"/>
+ <account name="Beiträge Berufsgenossenschaft" type="13"/>
+ <account name="Gehälter" type="13"/>
+ <account name="Gesetzliche soz. Aufwendungen" type="13"/>
+ <account name="Löhne" type="13"/>
+ <account name="Lohnsteuer Aushilfen" type="13"/>
+ <account name="Vermögenswirksame Leistungen" type="13"/>
+ </account>
+ <account name="Raumkosten" type="13">
+ <account name="Gas, Strom, Wasser" type="13"/>
+ <account name="Heizung" type="13"/>
+ <account name="Instandhaltung betr. Räume" type="13"/>
+ <account name="Miete" type="13"/>
+ <account name="Reinigung" type="13"/>
+ <account name="Sonstige Raumkosten" type="13"/>
+ </account>
+ <account name="Rechts- und Beratungskosten" type="13">
+ <account name="Abschluss- und Prüfungskosten" type="13"/>
+ </account>
+ <account name="Reisekosten" type="13">
+ <account name="km-Geld-Erstattung 8,7%" type="13"/>
+ <account name="Reisekosten 0%" type="13"/>
+ <account name="Reisekosten Arbeitnehmer 10,5%" type="13"/>
+ <account name="Reisekosten Arbeitnehmer 13,1%" type="13"/>
+ <account name="Reisekosten Unternehmer 6,1%" type="13"/>
+ </account>
+ <account name="Repräsentationskosten" type="13">
+ <account name="Bewirtungskosten" type="13"/>
+ <account name="Geschenke bis xx Euro" type="13"/>
+ <account name="Werbekosten" type="13"/>
+ </account>
+ <account name="Sonstige Kosten" type="13">
+ <account name="Ausgangsfrachten" type="13"/>
+ <account name="Betriebsbedarf" type="13"/>
+ <account name="Fremdarbeiten" type="13"/>
+ <account name="Kaufleasing" type="13"/>
+ <account name="Kosten des Geldverkehrs" type="13"/>
+ <account name="Mieten für Einrichtungen" type="13"/>
+ <account name="Mietleasing" type="13"/>
+ <account name="Reparatur und Instandhaltung" type="13"/>
+ <account name="Sonstige betriebl. Aufwendungen" type="13"/>
+ <account name="Sonstige Betriebssteuern" type="13"/>
+ <account name="Transportversicherungen" type="13"/>
+ <account name="Verkaufsprovisionen" type="13"/>
+ <account name="Verpackungsmaterial" type="13"/>
+ <account name="Werkzeug und Kleingeräte" type="13"/>
+ <account name="Zeitschriften/Bücher" type="13"/>
+ </account>
+ <account name="Sozialversicherung" type="13">
+ <account name="Arbeitslosenversicherung" type="13"/>
+ <account name="Krankenversicherung" type="13"/>
+ <account name="Pflegeversicherung" type="13"/>
+ <account name="Rentenversicherung" type="13"/>
+ </account>
+ <account name="Spenden" type="13"/>
+ <account name="Steuern" type="13">
+ <account name="Erbschaftsteuer" type="13"/>
+ <account name="Gewerbesteuer" type="13"/>
+ <account name="Grundsteuern" type="13"/>
+ <account name="Kapitalertragssteuer" type="13"/>
+ <account name="Kirchensteuer" type="13"/>
+ <account name="Lohn-/Einkommensteuer" type="13"/>
+ <account name="Solidaritätszuschlag" type="13"/>
+ <account name="Sonstige Steuern" type="13"/>
+ </account>
+ <account name="Umsatzsteuer" type="13">
+ <account name="Vorjahr" type="13"/>
+ <account name="Vorauszahlung" type="13"/>
+ </account>
+ <account name="Urlaub" type="13">
+ <account name="An- und Abreise" type="13"/>
+ <account name="Unterkunft" type="13"/>
+ </account>
+ <account name="Verschiedenes" type="13"/>
+ <account name="Versicherung" type="13">
+ <account name="Kraftfahrzeug" type="13"/>
+ <account name="Hausrat" type="13"/>
+ <account name="Krankenversicherung" type="13"/>
+ <account name="Lebensversicherung" type="13"/>
+ </account>
+ <account name="Wareneinsatz" type="13">
+ <account name="Wareneingang 16%" type="13"/>
+ <account name="Wareneingang 7%" type="13"/>
+ </account>
+ <account name="Werbungskosten" type="13">
+ <account name="Fachliteratur" type="13"/>
+ <account name="Fahrten ÖPNV" type="13"/>
+ </account>
+ <account name="Zahlungen" type="13">
+ <account name="Gas" type="13"/>
+ <account name="Haus- und Grundbesitzabgaben" type="13"/>
+ <account name="Hypothekenzinsen" type="13"/>
+ <account name="Kabelfernsehen" type="13"/>
+ <account name="Fernseh- und Rundfunkgebühren (GEZ)" type="13"/>
+ <account name="Miete" type="13"/>
+ <account name="Müllgebühren" type="13"/>
+ <account name="Strom" type="13"/>
+ <account name="Telefon" type="13"/>
+ <account name="Wasser/Abwasser" type="13"/>
+ </account>
+ <account name="Zinsaufwand" type="13"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/full.kmt b/kmymoney2/templates/de_DE/full.kmt
new file mode 100644
index 0000000..96cc9d7
--- /dev/null
+++ b/kmymoney2/templates/de_DE/full.kmt
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_full.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Alle Konten</title>
+ <shortdesc>Alle vorgeschlagenen Konten</shortdesc>
+ <longdesc>Dies ist die komplette Liste aller vorgeschlagenen Konten.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Barverbindlichkeiten">
+ <account type="4" name="Kreditkarte"/>
+ </account>
+ <account type="10" name="Kredite">
+ <account type="10" name="Sonstige"/>
+ <account type="10" name="Auto"/>
+ <account type="10" name="Bausparvertrag"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Geldanlagen">
+ <account type="9" name="Währungskonto"/>
+ <account type="9" name="Lebensversicherung"/>
+ <account type="9" name="Bausparvertrag"/>
+ <account type="9" name="Aktiendepot">
+ <account type="9" name="Bond"/>
+ <account type="9" name="Aktienfond"/>
+ <account type="9" name="Aktie"/>
+ </account>
+ <account type="9" name="Festgeld"/>
+ <account type="9" name="Investmentfonds"/>
+ </account>
+ <account type="9" name="Barvermögen">
+ <account type="1" name="Girokonto"/>
+ <account type="1" name="Sparkonto"/>
+ <account type="3" name="Bargeld"/>
+ </account>
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Sonstige"/>
+ <account type="9" name="Auto"/>
+ <account type="9" name="Haus"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Telekommunikation">
+ <account type="13" name="Online-Dienste"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Fernsehen"/>
+ </account>
+ <account type="13" name="Lebensmittel"/>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Lebensversicherung"/>
+ <account type="13" name="Hausrat"/>
+ <account type="13" name="Krankenversicherung"/>
+ <account type="13" name="Haftpflicht"/>
+ </account>
+ <account type="13" name="Hobbies"/>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Geschenke"/>
+ <account type="13" name="Fahrtkosten">
+ <account type="13" name="Auto">
+ <account type="13" name="Versicherungen"/>
+ <account type="13" name="Kreditzinsen"/>
+ <account type="13" name="Reparaturen"/>
+ <account type="13" name="Abgaben"/>
+ <account type="13" name="Benzin"/>
+ <account type="13" name="Parkgebühren"/>
+ </account>
+ <account type="13" name="Fahrkarten"/>
+ </account>
+ <account type="13" name="Kindergarten"/>
+ <account type="13" name="Wohnen">
+ <account type="13" name="Reparaturen"/>
+ <account type="13" name="Miete"/>
+ <account type="13" name="Grundsteuer"/>
+ <account type="13" name="Nebenkosten">
+ <account type="13" name="Strom"/>
+ <account type="13" name="Abfall"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Wasser"/>
+ </account>
+ <account type="13" name="Bausparvertrag"/>
+ </account>
+ <account type="13" name="Steuern">
+ <account type="13" name="Sozialabgaben"/>
+ <account type="13" name="Zinsabschlagsteuer"/>
+ <account type="13" name="Solidarzuschlag"/>
+ <account type="13" name="Pflegeversicherung"/>
+ <account type="13" name="Einkommenssteuer"/>
+ <account type="13" name="Rentenversicherung"/>
+ <account type="13" name="Sonstige"/>
+ </account>
+ <account type="13" name="Medikamente"/>
+ <account type="13" name="Kleidung"/>
+ <account type="13" name="Sonstiges">
+ <account type="13" name="Bankgebühren"/>
+ <account type="13" name="Komissionen"/>
+ <account type="13" name="Sonstiges Bar"/>
+ </account>
+ <account type="13" name="Bildung">
+ <account type="13" name="Büroartikel"/>
+ <account type="13" name="Studiengebühren"/>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Zeitungen"/>
+ <account type="13" name="Bücher"/>
+ </account>
+ <account type="13" name="Spenden"/>
+ <account type="13" name="Unterhaltung">
+ <account type="13" name="Musik/Kino"/>
+ <account type="13" name="Reisen"/>
+ <account type="13" name="Ausgehen"/>
+ <account type="13" name="Sport"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Anfangsbestand"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividenden"/>
+ <account type="12" name="BAFöG"/>
+ <account type="12" name="Gehalt">
+ <account type="12" name="Kindergeld"/>
+ <account type="12" name="Zulagen"/>
+ <account type="12" name="Gehalt"/>
+ </account>
+ <account type="12" name="Sonstiges"/>
+ <account type="12" name="Zinsen">
+ <account type="12" name="Girokonto"/>
+ <account type="12" name="Bausparvertrag"/>
+ <account type="12" name="Sparkonto"/>
+ <account type="12" name="Festgeld"/>
+ <account type="12" name="Investmentfonds"/>
+ <account type="12" name="Sonstige"/>
+ </account>
+ <account type="12" name="Geschenke"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/houseown.kmt b/kmymoney2/templates/de_DE/houseown.kmt
new file mode 100644
index 0000000..783a0fc
--- /dev/null
+++ b/kmymoney2/templates/de_DE/houseown.kmt
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_houseown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hausbesitz</title>
+ <shortdesc>Konten für Hausbesitzer/innen</shortdesc>
+ <longdesc>Konten für Hausbesitzer/innen</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Wohnen">
+ <account type="13" name="Reparaturen"/>
+ <account type="13" name="Grundsteuer"/>
+ <account type="13" name="Bausparvertrag"/>
+ </account>
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Hausrat"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="Bausparvertrag"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Haus"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/investment.kmt b/kmymoney2/templates/de_DE/investment.kmt
new file mode 100644
index 0000000..1798bbd
--- /dev/null
+++ b/kmymoney2/templates/de_DE/investment.kmt
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_investment.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Geldanlagen</title>
+ <shortdesc>Konten für Geldanlagen</shortdesc>
+ <longdesc>Konten für Investitionen in Geldanlagen: Bausparvertrag, Lebensversicherung, Festgeld, Investmentfonds.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Versicherungen">
+ <account type="13" name="Lebensversicherung"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Zinsen">
+ <account type="12" name="Investmentfonds"/>
+ <account type="12" name="Bausparvertrag"/>
+ <account type="12" name="Festgeld"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Geldanlagen">
+ <account type="9" name="Festgeld"/>
+ <account type="9" name="Investmentfonds"/>
+ <account type="9" name="Bausparvertrag"/>
+ <account type="9" name="Lebensversicherung"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/kids.kmt b/kmymoney2/templates/de_DE/kids.kmt
new file mode 100644
index 0000000..b59dc5a
--- /dev/null
+++ b/kmymoney2/templates/de_DE/kids.kmt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_kids.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kinder</title>
+ <shortdesc>Konten im Zusammenhang mit Kindern</shortdesc>
+ <longdesc>Kindergeld, Kindergarten</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kindergarten"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Gehalt">
+ <account type="12" name="Kindergeld"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/otherasset.kmt b/kmymoney2/templates/de_DE/otherasset.kmt
new file mode 100644
index 0000000..23fd810
--- /dev/null
+++ b/kmymoney2/templates/de_DE/otherasset.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_otherasset.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Sonstige Sachanlage</title>
+ <shortdesc>Sonstige Sachanlagen</shortdesc>
+ <longdesc>Sonstige Sachanlagen</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Sachanlagen">
+ <account type="9" name="Sonstige"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/otherloan.kmt b/kmymoney2/templates/de_DE/otherloan.kmt
new file mode 100644
index 0000000..062cd75
--- /dev/null
+++ b/kmymoney2/templates/de_DE/otherloan.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Sonstiger Kredit</title>
+ <shortdesc>Sonstige Kredite</shortdesc>
+ <longdesc>Weitere Kredite</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="Sonstige"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/skr03.kmt b/kmymoney2/templates/de_DE/skr03.kmt
new file mode 100644
index 0000000..42effc9
--- /dev/null
+++ b/kmymoney2/templates/de_DE/skr03.kmt
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_skr03.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kontenrahmen SKR03</title>
+ <shortdesc>Standardkontenrahmen SKR03</shortdesc>
+ <longdesc>Beta Version des Kontenrahmes SKR03 zum Erweitern und Umstrukturieren. Der Kontenrahmen sollte den eigenen Bedürfnissen angepasst werden was Struktur und Kontenbezeichnungen angeht. WICHTIG!: Die Privatkonten fließen nicht in die Berechnung des Berichtes Bilanz, sind jedoch im Bericht Bilanz aufgeführt. Die im Bericht Bilanz aufgeführte Passiva "Gewinnrücklagen" gibt den Saldo der GuV aus. Die Anlage dieses Kontenrahmens wurde von der Firma LiHAS - Linuxhaus Stuttgart - unterstützt.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Umsatzsteuer">
+ <account type="10" name="1780 Umsatzsteuer-Vorauszahlung"/>
+ <account type="10" name="1790 Umsatzsteuer Vorjahr"/>
+ <account type="10" name="1781 Umsatzsteuer-Vorauszahlung 1/11"/>
+ <account type="10" name="1771 Umsatzsteuer 7%"/>
+ <account type="10" name="1775 Umsatzsteuer 19%"/>
+ <account type="10" name="1791 Umsatzsteuer frühere Jahre"/>
+ <account type="10" name="1786 Umsatzsteuer § 13b UStG 19%"/>
+ </account>
+ <account type="10" name="Verbindlichkeiten"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Saldenvortragskonten">
+ <account type="16" name="9009 Saldenvorträge Kreditoren"/>
+ <account type="16" name="9008 Saldenvorträge Debitoren"/>
+ <account type="16" name="9000 Saldenvortrag Sachkonten"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Anlage- u. Kapitalkonten 0">
+ <account type="9" name="0565 Darlehen"/>
+ <account type="9" name="0420 Büroeinrichtung"/>
+ <account type="9" name="0027 EDV-Software"/>
+ <account type="9" name="0400 Betriebsausstattung"/>
+ <account type="9" name="0410 Geschäftsausstattung"/>
+ <account type="9" name="0210 Maschinen"/>
+ <account type="9" name="0430 Ladeneinrichtung"/>
+ </account>
+ <account type="9" name="Wareneingangs- u. Bestandskonten 3">
+ <account type="9" name="3400 Wareneingang VSt. 19%"/>
+ <account type="9" name="3120 Leistungen §13b UStG 19% Vorsteuer, 19% Umsatzsteuer"/>
+ </account>
+ <account type="9" name="Finanzkonten 1">
+ <account type="9" name="1371 Gewinnermittlung §4/3 nicht Ergebniswirksam"/>
+ <account type="9" name="1100 Postbank"/>
+ <account type="9" name="1576 Abziehbare VSt. nach §13b UStG 19%"/>
+ <account type="9" name="1200 Bankkonto"/>
+ <account type="9" name="1590 Durchlaufende Posten"/>
+ <account type="9" name="1571 Abziehbare VSt. 7%"/>
+ <account type="9" name="1575 Abziehbare VSt. 19%"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Ertragskonten 2">
+ <account type="12" name="2700 Sonstige Erträge"/>
+ <account type="12" name="2500 Außerordentliche Erträge"/>
+ <account type="12" name="2650 sonstige Zinsen und ähnliche Erträge"/>
+ </account>
+ <account type="12" name="Erlöskonten 8">
+ <account type="12" name="8400 Erlöse USt. 19%"/>
+ <account type="12" name="8300 Erlöse USt. 7%"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Werbe-/Reisekosten">
+ <account type="13" name="4610 Werbekosten"/>
+ <account type="13" name="4653 Aufmerksamkeiten"/>
+ <account type="13" name="4665 nicht abzugsfähige Betriebsausg. aus Werbe-, Repräs.- u. Reisekosten"/>
+ <account type="13" name="4670 Reisekosten Unternehmer"/>
+ </account>
+ <account type="13" name="Personalkosten">
+ <account type="13" name="4190 Aushilfslöhne"/>
+ <account type="13" name="4130 gesetzliche soziale Aufwendungen"/>
+ <account type="13" name="4170 Vermögenswirksame Leistungen"/>
+ <account type="13" name="4120 Gehälter"/>
+ <account type="13" name="4165 Aufwendungen für Altersvorsorge"/>
+ </account>
+ <account type="13" name="verschiedene Kosten">
+ <account type="13" name="4985 Werkzeuge und Kleingeräte"/>
+ <account type="13" name="4945 Fortbildungskosten"/>
+ <account type="13" name="4920 Telekom"/>
+ <account type="13" name="4940 Zeitschriften, Bücher"/>
+ <account type="13" name="4922 Internet"/>
+ <account type="13" name="4930 Bürobedarf"/>
+ <account type="13" name="4955 Buchführungskosten"/>
+ <account type="13" name="4921 Mobilfunk"/>
+ <account type="13" name="4970 Nebenkosten des Geldverkehrs"/>
+ <account type="13" name="4910 Porto"/>
+ <account type="13" name="4957 Abschluß- u. Prüfungskosten"/>
+ </account>
+ <account type="13" name="Abschreibungen">
+ <account type="13" name="4855 Sofortabschreibung GWG"/>
+ </account>
+ <account type="13" name="Zinsaufwendungen">
+ <account type="13" name="2110 Zinsaufwendungen für kurzfristige Verbindlichkeiten"/>
+ <account type="13" name="2121 Zinsaufwendungen für KFZ Finanzierung"/>
+ </account>
+ <account type="13" name="Raumkosten">
+ <account type="13" name="4210 Miete und Nebenkosten"/>
+ <account type="13" name="4240 Gas, Wasser, Strom (Verwaltung, Vertrieb)"/>
+ <account type="13" name="4250 Reinigung"/>
+ </account>
+ <account type="13" name="Reparatur/Instandhaltung">
+ <account type="13" name="4805 Reparatur u. Instandh. von Anlagen/Maschinen u. Betriebs- u. Geschäftsausst."/>
+ </account>
+ <account type="13" name="Kfz-Kosten">
+ <account type="13" name="4540 Kfz-Reparaturen"/>
+ <account type="13" name="4530 laufende Kfz-Betriebskosten"/>
+ <account type="13" name="4570 Fremdfahrzeuge"/>
+ <account type="13" name="4520 Kfz-Versicherungen"/>
+ <account type="13" name="4510 Kfz-Steuer"/>
+ <account type="13" name="4580 sonstige Kfz-Kosten"/>
+ </account>
+ <account type="13" name="Versicherungsbeiträge">
+ <account type="13" name="4380 Beiträge"/>
+ <account type="13" name="4390 sonstige Ausgaben"/>
+ <account type="13" name="4396 steuerlich abzugsfähige Verspätungszuschläge und Zwangsgelder"/>
+ <account type="13" name="4360 Versicherungen"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Privatentnahmen/-einlagen">
+ <account type="16" name="1830 Sonderausgaben unbeschränkt abzugsfähig"/>
+ <account type="16" name="1820 Sonderausgaben beschränkt abzugsfähig"/>
+ <account type="16" name="1810 Privatsteuern"/>
+ <account type="16" name="1800 Privatentnahme allgemein"/>
+ <account type="16" name="1890 Privateinlagen"/>
+ <account type="16" name="1850 Außergewöhnliche Belastungen"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/skr04.kmt b/kmymoney2/templates/de_DE/skr04.kmt
new file mode 100644
index 0000000..4828bb1
--- /dev/null
+++ b/kmymoney2/templates/de_DE/skr04.kmt
@@ -0,0 +1,1196 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_skr04.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Kontenrahmen SKR04</title>
+ <shortdesc>Standardkontenrahmen SKR04, Stand 2005</shortdesc>
+ <longdesc>BETA-Version eines Kontenrahmes SKR04 für 2005. Mehr Informationen unter http://linuxwiki.de/GnuCash/skr04</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Erträge aus Verlustübernahme und aufgrund einer Gewinngemeinschaft, eines Gewinn- oder Teilgewinnabführungsvertrags erhaltene Gewinne">
+ <account type="12" name="Erträge aus Verlustübernahme"/>
+ <account type="12" name="Erhaltene Gewinne aufgrund eines Gewinn- oder Teilgewinnabführungsvertrags"/>
+ <account type="12" name="Erhaltene Gewinne aufgrund einer Gewinngemeinschaft"/>
+ </account>
+ <account type="12" name="- davon aus verbundenen Unternehmen">
+ <account type="12" name="Sonstige Zinserträge aus verbundenen Unternehmen"/>
+ <account type="12" name="Zinsähnliche Erträge aus verbundenen Unternehmen"/>
+ <account type="12" name="Sonstige Zinsen und ähnliche Erträge aus verbundenen Unternehmen"/>
+ <account type="12" name="Laufende Erträge aus Anteilen an Kapitalgesellschaften (verbundene Unternehmen) 100 % / 50% steuerfrei"/>
+ <account type="12" name="Diskonterträge aus verbundenen Unternehmen"/>
+ </account>
+ <account type="12" name="Sonstige Zinsen und ähnliche Erträge">
+ <account type="12" name="Zinsähnliche Erträge"/>
+ <account type="12" name="Zinserträge § 233a AO"/>
+ <account type="12" name="Sonstige Zinserträge"/>
+ <account type="12" name="Diskonterträge"/>
+ <account type="12" name="Laufende Erträge aus Anteilen an Kapitalgesellschaften (Umlaufvermögen) 100 %/50 % steuerfrei"/>
+ <account type="12" name="Zinserträge § 233a AO Sonderfall Anlage A KSt"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="B. Umlaufvermögen">
+ <account type="9" name="III. Wertpapiere">
+ <account type="9" name="03. sonstige Wertpapiere">
+ <account type="9" name="Schecks"/>
+ <account type="9" name="Andere Wertpapiere mit unwesentlichen Wertschwankungen im Sinne Textziffer 18 DRS 2"/>
+ <account type="9" name="Finanzwechsel"/>
+ <account type="9" name="Wertpapieranlagen im Rahmen der kurzfristigen Finanzdisposition"/>
+ </account>
+ <account type="9" name="02. Eigene Anteile"/>
+ <account type="9" name="01. Anteile an verbundenen Unternehmen (Umlaufvermögen)">
+ <account type="9" name="Anteile an herrschender oder mit Mehrheit beteiligter Gesellschaft"/>
+ </account>
+ </account>
+ <account type="9" name="IV. Kassenbestand, Bundesbankguthaben, Guthaben bei Kreditinstituten und Schecks">
+ <account type="1" name="Bank"/>
+ <account type="1" name="LZB-Guthaben"/>
+ <account type="1" name="Postbank">
+ <account type="1" name="Postbank Dortmund"/>
+ </account>
+ <account type="9" name="Schecks"/>
+ <account type="1" name="Finanzmittelanlagen im Rahmen der kurzfristigen Finanzdisposition"/>
+ <account type="3" name="Kassenbestand">
+ <account type="3" name="Kasse"/>
+ </account>
+ <account type="1" name="Bundesbankguthaben"/>
+ </account>
+ <account type="9" name="I. Vorräte">
+ <account type="9" name="02. Unfertige Erzeugnisse, unfertige Leistungen (Bestand)">
+ <account type="9" name="Unfertige Leistungen"/>
+ <account type="9" name="In Arbeit befindliche Aufträge"/>
+ <account type="9" name="Unfertige Erzeugnisse"/>
+ <account type="9" name="In Ausführung befindl. Bauaufträge"/>
+ </account>
+ <account type="9" name="05. Erhaltene Anzahlungen auf Bestellungen">
+ <account type="9" name="Erhaltene Anzahlungen 16% MWSt"/>
+ <account type="9" name="Erhaltene Anzahlungen 7% MWSt"/>
+ </account>
+ <account type="9" name="03. Fertige Erzeugnisse und Waren (Bestand)">
+ <account type="9" name="Waren (Bestand)">
+ <account type="9" name="Stein"/>
+ <account type="9" name="Marmor"/>
+ <account type="9" name="Eisen"/>
+ </account>
+ <account type="9" name="Fertige Erzeugnisse (Bestand)"/>
+ </account>
+ <account type="9" name="01. Roh-, Hilfs- und Betriebsstoffe (Bestand)"/>
+ <account type="9" name="04. Geleistete Anzahlungen auf Vorräte">
+ <account type="9" name="Geleistete Anzahlungen 16% Vorsteuer"/>
+ <account type="9" name="Geleistete Anzahlungen 7% Vorsteuer"/>
+ </account>
+ </account>
+ <account type="9" name="II. Forderungen und sonstige Vermögensgegenstände">
+ <account type="9" name="Ausstehende Einlagen auf das gezeichnete Kapital, eingefordert"/>
+ <account type="9" name="02. Forderungen gegen verbundene Unternehmen">
+ <account type="9" name="Besitzwechsel gegen verbund. Unternehmen">
+ <account type="9" name="Besitzwechsel gegen verbundene UN &gt; 1J"/>
+ <account type="9" name="Besitzwechs.gg.verb.UN, bundesbankfähig"/>
+ <account type="9" name="Besitzwechsel gegen verbundene UN &lt; 1J"/>
+ </account>
+ <account type="9" name="WB Forderungen gg. verbundene UN &gt; 1J"/>
+ <account type="9" name="Forderungen aus L+L gg. verbundene UN">
+ <account type="9" name="Forderungen aus L+L gg. verbund. UN &gt; 1J"/>
+ <account type="9" name="Forderungen aus L+L gg. verbund. UN &lt; 1J"/>
+ </account>
+ <account type="9" name="Forderungen gg. verbundene UN &gt; 1 J"/>
+ <account type="9" name="Forderungen gg. verbundene UN &lt; 1 J"/>
+ <account type="9" name="WB Forderungen gg. verbundene UN &lt; 1 J"/>
+ </account>
+ <account type="9" name="03. Forderungen gegen Unternehmen, mit denen ein Beteiligungsverhältnis besteht">
+ <account type="9" name="Forderg. gg. UN mit Beteiligg.verh. &gt; 1 J"/>
+ <account type="9" name="Besitzwechsel gg.UN m. Beteiligungsverh.">
+ <account type="9" name="Besitzwechsel gg.UN m.Beteiligg.verh. &lt; 1 J"/>
+ <account type="9" name="Besitzwechsel gg.UN m.Beteiligg.verh. &gt; 1 J"/>
+ <account type="9" name="Besitzwechsel gg.UN m.Beteiligg.verh.bbf"/>
+ </account>
+ <account type="9" name="WB Forderg.gg.UN m.Beteiligg.verh. g.1J"/>
+ <account type="9" name="Forderg. L+L gg.UN m. Beteiligungsverh.">
+ <account type="9" name="Forderg. L+L gg.UN m.Beteiligg.verh. &lt; 1 J"/>
+ <account type="9" name="Forderg. L+L gg.UN m.Beteiligg.verh. &gt; 1 J"/>
+ </account>
+ <account type="9" name="Forderg. gg. UN mit Beteiligg.verh. &lt; 1 J."/>
+ <account type="9" name="WB Forderg.gg.UN m.Beteiligg.verh. b.1J"/>
+ </account>
+ <account type="9" name="04. Sonstige Vermögensgegenstände">
+ <account type="9" name="Körperschaftsteuerrückforderungen"/>
+ <account type="9" name="Gegenkonto für Vorsteuer nach Durchschnittssätzen für § 4 Abs. 3 EStG"/>
+ <account type="9" name="Umsatzsteuerforderungen">
+ <account type="9" name="USt-Forderungen frühere Jahre"/>
+ <account type="9" name="USt-Forderungen Vorjahr"/>
+ <account type="9" name="Forderungen aus entrichteten Verbrauchsteuern"/>
+ <account type="9" name="USt-Forderungen laufendes Jahr"/>
+ </account>
+ <account type="9" name="Sonstige Vermögensgegenstände">
+ <account type="9" name="Sonstige Vermögensgegenstände (g.1 J)"/>
+ <account type="9" name="Sonstige Vermögensgegenstände (b.1 J)"/>
+ </account>
+ <account type="9" name="Durchlaufende Posten">
+ <account type="9" name="Fremdgeld"/>
+ <account type="9" name="Agenturwarenabrechnung"/>
+ <account type="9" name="Ansprüche aus Rückdeckungsversicherungen"/>
+ </account>
+ <account type="9" name="Nachträglich abziehbare Vorsteuer, § 15a UStG, bewegliche Wirtschaftsgüter"/>
+ <account type="9" name="Darlehen">
+ <account type="9" name="Darlehen g. 1 Jahr"/>
+ <account type="9" name="Darlehen bis 1 Jahr"/>
+ </account>
+ <account type="9" name="Vorsteuer aus Investitionen § 4/3 EStG"/>
+ <account type="9" name="Geldtransit"/>
+ <account type="9" name="Abziehbare Vorsteuer">
+ <account type="9" name="Aufzuteilende Vorsteuer">
+ <account type="9" name="Aufzuteilende Vorsteuer 16%"/>
+ <account type="9" name="Aufzuteilende Vorsteuer nach §§ 13a/13b UStG 16 %"/>
+ <account type="9" name="Aufzuteilende Vorsteuer aus innergemeinschaftlichem Erwerb"/>
+ <account type="9" name="Aufzuteilende Vorsteuer 7%"/>
+ <account type="9" name="Aufzuteilende Vorsteuer nach §§ 13a/13b UStG"/>
+ <account type="9" name="Aufzuteilende Vorsteuer 15%"/>
+ </account>
+ <account type="9" name="Bezahlte Einfuhrumsatzsteuer"/>
+ <account type="9" name="Vorsteuer nach allgemeinen Durchschnittsätzen"/>
+ <account type="9" name="Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb von Neufahrzeugen von Lieferanten ohne UStId-Nr"/>
+ <account type="9" name="Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb">
+ <account type="9" name="Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 15%/16%"/>
+ </account>
+ <account type="9" name="Vorsteuer aus der Auslagerung von Gegenständen aus einem Umsatzsteuerlager"/>
+ <account type="9" name="Abziehbare Vorsteuer nach § 13b UStG">
+ <account type="9" name="Abziehbare Vorsteuer nach § 13b UStG 16%"/>
+ </account>
+ <account type="9" name="Abziehbare Vorsteuern Inland">
+ <account type="9" name="Abziehbare Vorsteuer 16%"/>
+ <account type="9" name="Abziehbare Vorsteuer 7%"/>
+ </account>
+ </account>
+ <account type="9" name="Steuererstattungsanspruch gegenüber anderen EG-Ländern"/>
+ <account type="9" name="Gegenkonto Vorsteuer § 4/3 EStG"/>
+ <account type="9" name="Forderungen gegen Gesellschafter">
+ <account type="9" name="Forderungen gg. Gesellschafter (b.1J)"/>
+ <account type="9" name="Forderungen gg. Gesellschafter (g.1J)"/>
+ </account>
+ <account type="9" name="Verrechnungskonto Gewinnermittlung §4/3 EStG, nicht ergebniswirksam"/>
+ <account type="9" name="Steuerüberzahlungen"/>
+ <account type="9" name="Forderungen gegen Personal aus Lohn- und Gehaltsabrechnung">
+ <account type="9" name="Forderungen gegen Personal (g. 1Jahr)"/>
+ <account type="9" name="Forderungen gegen Personal (bis 1Jahr)"/>
+ </account>
+ <account type="9" name="Genossenschaftsanteile zum kurzfristigen Verbleib"/>
+ <account type="9" name="Zurückzuzahlende Vorsteuer, § 15a UStG, unbewegliche Wirtschaftsgüter"/>
+ <account type="9" name="Nachträglich abziehbare Vorsteuer, § 15a UStG, unbewegliche Wirtschaftsgüter"/>
+ <account type="9" name="GmbH-Anteile zum kurzfristigen Verbleib"/>
+ <account type="9" name="Verrechnungskonto Gewinnermittlung § 4/3 EStG, ergebniswirksam"/>
+ <account type="9" name="Verrechnungskonto Ist-Versteuerung">
+ <account type="9" name="Verrechnungskonto erhaltene Anzahlungen bei Buchung über Debitoren-Konto"/>
+ <account type="9" name="Überleitung Kostenstellen"/>
+ </account>
+ <account type="9" name="Zurückzuzahlende Vorsteuer, § 15a UStG, bewegliche Wirtschaftsgüter"/>
+ <account type="9" name="Forderungen an das Finanzamt aus abgeführtem Bauabzugsbetrag"/>
+ <account type="9" name="Vorsteuer im Folgejahr abziehbar"/>
+ <account type="9" name="Kautionen">
+ <account type="9" name="Kautionen (g. 1 J)"/>
+ <account type="9" name="Kautionen (bis 1 J)"/>
+ </account>
+ <account type="9" name="Auflösung Vorsteuer aus Vorjahr § 4/3 EStG"/>
+ <account type="9" name="Forderungen gegen Vorstandsmitglieder und Geschäftsführer">
+ <account type="9" name="Forderungen gg. Geschäftsf.(g.1J)"/>
+ <account type="9" name="Forderungen gg. Geschäftsf.(b.1J)"/>
+ </account>
+ <account type="9" name="Forderungen gegen Aufsichtsrats- und Beirats-Mitglieder">
+ <account type="9" name="Forderungen gg. Aufsichtsratsm. (g.1 J)"/>
+ <account type="9" name="Forderungen gg. Aufsichtsratsm. (b.1 J)"/>
+ </account>
+ </account>
+ <account type="9" name="01. Forderungen aus Lieferungen und Leistungen">
+ <account type="9" name="Forderungen aus L+L gg. Gesellschafter">
+ <account type="9" name="Forderg. aus L+L gg.Gesellschafter &lt; 1 J"/>
+ <account type="9" name="Forderg. aus L+L gg.Gesellschafter &gt; 1 J"/>
+ </account>
+ <account type="9" name="Zweifelhafte Forderungen">
+ <account type="9" name="Einzelwertberichtigung Forderung (&lt; 1J)"/>
+ <account type="9" name="Zweifelhafte Forderungen (&gt; 1 Jahr)"/>
+ <account type="9" name="Pauschalwertberichtigung Forderg. &lt; 1J"/>
+ <account type="9" name="Einzelwertberichtigung Forderung (&gt; 1J)"/>
+ <account type="9" name="Zweifelhafte Forderungen (bis 1 Jahr)"/>
+ <account type="9" name="Pauschalwertberichtigung Forderg. &gt; 1J"/>
+ </account>
+ <account type="9" name="Wechsel aus Lieferung und Leistung">
+ <account type="9" name="Wechsel a. Lieferungen/Leistungen &lt; 1 J"/>
+ <account type="9" name="Wechsel a. Lieferungen/Leistungen, bundesbankfähig"/>
+ <account type="9" name="Wechsel a. Lieferungen/Leistungen &gt; 1 J"/>
+ </account>
+ <account type="9" name="Forderungen aus Lieferungen und Leistungen ohne Kontokorrent">
+ <account type="9" name="Forderg. aus steuerfreien oder nicht steuerbaren steuerbaren L+L"/>
+ <account type="9" name="Forderungen aus L+L allgem. Steuersatz oder eines Kleinunternehmers"/>
+ <account type="9" name="Forderungen aus L+L gemäß § 24 UStG"/>
+ <account type="9" name="Gegenkonto 1215 - 1218 bei Aufteilung der Forderungen nach Steuersätzen (EÜR)"/>
+ <account type="9" name="Forderungen aus L+L ermäßigt. Steuersatz"/>
+ </account>
+ <account type="9" name="Forderungen nach § 11 Abs. 1 Satz 2 EStG für § 4/3">
+ <account type="9" name="Forderg.a. Lieferungen/Leistungen &gt; 1 J"/>
+ <account type="9" name="Forderg.a. Lieferungen/Leistungen &lt; 1 J"/>
+ </account>
+ <account type="9" name="Gegenkonto 1221-1229, 1250-1257, 1270-1279, 1290-1297 bei Aufteilung Debitorenkonto"/>
+ <account type="9" name="Gegenkonto zu sonstigen Vermögensgegenständen bei Buchungen über Debitorenkonto"/>
+ </account>
+ <account type="9" name="Eingeforderte Nachschüsse"/>
+ </account>
+ </account>
+ <account type="9" name="C. Rechnungsabgrenzungsposten Umlaufvermögen">
+ <account type="9" name="Aktive Rechnungsabgrenzung">
+ <account type="9" name="Damnum/Disagio"/>
+ <account type="9" name="Als Aufwand berücksichtigte Zölle und Verbrauchsteuern auf Vorräte"/>
+ <account type="9" name="Als Aufwand berücksichtigte Umsatzsteuer auf Anzahlungen"/>
+ </account>
+ <account type="9" name="Abgrenzung aktive latente Steuern"/>
+ </account>
+ <account type="9" name="A. Anlagevermögen">
+ <account type="9" name="III. Immaterielle Vermögensgegenstände">
+ <account type="9" name="02. Geschäfts- oder Firmenwert">
+ <account type="9" name="Geschäfts- oder Firmenwert"/>
+ <account type="9" name="Verschmelzungsmehrwert"/>
+ </account>
+ <account type="9" name="03. Geleistete Anzahlungen">
+ <account type="9" name="Anzahlungen auf immaterielle Vermögensgegenstände"/>
+ <account type="9" name="Anzahlungen auf Geschäfts-, Firmenwert"/>
+ </account>
+ <account type="9" name="01. Konzessionen, gewerbliche Schutzrechte und ähnliche Rechte und Werte sowie Lizenzen an solchen Rechten und Werten">
+ <account type="9" name="Konzessionen und gewerbl.Schutzrechte">
+ <account type="9" name="Konzessionen"/>
+ <account type="9" name="Lizenzen an gewerblichen Schutzrechten und ähnlichen Rechten und Werten"/>
+ <account type="9" name="Gewerbliche Schutzrechte"/>
+ <account type="9" name="Ähnliche Rechte und Werte"/>
+ <account type="9" name="EDV-Software"/>
+ </account>
+ </account>
+ </account>
+ <account type="9" name="II. Ingangsetzung und Erweiterung des Geschäftsbetriebes">
+ <account type="9" name="Ingangsetzungs- und Erweiterungsaufwand"/>
+ <account type="9" name="Aufwendungen Währungsumstellung Euro"/>
+ </account>
+ <account type="9" name="V. Finanzanlagen">
+ <account type="9" name="07. Genossenschaftsanteile zum langfristigen Verbleib"/>
+ <account type="9" name="01. Anteile an verbundenen Unternehmen">
+ <account type="9" name="Anteile an herrschender oder mit Mehrheit beteiligter Gesellschaft"/>
+ </account>
+ <account type="9" name="04. Ausleihungen an Unternehmen, mit denen ein Beteiligungsverhältnis besteht "/>
+ <account type="9" name="02. Ausleihungen an verbundene Unternehmen"/>
+ <account type="9" name="03. Beteiligungen">
+ <account type="9" name="Typisch stille Beteiligungen"/>
+ <account type="9" name="Andere Beteiligungen an Kapitalgesellschaften"/>
+ <account type="9" name="Beteiligung einer GmbH &amp; Co.KG an einer Komplementär GmbH"/>
+ <account type="9" name="Andere Beteiligungen an Personengesellschaften"/>
+ <account type="9" name="Atypische stille Beteiligungen"/>
+ </account>
+ <account type="9" name="08. Rückdeckungsansprüche aus Lebensversicherungen zum langfristigen Verbleib"/>
+ <account type="9" name="05. Wertpapiere des Anlagevermögens">
+ <account type="9" name="Festverzinsliche Wertpapiere"/>
+ <account type="9" name="Wertpapiere mit Gewinnbeiligungsansprüchen"/>
+ </account>
+ <account type="9" name="06. Sonstige Ausleihungen">
+ <account type="9" name="Ausleihungen an nahe stehende Personen"/>
+ <account type="9" name="Darlehen"/>
+ <account type="9" name="Ausleihungen an Gesellschafter"/>
+ </account>
+ </account>
+ <account type="9" name="I. Ausstehende Einlagen">
+ <account type="9" name="b) Kommanditgesellschaft">
+ <account type="9" name="Ausstehende Einlagen auf das Kommandit-Kapital, nicht eingefordert"/>
+ <account type="9" name="Ausstehende Einlagen auf das Kommandit-Kapital, eingefordert"/>
+ <account type="9" name="Ausstehende Einlagen auf das Komplementär-Kapital, eingefordert"/>
+ <account type="9" name="Ausstehende Einlagen auf das Komplementär-Kapital, nicht eingefordert"/>
+ </account>
+ <account type="9" name="a) Kapitalgesellschaft">
+ <account type="9" name="Ausstehende Einlagen auf das gezeichnete Kapital, nicht eingefordert (Aktivausweis)"/>
+ <account type="9" name="Ausstehende Einlagen auf das gezeichnete Kapital, eingefordert (Aktivausweis)"/>
+ </account>
+ </account>
+ <account type="9" name="IV. Sachanlagen">
+ <account type="9" name="03. Andere Anlagen, Betriebs- und Geschäftsausstattung">
+ <account type="9" name="Ladeneinrichtung"/>
+ <account type="9" name="Einbauten in fremde Grundstücke"/>
+ <account type="9" name="Computer"/>
+ <account type="9" name="Geringwertige Wirtschaftsgüter bis 410€"/>
+ <account type="9" name="Sonstige Betriebs- und Geschäftsausstattung"/>
+ <account type="9" name="Büroeinrichtung"/>
+ <account type="9" name="Sonstige Transportmittel"/>
+ <account type="9" name="PKW"/>
+ <account type="9" name="LKW"/>
+ <account type="9" name="Gerüst- und Schalungsmaterial"/>
+ <account type="9" name="Werkzeuge"/>
+ <account type="9" name="Andere Anlagen"/>
+ </account>
+ <account type="9" name="01. Grundstücke, grundstücksgleiche Rechte und Bauten einschließlich der Bauten auf fremden Grundstücken">
+ <account type="9" name="Grundstücke und grundstücksgleiche Rechte ohne Bauten">
+ <account type="9" name="Grundstücke mit Substanzverzehr"/>
+ <account type="9" name="Unbebaute Grundstücke"/>
+ <account type="9" name="Grundstücksgleiche Rechte"/>
+ </account>
+ <account type="9" name="Bauten auf fremden Grundstücken">
+ <account type="9" name="Andere Bauten"/>
+ <account type="9" name="Geschäftsbauten"/>
+ <account type="9" name="Garagen"/>
+ <account type="9" name="Fabrikbauten"/>
+ <account type="9" name="Einrichtungen für Geschäfts-, Fabrik-, Wohn- und andere Bauten"/>
+ <account type="9" name="Außenanlagen"/>
+ <account type="9" name="Wohnbauten"/>
+ <account type="9" name="Hof- und Wegebefestigungen"/>
+ </account>
+ <account type="9" name="Wohnbauten">
+ <account type="9" name="Außenanlagen"/>
+ <account type="9" name="Einrichtungen für Wohnbauten"/>
+ <account type="9" name="Garagen"/>
+ <account type="9" name="Hof- und Wegebefestigungen"/>
+ </account>
+ <account type="9" name="Bauten auf eigenen Grundstücken">
+ <account type="9" name="Grundstückswert bebauter Grundstücke"/>
+ <account type="9" name="Fabrikbauten"/>
+ <account type="9" name="Hof- und Wegebefestigungen"/>
+ <account type="9" name="Andere Bauten"/>
+ <account type="9" name="Außenanlagen für Geschäfts-, Fabrik- und andere Bauten"/>
+ <account type="9" name="Garagen"/>
+ <account type="9" name="Einrichtungen für Geschäfts-, Fabrik- und andere Bauten"/>
+ <account type="9" name="Geschäftsbauten"/>
+ </account>
+ </account>
+ <account type="9" name="04. Geleistete Anzahlungen und Anlagen im Bau">
+ <account type="9" name="Anzahlungen auf technische Anlagen"/>
+ <account type="9" name="Geschäfts-, Fabrik- und andere Bauten im Bau auf fremden Grundstücken"/>
+ <account type="9" name="Wohnbauten im Bau auf eigenen Grundstücken"/>
+ <account type="9" name="Anzahlungen auf Geschäfts-, Fabrik- und andere Bauten auf eigenen Grundstücken und grundstücksgleichen Rechten"/>
+ <account type="9" name="Technische Anlagen und Maschinen im Bau"/>
+ <account type="9" name="Anzahlungen auf Wohnbauten auf eigenen Grundstücken und grundstücksgleichen Rechten"/>
+ <account type="9" name="Anzahlungen auf Wohnbauten auf fremden Grundstücken"/>
+ <account type="9" name="Anzahlungen auf Geschäfts-, Fabrik- und andere Bauten auf fremden Grundstücken"/>
+ <account type="9" name="Andere Anlagen, Betriebs- und Geschäftsausstattung im Bau"/>
+ <account type="9" name="Geschäfts-, Fabrik- und andere Bauten im Bau auf eigenen Grundstücken"/>
+ <account type="9" name="Anzahlungen auf andere Anlagen, Betriebs- und Geschäftsausstattung"/>
+ <account type="9" name="Wohnbauten im Bau auf fremden Grundstücken"/>
+ <account type="9" name="Anzahlungen auf Grundstücke und grundstücksgleiche Rechte ohne Bauten"/>
+ </account>
+ <account type="9" name="02. Technische Anlagen und Maschinen">
+ <account type="9" name="Maschinengebundene Werkzeuge"/>
+ <account type="9" name="Technische Anlagen"/>
+ <account type="9" name="Betriebsvorrichtungen"/>
+ <account type="9" name="Maschinen"/>
+ </account>
+ </account>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Erträge aus Beteiligungen">
+ <account type="12" name="Laufende Erträge aus Anteilen an Kapitalgesellschaften (Beteiligung) 100 %/50 % steuerfrei"/>
+ <account type="12" name="Gewinnanteile aus Mitunternehmerschaften § 9 GewStG"/>
+ <account type="12" name="Gewinne aus Anteilen an nicht steuerbefreiten inländischen Kapitalgesellschaften § 9 Nr. 2a GewStG"/>
+ </account>
+ <account type="12" name="- davon aus verbundenen Unternehmen">
+ <account type="12" name="Erträge aus Beteiligungen an Finanzverbundenen Unternehmen"/>
+ <account type="12" name="Laufende Erträge aus Anteilen an Kapitalgesellschaften (verbundene Unternehmen) 100 % / 50 % steuerfrei"/>
+ </account>
+ </account>
+ <account type="12" name=""/>
+ <account type="12" name="">
+ <account type="12" name="Bestandsveränderung unfertige Leistung"/>
+ <account type="12" name="Bestandsveränd.unfertige Erzeugnisse"/>
+ <account type="12" name="Bestandsveränderung Aufträge in Arbeit"/>
+ <account type="12" name="Bestandsveränderungen fertige Erzeugnisse"/>
+ <account type="12" name="Bestandsveränderung Bauaufträge"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Außerordentliche Erträge">
+ <account type="12" name="Außerordentliche Erträge nicht finanzwirksam"/>
+ <account type="12" name="Außerordentliche Erträge finanzwirksam"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Einstellungen in Sonderposten mit Rücklageanteil (§ 52 Abs. 16 EStG)"/>
+ <account type="13" name="Einstellungen in Sonderposten mit Rücklageanteil (steuerfreie Rücklagen)"/>
+ <account type="13" name="Sonstige Aufwendungen betriebsfremd und regelmäßig"/>
+ <account type="13" name="Einstellung in die Einzelwertberichtigung zu Forderungen"/>
+ <account type="13" name="Einstellungen in Sonderposten mit Rücklageanteil (Ansparabschreibungen)"/>
+ <account type="13" name="b) Verluste aus dem Abgang von Gegenständen des Anlagevermögens">
+ <account type="13" name="Verluste aus dem Abgang von Gegenständen des Anlagevermögens"/>
+ <account type="13" name="Anlagenabgänge Finanzanlagen 100 %/50 % nicht abzugsfähig (inländische Kap.Ges.)"/>
+ <account type="13" name="Erlöse aus Verkäufen Finanzanlagen 100 %/50 % nicht abzugsfähig (inländische Kap.Ges.)"/>
+ <account type="13" name="Erlöse aus Verkäufen Finanzanlagen"/>
+ <account type="13" name="Anlagenabgänge immaterielle Vermögensgegenstände"/>
+ <account type="13" name="Erlöse aus Verkäufen Sachanlagevermögen steuerfrei § 4 Nr. 1a UStG"/>
+ <account type="13" name="Erlöse aus Verkäufen Sachanlagevermögen"/>
+ <account type="13" name="Anlagenabgänge Sachanlagen"/>
+ <account type="13" name="Anlagenabgänge Finanzanlagen"/>
+ <account type="13" name="Erlöse aus Verkäufen Sachanlagevermögen 16% USt"/>
+ <account type="13" name="Erlöse aus Verkäufen Sachanlagevermögen steuerfrei § 4 Nr. 1b UStG"/>
+ <account type="13" name="Verluste aus der Veräußerung von Anteilen an Kapitalgesellschaften 100 %/50 % nicht abzugsfähig"/>
+ <account type="13" name="Erlöse aus Verkäufen immaterieller Vermögensgegenstände"/>
+ </account>
+ <account type="13" name="e) Kalkulatorische Kosten">
+ <account type="13" name="Kalkulatorische Abschreibungen"/>
+ <account type="13" name="Verrechnete kalkulatorische Wagnisse"/>
+ <account type="13" name="Verrechneter kalkulatorischer Lohn für unentgeltliche Mitarbeiter"/>
+ <account type="13" name="Kalkulatorischer Lohn für unentgeltliche Mitarbeiter"/>
+ <account type="13" name="Verrechneter kalkulatorischer Unternehmerlohn"/>
+ <account type="13" name="Verrechnete kalkulatorische Abschreibungen"/>
+ <account type="13" name="Kalkulatorische Wagnisse"/>
+ <account type="13" name="Verrechnete kalkulatorische Miete und Pacht"/>
+ <account type="13" name="Kalkulatorischer Unternehmerlohn"/>
+ <account type="13" name="Kalkulatorische Miete und Pacht"/>
+ <account type="13" name="Verrechnete kalkulatorische Zinsen"/>
+ <account type="13" name="Kalkulatorische Zinsen"/>
+ </account>
+ <account type="13" name="Forderungsverluste">
+ <account type="13" name="Forderungsverluste aus steuerfreien EG-Lieferunge"/>
+ <account type="13" name="Forderungsverluste 15% USt"/>
+ <account type="13" name="Forderungsverluste aus im Inland steuerpflichtigen EGLieferungen 15% USt"/>
+ <account type="13" name="Forderungsverluste aus im Inland steuerpflichtigen EGLieferungen 16% USt"/>
+ <account type="13" name="Forderungsverluste aus im Inland steuerpflichtigen EG-Lieferungen 7% USt"/>
+ <account type="13" name="Forderungsverluste 16% USt"/>
+ <account type="13" name="Forderungsverluste 7% USt"/>
+ </account>
+ <account type="13" name="Einstellungen in Sonderposten mit Rücklageanteil (Existenzgründerrücklage)"/>
+ <account type="13" name="f) Kosten bei Anwendung des Umsatzkostenverfahrens">
+ <account type="13" name="Herstellungskosten"/>
+ <account type="13" name="Verwaltungskosten"/>
+ <account type="13" name="Vertriebskosten"/>
+ <account type="13" name="Gegenkonto zu 6990 bis 6998"/>
+ </account>
+ <account type="13" name="Sonstige Aufwendungen unregelmäßig"/>
+ <account type="13" name="d) sonstige Aufwendungen im Rahmen der gewöhnlichen Geschäftstätigkeit">
+ <account type="13" name="Zuwendungen, Spenden an Stiftungen für gemeinnützige Zwecke i.S.d. § 52 Abs. 2 Nr. 4 AO"/>
+ <account type="13" name="Zuwendungen, Spenden für mildtätige Zwecke"/>
+ <account type="13" name="Zuwendungen, Spenden an Stiftungen für kirchliche, religiöse und gemeinnützige Zwecke"/>
+ <account type="13" name="Zuwendungen, Spenden an Stiftungen für gemeinnützige Zwecke i.S.d. § 52 Abs. 2 Nr. 1-3 AO"/>
+ <account type="13" name="Zuwendungen, Spenden für kirchliche, religiöse und gemeinntüzige Zwecke"/>
+ <account type="13" name="Zuwendungen, Spenden für wissenschaftliche und kulturelle Zwecke"/>
+ <account type="13" name="Zuwendungen, Spenden an Stiftungen für wissenschaftliche, mildtätige, kulturelle Zwecke"/>
+ <account type="13" name="Zuwendungen, Spenden, steuerlich nicht abziehbar"/>
+ <account type="13" name="Zuwendungen, Spenden an politische Parteien"/>
+ </account>
+ <account type="13" name="Periodenfremde Aufwendungen"/>
+ <account type="13" name="c) Verluste aus Wertminderungen oder aus dem Abgang von Gegenständen des Umlaufvermögens und Einstellung in die Pauschalwertberichtigung zu Forderungen">
+ <account type="13" name="Aufwendugnen aus der Zuschreibung von steuerlich niedriger bewerteten Rückstellungen"/>
+ <account type="13" name="Abschreibungen auf Umlaufvermögen außer Vorräten und Wertpapieren des UV"/>
+ <account type="13" name="Vorwegnahme künftiger Wertschwankungen im Umlaufvermögen außer Vorräten und Wertpapieren"/>
+ <account type="13" name="Einstellung in die Pauschalwertberichtigung zu Forderungen"/>
+ <account type="13" name="Verluste aus dem Abgang von Gegenständen des Umlaufvermögens (außer Vorräten) 100%/50% nicht abzugsfähig"/>
+ <account type="13" name="Verluste aus dem Abgang von Gegenständen des Umlaufvermögens außer Vorräten"/>
+ <account type="13" name="Abschreibungen auf Umlaufvermögen außer Vorräten und Wertpapieren des UV, steuerrechtlich bedingt"/>
+ <account type="13" name="Aufwendungen aus der Zuschreibung von steuerlich niedriger bewerteten Verbindlichkeiten"/>
+ </account>
+ <account type="13" name="Einstellungen in Sonderposten mit Rücklageanteil (Sonderabschreibungen)"/>
+ <account type="13" name="a) ordentliche betriebliche Aufwendungen">
+ <account type="13" name="Aufwendungen aus Kursdifferenzen"/>
+ <account type="13" name="8) verschiedene betriebliche Kosten">
+ <account type="13" name="Freiwillige Sozialleistungen"/>
+ <account type="13" name="Vergütungen an Mitunternehmer §15 EStG"/>
+ <account type="13" name="Aufwendungen aus der Veräußerung von Anteilen an Kapitalgesellschaften 100 %/50 % nicht abzugsfähig"/>
+ <account type="13" name="Zeitschriften, Bücher"/>
+ <account type="13" name="Nebenkosten des Geldverkehrs"/>
+ <account type="13" name="Aufwendungen aus Anteilen an Kapitalgesellschaften 100 %/ 50 % nicht abzugsfähig (inländische Kap.Ges.)"/>
+ <account type="13" name="Abschluß- und Prüfungskosten"/>
+ <account type="13" name="Aufwendungen für Abraum- und Abfallbeseitigung"/>
+ <account type="13" name="Sonstiger Betriebsbedarf"/>
+ <account type="13" name="Nicht abziehbare Hälfte der Aufsichtsratsvergütungen"/>
+ <account type="13" name="Telefax und Internetkosten"/>
+ <account type="13" name="Nicht abziehbare Vorsteuer">
+ <account type="13" name="Nicht abziehbare Vorsteuer 16%"/>
+ <account type="13" name="Nicht abziehbare Vorsteuer 7%"/>
+ </account>
+ <account type="13" name="Rechts- und Beratungskosten"/>
+ <account type="13" name="Mietleasing">
+ <account type="13" name="Gewerbesteuerlich zu berücksichtigendes Mietleasing § 8 GewStG"/>
+ </account>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Bürobedarf"/>
+ <account type="13" name="Abziehbare Aufsichtsratsvergütungen"/>
+ <account type="13" name="Buchführungskosten"/>
+ <account type="13" name="Haftungsvergütung an Mitunternehmer § 15 EStG"/>
+ <account type="13" name="Werkzeuge und Kleingeräte"/>
+ <account type="13" name="Mieten für Einrichtungen">
+ <account type="13" name="Gewerbesteuerlich zu berücksichtigende Miete für Einrichtungen § 8 GewStG"/>
+ </account>
+ <account type="13" name="Fortbildungskosten"/>
+ <account type="13" name="Porto"/>
+ </account>
+ <account type="13" name="Aufwendungen aus der Währungsumstellung auf den Euro (Art. 43 Abs. 1 EGHGB)"/>
+ <account type="13" name="7) Kosten der Warenabgabe">
+ <account type="13" name="Fremdarbeiten (Vertrieb)"/>
+ <account type="13" name="Aufwand für Gewährleistung"/>
+ <account type="13" name="Verpackungsmaterial"/>
+ <account type="13" name="Transportversicherungen"/>
+ <account type="13" name="Ausgangsfrachten"/>
+ <account type="13" name="Verkaufsprovisionen"/>
+ </account>
+ <account type="13" name="sonstige betriebliche Aufwendungen">
+ <account type="13" name="Fremdleistungen und Fremdarbeiten"/>
+ <account type="13" name="Sonstige betriebl.u.regelm.Aufwendungen"/>
+ </account>
+ <account type="13" name="6) Werbe- und Reisekosten">
+ <account type="13" name="Reisekosten Arbeitnehmer">
+ <account type="13" name="Reisekosten AN Übernachtungsaufwand"/>
+ <account type="13" name="Kilometergelderstattung Arbeitnehmer"/>
+ <account type="13" name="Reisekosten Arbeitnehmer Verpflegungsmehraufwand"/>
+ <account type="13" name="Reisekosten Arbeitnehmer, Fahrtkosten"/>
+ </account>
+ <account type="13" name="Werbekosten">
+ <account type="13" name="Repräsentationskosten"/>
+ <account type="13" name="Nicht abzugsfähige Betriebsausgaben aus Werbe-, Repräsentations- und Reisekosten (nicht abziehbarer Anteil)"/>
+ <account type="13" name="Geschenke ausschlielich betrieblich genutzt"/>
+ <account type="13" name="Sonstige eingeschränkt abziehbare Betriebsausgaben (abziehbarer Anteil)"/>
+ <account type="13" name="Geschenke über 40 €"/>
+ <account type="13" name="Geschenke bis 40 €"/>
+ <account type="13" name="Nicht abzugsfähige Bewirtungskosten"/>
+ <account type="13" name="Bewirtungskosten"/>
+ <account type="13" name="Sonstige eingeschränkt abziehbare Betriebsausgaben (nicht abziehbarer Anteil)"/>
+ <account type="13" name="Aufmerksamkeiten"/>
+ </account>
+ <account type="13" name="Reisekosten Unternehmer">
+ <account type="13" name="Reisekosten Unternehmer Übernachtungsaufwand"/>
+ <account type="13" name="Reisekosten Unternehmer, Fahrtkosten"/>
+ <account type="13" name="Fahrten Wohnung zwischen Wohnung und Arbeitsstätte (Haben)"/>
+ <account type="13" name="Fahrten zwischen Wohnung und Arbeitsstätte (nicht abziehbarer Anteil)"/>
+ <account type="13" name="Reisekosten Unternehmer Verpflegungsmehraufwand"/>
+ <account type="13" name="Fahrten zwischen Wohnung und Arbeitsstätte (abziehbarer Anteil)"/>
+ </account>
+ </account>
+ <account type="13" name="3) Versicherungen, Beiträge und Abgaben">
+ <account type="13" name="Versicherungen"/>
+ <account type="13" name="Sonstige Abgaben">
+ <account type="13" name="Steuerlich abzugsfähige Verspätungszuschläge und Zwangsgelder"/>
+ <account type="13" name="Steuerlich nicht abzugsfähige Verspätungszuschläge und Zwangsgelder"/>
+ </account>
+ <account type="13" name="Ausgleichsabgabe i. S. d. Schwerbehindertengesetzes"/>
+ <account type="13" name="Versicherungen für Gebäude, die nicht zum Betriebsvermögen gehören"/>
+ <account type="13" name="Beiträge"/>
+ <account type="13" name="Nettoprämie für Rückdeckung künftiger Versorgungsleistungen"/>
+ <account type="13" name="Versicherungen für Gebäude, die zum Betriebsvermögen gehören"/>
+ </account>
+ <account type="13" name="Aufwendungen aus Bewertung Finanzmittelfonds"/>
+ <account type="13" name="5) Fahrzeugkosten">
+ <account type="13" name="Fremdfahrzeugkosten"/>
+ <account type="13" name="Kfz-Kosten für betrieblich genutzte, zum Privatvermögen gehörende Kraftfahrzeuge"/>
+ <account type="13" name="Leasingfahrzeugkosten"/>
+ <account type="13" name="Garagenmiete"/>
+ <account type="13" name="Sonstige Kfz-Kosten"/>
+ <account type="13" name="Kfz-Versicherungen"/>
+ <account type="13" name="Laufende Kfz-Betriebskosten"/>
+ <account type="13" name="Mautgebühren"/>
+ <account type="13" name="Kfz-Reparaturen"/>
+ </account>
+ <account type="13" name="4) Reparaturen und Instandhaltungen">
+ <account type="13" name="Reparaturen und Instandhaltung von anderen Anlagen"/>
+ <account type="13" name="Reparaturen und Instandhaltung von Bauten">
+ <account type="13" name="Reparaturen und Instandhaltung von Bauten, die nicht zum Betriebsvermögen gehören"/>
+ </account>
+ <account type="13" name="Reparaturen und Instandhaltung von Betriebs- und Geschäftsausstattung"/>
+ <account type="13" name="Mietleasing">
+ <account type="13" name="Gewerbesteuerlich zu berücksichtigendes Mietleasing § 8 GewStG"/>
+ </account>
+ <account type="13" name="Wartungskosten für Hard- und Software"/>
+ <account type="13" name="Reparaturen und Instandhaltung von technischen Anlagen und Maschinen"/>
+ <account type="13" name="Sonstige Reparaturen und Instandhaltung"/>
+ </account>
+ <account type="13" name="1) Raumkosten">
+ <account type="13" name="Gas, Strom, Wasser">
+ <account type="13" name="Gas, Strom, Wasser für Gebäude, die nicht zum Betriebsvermögen gehören"/>
+ </account>
+ <account type="13" name="Pacht">
+ <account type="13" name="Vergütungen an Mitunternehmer für die pachtweise Überlassung ihrer Wirtschaftsgüter § 15 EStG"/>
+ <account type="13" name="GewStl. zu berücksichtigende Pacht §8 GewStG"/>
+ </account>
+ <account type="13" name="Abgaben für betrieblich genutzen Grundbesitz">
+ <account type="13" name="Abgaben für Grundbesitz, der nicht zum Betriebsvermögen gehört"/>
+ </account>
+ <account type="13" name="Heizung">
+ <account type="13" name="Heizung für Gebäude, die nicht zum Betriebsvermögen gehren"/>
+ </account>
+ <account type="13" name="Raumkosten"/>
+ <account type="13" name="Instandhaltung betrieblicher Räume">
+ <account type="13" name="Instandhaltung betrieblicher Räume in Gebäuden, die nicht zum Betriebs- Geschäftsausvermögen gehören"/>
+ </account>
+ <account type="13" name="Aufwendungen für ein häusliches Arbeitszimmer (nicht abziehbarer Anteil)"/>
+ <account type="13" name="Sonstige Raumkosten">
+ <account type="13" name="Sonstige Raumkosten für Gebäude, die nicht zum Betriebsvermögen gehören"/>
+ </account>
+ <account type="13" name="Aufwendungen für ein häusliches Arbeitszimmer (abziehbarer Anteil)"/>
+ <account type="13" name="Miete">
+ <account type="13" name="Vergütungen an Mitunternehmer für die mietweise Überlassung ihrer Wirtschaftsgüter § 16 EStG"/>
+ <account type="13" name="Gewerbesteuerlich zu berücksichtigende Miete § 8 GewStG "/>
+ </account>
+ <account type="13" name="Sonstige Grundstücksaufwendungen">
+ <account type="13" name="Grundstücksaufwendungen für Gebäude, die nicht zum Betriebsvermögen gehören"/>
+ </account>
+ <account type="13" name="Reinigung">
+ <account type="13" name="Reinigung für Gebäude nicht im BV"/>
+ </account>
+ </account>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Nicht steuerbare Umsätze"/>
+ <account type="12" name="Umsatzsteuer-Vergütungen"/>
+ <account type="12" name="Erlösschmälerungen">
+ <account type="12" name="Erlösschmälerungen 7% USt"/>
+ <account type="12" name="Erlösschmälerung EG-Lieferung 15% USt"/>
+ <account type="12" name="Gewährte Boni">
+ <account type="12" name="Gewährte Boni 7% USt"/>
+ <account type="12" name="Gewährte Boni 16% USt"/>
+ </account>
+ <account type="12" name="Erlösschmälerungen steuerfr. EG-Lief."/>
+ <account type="12" name="Erlösschmälerungen 16% USt"/>
+ <account type="12" name="Gewährte Rabatte">
+ <account type="12" name="Gewährte Rabatte 7% USt"/>
+ <account type="12" name="Gewährte Rabatte 16% USt"/>
+ </account>
+ <account type="12" name="Erlösschmälerung EG-Lieferung 16% USt"/>
+ <account type="12" name="Erlösschmäl.i.and.EG-Ld.stpfl.Liefer."/>
+ <account type="12" name="Erlösschmälerung EG-Lieferung 7% USt"/>
+ <account type="12" name="Erlösschmälerungen steuerfrei §4 Nr. 1a"/>
+ <account type="12" name="Gewährte Skonti">
+ <account type="12" name="Gewährte Skonti 7% USt"/>
+ <account type="12" name="Gewährte Skonti 16% USt"/>
+ </account>
+ </account>
+ <account type="12" name="b) Statistische Konten EÜR Umsatzerlöse">
+ <account type="12" name="Statistisches Konto Erlöse steuerfrei und nicht steuerbar (EÜR)"/>
+ <account type="12" name="Statistisches Konto Erlöse zum ermäßigten Umsatzsteuersatz (EÜR)"/>
+ <account type="12" name="Statistisches Konto Erlöse zum allgemeinen Umsatzsteuersatz (EÜR)"/>
+ <account type="12" name="Gegenkonto 4580 - 4582 bei Aufteilung der Erlöse nach Steuersätzen (EÜR)"/>
+ </account>
+ <account type="12" name="a) Umsatzerlöse">
+ <account type="12" name="Umsatzerlöse 7% USt"/>
+ <account type="12" name="Steuerfreie Umsätze">
+ <account type="12" name="Innergemeinschaftl. Dreiecksgeschäft"/>
+ <account type="12" name="Steuerfreie Umsätze Offshore usw."/>
+ <account type="12" name="Steuerfreie Umsätze § 4 Nr. 1a UStG"/>
+ <account type="12" name="Steuerfreie Umsätze § 4 Nr. 2-7 UStG"/>
+ <account type="12" name="Steuerfreie Umsätze §4 Nr. 8 ff UStG"/>
+ <account type="12" name="Sonstige steuerfr. Umsätze Inland"/>
+ <account type="12" name="Steuerfr. EG-Lief.v.Neufahrzg.ohne UStID"/>
+ <account type="12" name="Steuerfreie EG-Lieferungen, §4,1b UStG"/>
+ </account>
+ <account type="12" name="Umsatzerlöse"/>
+ <account type="12" name="Erlöse aus im Drittland steuerbaren Leistungen, im Inland nicht steuerbare Umsätze"/>
+ <account type="12" name="Erlöse Geldspielautomaten 16% USt"/>
+ <account type="12" name="Erlöse"/>
+ <account type="12" name="Erlöse aus im anderen EG-Land steuerbaren Leistungen, im Inland nicht steuerbare Umsätze"/>
+ <account type="12" name="Erlöse aus im anderen EG-Land steuerpflichtigen Lieferungen"/>
+ <account type="12" name="Erlöse aus Leistungen, für die der Leistungsempfänger die Steuer nach § 13b UStG schuldet."/>
+ <account type="12" name="Erlöse die mit den Durchschnittssätzen des § 24 UStG versteuert werden"/>
+ <account type="12" name="Erlöse Abfallverwertung"/>
+ <account type="12" name="Erlöse Kleinunternehmer § 19 UStG"/>
+ <account type="12" name="Provisionserlöse">
+ <account type="12" name="Provisionserlöse, steuerfrei § 4 Nr.5"/>
+ <account type="12" name="Provisionserlöse 7% USt"/>
+ <account type="12" name="Provisionserlöse 16% USt"/>
+ <account type="12" name="Provisionserlöse, steuerfrei §4 Nr.8ff"/>
+ </account>
+ <account type="12" name="Umsatzerlöse 16% USt"/>
+ <account type="12" name="Erlöse aus im Inland steuerpflichtigen EG Lieferungen 16% USt"/>
+ <account type="12" name="Erlöse Leergut"/>
+ <account type="12" name="Erlöse aus im Inland steuerpflichtigen EG Lieferungen 7% USt"/>
+ </account>
+ <account type="12" name="Unentgeltliche Wertabgaben">
+ <account type="12" name="Entnahme Unternehmer (Waren) 16% USt"/>
+ <account type="12" name="Entnahme Unternehmer (Waren) ohne USt"/>
+ <account type="12" name="Verwendung von Gegenständen 16% USt"/>
+ <account type="12" name="Entnahme von Gegenständen ohne USt"/>
+ <account type="12" name="Verwendung von Gegenst. (Tel) 16% USt"/>
+ <account type="12" name="Unentgeltl. Erbringung Leist. 7% USt"/>
+ <account type="12" name="Verwendung von Gegenst.(Kfz) ohne USt"/>
+ <account type="12" name="Unentgeltl. Zuwend. von Waren 7% USt"/>
+ <account type="12" name="Unentgeltl. Zuwend. Gegenstände 16% USt"/>
+ <account type="12" name="Entnahme Unternehmer (Waren) 7% USt"/>
+ <account type="12" name="Unentgeltl. Zuwend. Gegenstände ohne USt"/>
+ <account type="12" name="Verwendung von Gegenständen 7% USt"/>
+ <account type="12" name="Unentgeltl. Erbringung Leist. ohne USt"/>
+ <account type="12" name="Verwendung von Gegenst. (Kfz) 16% USt"/>
+ <account type="12" name="Unentgeltl. Zuwend. von Waren ohne USt"/>
+ <account type="12" name="Unentgeltl. Zuwend. von Waren 16% USt"/>
+ <account type="12" name="Unentgeltl. Erbringung Leist. 16% USt"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Erträge aus anderen Wertpapieren und Ausleihungen des Finanzanlagevermögens"/>
+ <account type="12" name="- davon aus verbundenen Unternehmen">
+ <account type="12" name="Laufende Erträge aus Anteilen Wertpapiean Kapitalgesellschaften (verbundene Unternehmen) 100 %/50 % steuerfrei"/>
+ <account type="12" name="Erträge aus anderen Wertpapieren und Ausleihungen des Finanzanlagevermögens aus Finanzverbundenen Unternehmen"/>
+ </account>
+ <account type="12" name="Laufende Erträge aus Anteilen Wertpapiere an Kapitalgesellschaften (verbundene Unternehmen) 100 %/50 % steuerfrei"/>
+ <account type="12" name="Laufende Erträge aus Anteilen an Kapitalgesellschaften (Finanzanlagevermögen) 100 %/50 % steuerfrei"/>
+ </account>
+ <account type="9" name=""/>
+ <account type="13" name="">
+ <account type="13" name="a) Aufwendungen für Roh-, Hilfs- und Betriebsstoffe und für bezogene Waren">
+ <account type="13" name="01. Aufwendungen für Roh-, Hilfs- und Betriebsstoffe und für bezogene Waren">
+ <account type="13" name="Energiestoffe"/>
+ <account type="13" name="Einkauf von Roh-,Hilfs- und Betriebsstoffen"/>
+ <account type="13" name="Aufwendungen für Roh-, Hilfs- und Betriebsstoffe und für bezogene Waren"/>
+ </account>
+ <account type="13" name="03. Statistische Konten EÜR">
+ <account type="13" name="Nachlässe">
+ <account type="13" name="Nachlässe aus innergemeinschaftlichem Erwerb 7% Vorsteuer/USt"/>
+ <account type="13" name="Erhaltene Rabatte">
+ <account type="13" name="Erhaltene Rabatte 16% Vorsteuer"/>
+ <account type="13" name="Erhaltene Rabatte 7% Vorsteuer"/>
+ </account>
+ <account type="13" name="Nachlässe 7% Vorsteuer"/>
+ <account type="13" name="Erhaltene Boni">
+ <account type="13" name="Erhaltene Boni 16% Vorsteuer"/>
+ <account type="13" name="Erhaltene Boni 7% Vorsteuer"/>
+ </account>
+ <account type="13" name="Erhaltene Skonti">
+ <account type="13" name="Erhaltene Skonti 7% Vorsteuer"/>
+ <account type="13" name="Erhaltene Skonti 16% Vorsteuer"/>
+ </account>
+ <account type="13" name="Nachlässe aus innergemeinschaftlichem Erwerb 16% Vorsteuer/USt"/>
+ <account type="13" name="Nachlsse aus innergemeinschaftlichem Erwerb 15% Vorsteuer/USt"/>
+ <account type="13" name="Nachlässe 16% Vorsteuer"/>
+ </account>
+ <account type="13" name="Bezugsnebenkosten">
+ <account type="13" name="Leergut"/>
+ <account type="13" name="Zölle und Einfuhrabgaben"/>
+ <account type="13" name="Verrechnete Stoffkosten"/>
+ </account>
+ <account type="13" name="Statistisches Konto Wareneinkauf zum allgemeinen Umsatzsteuersatz (EÜR)"/>
+ <account type="13" name="Statistisches Konto Wareneinkauf zum ermäßigten Umsatzsteuersatz (EÜR)"/>
+ <account type="13" name="Bestandsveränderungen"/>
+ <account type="13" name="Nicht abziehbare Vorsteuer">
+ <account type="13" name="Nicht abziehbare Vorsteuer 7%"/>
+ <account type="13" name="Nicht abziehbare Vorsteuer 16%"/>
+ </account>
+ <account type="13" name="Statistisches Konto Wareneinkauf ohne Vorsteuerabzug (EÜR)"/>
+ <account type="13" name="Gegenkonto 5580-5582 bei Aufteilung des Wareneinkaufs nach Steuersätzen (EÜR)"/>
+ </account>
+ <account type="13" name="02. Wareneingang">
+ <account type="13" name="lnnergemeinschaftlicher Erwerb 7% Vorsteuer und 7% Umsatzsteuer"/>
+ <account type="13" name="Wareneingang 7% Vorsteuer"/>
+ <account type="13" name="Steuerfreie Einfuhren"/>
+ <account type="13" name="Wareneingang 9% Vorsteuer"/>
+ <account type="13" name="Wareneingang 16% Vorsteuer"/>
+ <account type="13" name="Steuerfreier innergemeinschaftlicher Erwerb"/>
+ <account type="13" name="Innergemeinschaftlicher Erwerb 16% Vorsteuer und 16% Umsatzsteuer"/>
+ <account type="13" name="lnnergemeinschaftlicher Erwerb ohne Vorsteuerabzug und 7% Umsatzsteuer"/>
+ <account type="13" name="lnnergemeinschaftlicher Erwerb ohne Vorsteuerabzug und 16% Umsatzsteuer"/>
+ <account type="13" name="Innergemeinschaftlicher Erwerb von Neufahrzeugen von Lieferanten ohne UStID 16% Vorsteuer und 16% Umsatzsteuer"/>
+ <account type="13" name="Wareneingang 5% Vorsteuer"/>
+ <account type="13" name="Waren aus einem Umsatzsteuerlager, 13a UStG 16% Vorsteuer und 16% Umsatzsteuer"/>
+ <account type="13" name="Waren aus einem Umsatzsteuerlager, 13a UStG 7% Vorsteuer und 7% Umsatzsteuer"/>
+ <account type="13" name="Wareneingang"/>
+ </account>
+ </account>
+ <account type="13" name="b) Aufwendungen für bezogene Leistungen">
+ <account type="13" name="02. Umstäze, für die als Leistungsempfänger die Steuer nach 13b Abs. 2 UStG geschuldet wird">
+ <account type="13" name="Bauleistungen eines im Inland ansässigen Unternehmers 16% Vorsteuer und 16% Umsatzsteuer"/>
+ <account type="13" name="Leistungen eines im Ausland ansässigen Unternehmers ohne Vorsteuer und 7% Umsatzsteuer"/>
+ <account type="13" name="Leistungen eines im Ausland ansässigen Unternehmers ohne Vorsteuer und 16% Umsatzsteuer"/>
+ <account type="13" name="Bauleistungen eines im Inland ansässigen Unternehmers ohne Vorsteuer und 7% Umsatzsteuer"/>
+ <account type="13" name="Bauleistungen eines im Inland ansässigen Unternehmers 7% Vorsteuer und 7% Umsatzsteuer"/>
+ <account type="13" name="Leistungen von ausländischen Unternehmern"/>
+ <account type="13" name="Bauleistungen eines im Inland ansässigen Unternehmers ohne Vorsteuer und 16% Umsatzsteuer"/>
+ <account type="13" name="Leistungen eines im Ausland ansässigen Unternehmers 7% Vorsteuer und 7% Umsatzsteuer"/>
+ <account type="13" name="Leistungen eines im Ausland ansässigen Unternehmers 16% Vorsteuer und 16% Umsatzsteuer"/>
+ </account>
+ <account type="13" name="01. Fremdleistungen">
+ <account type="13" name="Fremdleistungen"/>
+ </account>
+ </account>
+ </account>
+ <account type="12" name=""/>
+ <account type="13" name="">
+ <account type="13" name="Sonstige Steuern">
+ <account type="13" name="Kfz-Steuer"/>
+ <account type="13" name="Erträge aus der Auflösung von Rückstellungen für sonstige Steuern"/>
+ <account type="13" name="Verbrauchsteuer"/>
+ <account type="13" name="Steuernachzahlungen Vorjahre für sonstige Steuern"/>
+ <account type="13" name="Ökosteuer"/>
+ <account type="12" name="Steuererstattungen Vorjahre für sonstige Steuern"/>
+ <account type="13" name="Grundsteuer">
+ <account type="13" name="Grundsteuer für Gebäude, die nicht zum Betriebsvermögen gehören"/>
+ </account>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Zinsen und ähnliche Aufwendungen 100 %/50 % nicht abzugsfähig"/>
+ <account type="13" name="Aufwendungen aus Verlustübernahme und aufgrund einer Gewinngemeinschaft, eines Gewinn- oder Teilgewinnabführungsvertrags abgeführte Gewinne">
+ <account type="13" name="Abgeführte Gewinne aufgrund eines Gewinn- oder Teilgewinnabführungsvertrags"/>
+ <account type="13" name="Abgeführte Gewinne aufgrund einer Gewinngemeinschaft"/>
+ <account type="13" name="Aufwendungen aus Verlustübernahme"/>
+ <account type="13" name="Abgeführte Gewinnanteile an stille Gesellschafter § 8 GewStG"/>
+ </account>
+ <account type="13" name="- davon an verbundene Unternehmen">
+ <account type="13" name="Zinsähnliche Aufwendungen an verbundene Unternehmen"/>
+ <account type="13" name="Zinsen und ähnliche Aufwendungen an verbundene Unternehmen 100 %/50 % nicht abzugsfähig"/>
+ <account type="13" name="Zinsaufwendungen für kurzfristige Verbindlichkeiten an verbundene Unternehmen"/>
+ <account type="13" name="Zinsaufwendungen für langfristige Verbindlichkeiten an verbundene Unternehmen"/>
+ <account type="13" name="Zinsen und ähnliche Aufwendungen an verbundene Unterbundenen nehmen"/>
+ <account type="13" name="Diskontaufwendungen an verbundene Unternehmen"/>
+ </account>
+ <account type="13" name="Diskontaufwendungen"/>
+ <account type="13" name="Zinsen und ähnliche Aufwendungen">
+ <account type="13" name="Zinsaufwendungen §§ 233a bis 237 AO"/>
+ <account type="13" name="Steuerlich nicht abzugsfähige, andere Nebenleistungen zu Steuern"/>
+ <account type="13" name="Steuerlich abzugsfähige, andere Nebenleistungen zu Steuern"/>
+ <account type="13" name="Zinsaufwendungen § 233a AO betriebliche Steuern"/>
+ </account>
+ <account type="13" name="Zinsaufwendungen für kurzfristige Verbindlichkeiten">
+ <account type="13" name="Nicht abzugsfähige Schuldzinsen (langfristig) gemäß § 4 Abs. 4a EStG"/>
+ <account type="13" name="Nicht abzugsfähige Schuldzinsen (kurzfristig) gemäß § 4 Abs. 4a EStG"/>
+ <account type="13" name="In Dauerschuldzinsen umqualifizierte Zinsen auf kurzfristige Verbindlichkeiten"/>
+ </account>
+ <account type="13" name="Zinsähnliche Aufwendungen"/>
+ <account type="13" name="Zinsaufwendungen für langfristige Verbindlichkeiten">
+ <account type="13" name="Zinsaufwendungen für Gebäude, die zum Betriebsvermögen gehören"/>
+ <account type="13" name="Zinsen zur Finanzierung des Anlagevermögen"/>
+ <account type="13" name="Zinsaufwendungen an Mitunternehmer für die Hingabe von Kapital § 15 EStG"/>
+ <account type="13" name="Renten und dauernde Lasten aus Gründung/Erwerb § 8 GewStG"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Außerordentliche Aufwendungen">
+ <account type="13" name="Außerordentliche Aufwendungen finanzwirksam"/>
+ <account type="13" name="Außerordentliche Aufwendungen nicht finanzwirksam"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="02. Entnahmen aus Gewinnrücklagen">
+ <account type="16" name="Entnahmen aus satzungsmäßigen Rücklagen"/>
+ <account type="16" name="Entnahmen aus der gesetzlichen Rücklage"/>
+ <account type="16" name="Entnahmen aus anderen Gewinnrücklagen"/>
+ <account type="16" name="Entnahmen aus der Rücklage für eigene Anteile"/>
+ <account type="16" name="Einstellungen in die Kapitalrücklage nach den Vorschriften über die vereinfachte Kapitalherabsetzung"/>
+ <account type="16" name="Erträge aus Kapitalherabsetzung"/>
+ </account>
+ <account type="16" name="01. Gewinn-/Verlustvortrag nach Verwendung">
+ <account type="16" name="Gewinnvortrag nach Verwendung"/>
+ <account type="16" name="Gewinnvortrag 40% Vorbelastung"/>
+ <account type="16" name="Entnahmen aus der Kapitalrücklage"/>
+ <account type="16" name="Gewinnvortrag 0% Vorbelastung (steuerliches Einlagekonto)"/>
+ <account type="16" name="Verlustvortrag nach Verwendung"/>
+ <account type="16" name="Gewinnvortrag 0% Vorbelastung (EK02)"/>
+ </account>
+ <account type="16" name="03. Einstellungen in Gewinnrücklagen">
+ <account type="16" name="Vorabausschüttung"/>
+ <account type="16" name="Einstellungen in die gesetzliche Rücklage"/>
+ <account type="16" name="Einstellungen in satzungsmäßige Rücklagen"/>
+ <account type="16" name="Einstellungen in die Rücklage für eigene Anteile"/>
+ <account type="16" name="Einstellungen in andere Gewinnrücklagen"/>
+ <account type="16" name="Aufwendungen/Erträge aus Umrechnungsdifferenzen"/>
+ <account type="16" name="Vortrag auf neue Rechnung (GuV)"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Erlöse a. Verkäufen Finanzanlagen"/>
+ <account type="12" name="Erträge aus dem Abgang von Gegenständen des Umlaufvermögens (außer Vorräten) 100%/50% steuerfrei"/>
+ <account type="12" name="Sachbezüge 16% USt"/>
+ <account type="12" name="Erträge aus der Auflösung von Sonderposten mit Rücklageanteil (steuerfreie Rücklagen)"/>
+ <account type="12" name="Erlöse Verkäufe immat.Vermögensgegenst"/>
+ <account type="12" name="Steuerfreie Erträge aus der Auflösung von Sonderposten mit Rücklageanteil"/>
+ <account type="12" name="Investitionszuschüsse"/>
+ <account type="12" name="Anlagenabgänge Finanzanlagen 100 %/50 % steuerfrei"/>
+ <account type="12" name="Verrechnete sonstige Sachbezüge ohne Umsatzsteuer"/>
+ <account type="12" name="Erträge aus Zuschreibungen des Sachanlagevermögen"/>
+ <account type="12" name="Erträge aus abgeschriebenen Forderungen"/>
+ <account type="12" name="Erträge aus der Auflösung von Sonderposten mit Rücklageanteil nach 52 Abs. 16 EStG"/>
+ <account type="12" name="Grundstückserträge"/>
+ <account type="12" name="Abgänge Finanzanlagen"/>
+ <account type="12" name="Verrechnete sonstige Sachbezüge"/>
+ <account type="12" name="Erträge aus Abgang von Gegenständen des Anlagevermögens"/>
+ <account type="12" name="Versicherungsentschädigungen"/>
+ <account type="12" name="Erlöse Sachanlageverkäufe"/>
+ <account type="12" name="Erträge aus der Auflösung von Sonderposten mit Rücklageanteil (aus der Währungsumstellung auf den Euro)"/>
+ <account type="12" name="Erträge aus der Auflösung von Sonderposten mit Rücklageanteil (Sonderabschreibungen)"/>
+ <account type="12" name="Erträge aus Zuschreibungen des Finanzanlagevermögens"/>
+ <account type="12" name="Erträge aus der Auflösung von Rückstellungen"/>
+ <account type="12" name="Periodenfremde Erträge"/>
+ <account type="12" name="Verrechnete sonstige Sachbezüge 16% USt"/>
+ <account type="12" name="Sonstige steuerfreie Betriebseinnahmen"/>
+ <account type="12" name="Erträge aus Zuschreibungen des anderen Anlagevermögens 100 %/50 % steuerfrei"/>
+ <account type="12" name="Investitionszulagen"/>
+ <account type="12" name="Erlöse Sachanlageverkäufe steuerfrei § 4 Nr. 1b"/>
+ <account type="12" name="Erlöse Sachanlageverkäufe steuerfrei § 4 Nr. 1a"/>
+ <account type="12" name="Erträge aus der steuerlich niedrigeren Bewertung von Verbindlichkeiten"/>
+ <account type="12" name="Sachbezüge 7% USt"/>
+ <account type="12" name="Erträge aus Zuschreibungen des immateriellen Anlagevermög."/>
+ <account type="12" name="Verrechnete sonstige Sachbezüge (keine Waren)"/>
+ <account type="12" name="Erträge aus dem Abgang von Gegenständen des Umlaufvermögens außer Vorräten"/>
+ <account type="12" name="Anlagenabgänge Sachanlagen"/>
+ <account type="12" name="Erträge aus Zuschreibungen des Umlaufvermögens 100 % /50 % steuerfrei"/>
+ <account type="12" name="Erlöse aus Verkäufen des Anlagevermögens 16% USt"/>
+ <account type="12" name="Erträge aus der Auflösung von Sonderposten mit Rücklageanteil (Existenzgründerrücklage)"/>
+ <account type="12" name="Erträge aus der Veräußerung von Anteilen an Kapitalgesellschaften 100 %/50 % steuerfrei"/>
+ <account type="12" name="Erträge aus Zuschreibungen des Finanzanlagevermögens 100 %/50 % steuerfrei"/>
+ <account type="12" name="Erträge aus der Auflösung von Sonderposten mit Rücklageanteil (Ansparabschreibungen)"/>
+ <account type="12" name="Erträge aus Kursdifferenzen">
+ <account type="12" name="Erträge Bewertung Finanzmittelfonds"/>
+ </account>
+ <account type="12" name="Erträge aus der Herabsetzung der Pauschalwertberichtigung zu Forderungen"/>
+ <account type="12" name="Anlagenabgänge immaterielle Vermögensgegenstände"/>
+ <account type="12" name="Erträge aus der steuerlich niedrigeren Bewertung von Rückstellungen"/>
+ <account type="12" name="Erträge aus der Herabsetzung der Einzelwertberichtigung zu Forderungen"/>
+ <account type="12" name="Erlöse aus Verkäufen Finanzanlagen 100 %/50 % steuerfrei"/>
+ <account type="12" name="Erträge aus Zuschreibungen des Umlaufvermögens außer Vorräten"/>
+ <account type="12" name="Sonstige betriebliche Erträge">
+ <account type="12" name="Sonstige betriebl. regelm. Erträge"/>
+ <account type="12" name="Sonstige Erträge betriebl., regelm. 16%"/>
+ <account type="12" name="Sonstige Erträge unregelmäßig"/>
+ <account type="12" name="Sonstige betriebsfr.regelm. Erträge"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="b) auf Vermögensgegenstände des Umlaufvermögens">
+ <account type="13" name="Abschreibung auf Vermögensgegenstände des Umlaufvermögens">
+ <account type="13" name="Vorwegnahme künftiger Wertschwankungen im Umlaufvermögen"/>
+ <account type="13" name="Abschreibungen auf Umlaufvermögen, steuerrechtlich bedingt"/>
+ </account>
+ <account type="13" name="Forderungsverluste">
+ <account type="13" name="Forderungsverluste 7% USt"/>
+ <account type="13" name="Forderungsverluste 16% USt"/>
+ </account>
+ </account>
+ <account type="13" name="a) auf immaterielle Vermögensgegenstände des Anlagevermögens und Sachanlagen">
+ <account type="13" name="Abschreibungen auf Aufwendungen für die Währungsumstellung auf den Euro"/>
+ <account type="13" name="Abschreibungen auf immaterielle Vermögensgegenstände">
+ <account type="13" name="Außerplanmäßige Abschreibungen auf immaterielle Vermögensgegenstände"/>
+ <account type="13" name="Abschreibungen auf den Geschäfts- oder Firmenwert"/>
+ </account>
+ <account type="13" name="Sofortabschreibungen geringwertiger Wirtschaftsgüter">
+ <account type="13" name="Abschreibungen auf aktivierte geringwertige Wirtschaftsgüter"/>
+ <account type="13" name="Außerplanmäßige Abschreibungen auf aktivierte geringwertige Wirtschaftsgüter"/>
+ </account>
+ <account type="13" name="Abschreibungen auf das Anlagevermögen">
+ <account type="13" name="Sonderabschreibungen nach 7g Abs. 1 und 2 EStG (fr Kfz)"/>
+ <account type="13" name="Absetzung für außergewöhnliche technische und wirtschaftliche Abnutzung sonstiger Wirtschaftsgüter"/>
+ <account type="13" name="Kaufleasing"/>
+ <account type="13" name="Abschreibungen auf Kfz"/>
+ <account type="13" name="Abschreibungen auf Gebäude"/>
+ <account type="13" name="Absetzung für außergewöhnliche technische und wirtschaftliche Abnutzung der Kfz"/>
+ <account type="13" name="Außerplanmäßige Abschreibungen auf Sachanlagen"/>
+ <account type="13" name="Sonderabschreibungen nach 7g Abs. 1 und 2 EStG (ohne Kfz)"/>
+ <account type="13" name="Absetzung für außergewöhnliche technische und wirtschaftliche Abnutzung der Gebäude"/>
+ <account type="13" name="Abschreibungen auf Sachanlagen aufgrund steuerlicher Sondervorschriften"/>
+ </account>
+ <account type="13" name="Abschreibungen auf Aufwendungen für die Ingangsetzung und Erweiterung des Geschäftsbetriebs"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Gewerbeertragsteuer"/>
+ <account type="12" name="Steuererstattungen Vorjahre für Steuern vom Einkommen und Ertrag"/>
+ <account type="13" name="Anrechenbarer Solidaritätszuschlag auf Kapitelertragsteuer 20%"/>
+ <account type="13" name="Kapitalertragsteuer 25%"/>
+ <account type="13" name="Steuernachzahlungen Vorjahre für Steuern vom Einkommen und Ertrag"/>
+ <account type="13" name="Solidaritätszuschlag für Vorjahre"/>
+ <account type="13" name="Solidaritätszuschlag"/>
+ <account type="13" name="Kapitalertragsteuer 20%"/>
+ <account type="13" name="Gewerbesteuer"/>
+ <account type="12" name="Solidaritätszuschlagerstattungen für Vorjahre"/>
+ <account type="13" name="Zinsabschlagsteuer"/>
+ <account type="12" name="Erträge aus der Auflösung von Rückstellungen für Steuern vom Einkommen und Ertrag"/>
+ <account type="13" name="Körperschaftsteuer">
+ <account type="13" name="Körperschaftsteuer für Vorjahre"/>
+ <account type="12" name="Körperschaftsteuererstattung Vorjahre"/>
+ </account>
+ <account type="13" name="Anrechenbarer Solidaritätszuschlag auf Zinsabschlagsteuer"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Abschreibungen auf Finanzanlagen">
+ <account type="13" name="Abschreibungen auf Wertpapiere des Umlaufvermögens 100% / 50% nicht abzugsfähig"/>
+ <account type="13" name="Abschreibungen aufgrund von Verlustanteilen an Mitunternehmerschaften § 8 GewStG"/>
+ <account type="13" name="Abschreibungen auf Finanzanlagen aufgrund steuerlicher Sondervorschriften"/>
+ <account type="13" name="Abschreibungen auf Finanzanlagen auf Grund steuerlicher Sondervorschriften 100% / 50% nicht abzugsfähig"/>
+ <account type="13" name="Vorwegnahme künfiger Wertschwankungen bei Wertpapieren des Umlaufvermögens"/>
+ <account type="13" name="Abschreibungen auf Wertpapiere des Umlaufvermögens"/>
+ <account type="13" name="Abschreibungen auf Finanzanlagen 100% / 50% nicht abzugsfähig"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Andere aktivierte Eigenleistungen"/>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="C. Verbindlichkeiten"/>
+ <account type="10" name="D. Rechnungsabgrenzungsposten Fremdkapital">
+ <account type="10" name="Passive Rechnungsabgrenzung"/>
+ <account type="10" name="Abgrenzungen zur unterjährigen Kostenverrechnung für BWA"/>
+ </account>
+ <account type="10" name="A. Eigenkapital">
+ <account type="10" name="a) Personengesellschaft">
+ <account type="10" name="IV. Privat Teilhafter">
+ <account type="10" name="Unentgeltliche Wertabgaben"/>
+ <account type="10" name="Zuwendungen, Spenden -79"/>
+ <account type="10" name="Grundstücksaufwand"/>
+ <account type="10" name="Privatsteuern"/>
+ <account type="10" name="Sonderausgaben unbeschränkt abzugsfähig"/>
+ <account type="10" name="Privateinlagen"/>
+ <account type="10" name="Außergewöhnliche Belastungen"/>
+ <account type="10" name="Privatentnahmen allgemein"/>
+ <account type="10" name="Grundstücksertrag"/>
+ <account type="10" name="Sonderausgaben beschränkt abzugsfähig"/>
+ </account>
+ <account type="10" name="II. Kapital / Teilhafter">
+ <account type="10" name="(zur freien Verfügung)"/>
+ <account type="10" name="Gesellschafter-Darlehen"/>
+ <account type="10" name="Kommandit-Kapital"/>
+ <account type="10" name="Verlustausgleichskonto"/>
+ </account>
+ <account type="10" name="I. Kapital / Vollhafter / Einzelunternehmer">
+ <account type="10" name="Variables Kapital"/>
+ <account type="10" name="(zur freien Verfügung)"/>
+ <account type="10" name="Gesellschafter-Darlehen"/>
+ <account type="10" name="Festkapital"/>
+ </account>
+ <account type="10" name="III. Privat Vollhafter/Einzelunternehmer">
+ <account type="10" name="Privateinlagen"/>
+ <account type="10" name="Grundstücksaufwand (Umsatzsteuerschlüssel möglich)"/>
+ <account type="10" name="Privatentnahmen allgemein"/>
+ <account type="10" name="Außergewöhnliche Belastungen"/>
+ <account type="10" name="Sonderausgaben unbeschränkt abzugsfähig"/>
+ <account type="10" name="Grundstücksertrag"/>
+ <account type="10" name="Zuwendungen, Spenden -79"/>
+ <account type="10" name="Grundstücksaufwand"/>
+ <account type="10" name="Grundstücksertrag (Umsatzsteuerschlüssel möglich)"/>
+ <account type="10" name="Sonderausgaben beschränkt abzugsfähig"/>
+ <account type="10" name="Unentgeltliche Wertabgaben"/>
+ <account type="10" name="Privatsteuern"/>
+ </account>
+ </account>
+ <account type="10" name="c) alle">
+ <account type="10" name="I. Gewinnrücklagen">
+ <account type="10" name="02. Rücklage für eigene Anteile"/>
+ <account type="10" name="03. Satzungsmäßige Rücklagen">
+ <account type="10" name="Satzungsmäßige Rücklagen 0% Vorbelastung (steuerliches Einlagekonto)"/>
+ <account type="10" name="Satzungsmäßige Rücklagen 40% Vorbelastung"/>
+ <account type="10" name="Satzungsmäßige Rücklagen 0% Vorbelastung (EK02)"/>
+ </account>
+ <account type="10" name="04. Andere Gewinnrücklagen">
+ <account type="10" name="Andere Gewinnrücklagen 0% Vorbelastung (steuerliches Einlagekonto)"/>
+ <account type="10" name="Eigenkapitalanteil von Wertaufholungen"/>
+ <account type="10" name="Andere Gewinnrücklagen 40% Vorbelastung"/>
+ <account type="10" name="Andere Gewinnrücklagen 0% Vorbelastung (EK02)"/>
+ </account>
+ <account type="10" name="01. Gesetzliche Rücklage">
+ <account type="10" name="Gesetzliche Rücklage 0% Vorbelastung (EK02)"/>
+ <account type="10" name="Gesetzliche Rücklage 0% Vorbelastung (steuerliches Einlagekonto)"/>
+ <account type="10" name="Gesetzliche Rücklage 40% Vorbelastung"/>
+ </account>
+ </account>
+ <account type="10" name="II. Gewinnvortrag/Verlustvortrag vor Verwendung">
+ <account type="10" name="Vortrag auf neue Rechnung (Bilanz)"/>
+ <account type="10" name="Gewinnvortrag 0% Vorbelastung (EK02)"/>
+ <account type="10" name="Verlustvortrag vor Verwendung"/>
+ <account type="10" name="Gewinnvortrag 0% Vorbelastung (steuerliches Einlagekonto)"/>
+ <account type="10" name="Gewinnvortrag vor Verwendung"/>
+ <account type="10" name="Gewinnvortrag 40% Vorbelastung"/>
+ </account>
+ <account type="10" name="III. Sonderposten mit Rücklageanteil">
+ <account type="10" name="Sonderposten mit Rücklageanteil, steuerfreie Rücklagen">
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 82d EStDV"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 14 BerlinFG"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 4d EStG"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil für Förderung nach § 3 ZonenRFG/§ 4-6 FördergebietsG"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil, Sonderabschreibungen"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 7d EStG"/>
+ <account type="10" name="Sonderposten für Zuschüsse und Zulagen"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 82e EStDV"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 80 EStDV"/>
+ <account type="10" name="Sonderposten mit Rücklagenanteil nach § 1 EntwLStG"/>
+ <account type="10" name="Sonderposten mit Rücklagenanteil nach § 6b EStG"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 7g Abs. 1 EStG"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 81 EStDV"/>
+ <account type="10" name="Sonderposten mit Rücklagenanteil nach § 6d EStG"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 82a EStDV"/>
+ <account type="10" name="Sonderposten mit Rücklagenanteil nach Abschnitt 35 EStR"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 7g Abs. 3, 7 EStG"/>
+ <account type="10" name="Sonderposten aus der Währungsumstellung auf den Euro"/>
+ <account type="10" name="Sonderposten mit Rücklageanteil nach § 79 EStDV"/>
+ </account>
+ </account>
+ <account type="10" name="IV. Jahresüberschuß/Jahresfehlbetrag"/>
+ </account>
+ <account type="10" name="b) Kapitalgesellschaft">
+ <account type="10" name="II. Kapitalrücklage">
+ <account type="10" name="Kapitalrücklage">
+ <account type="10" name="Kapitalrücklage durch Zuzahlungen gegen Gewährung eines Vorzugs für Anteile"/>
+ <account type="10" name="Kapitalrücklage durch Ausgabe von Anteilen über Nennbetrag"/>
+ <account type="10" name="Kapitalrücklage durch Ausgabe von Schuldverschreibungen für Wandlungsrechte und Optionsrechte zum Erwerb von Anteilen"/>
+ <account type="10" name="Eingefordertes Nachschusskapital"/>
+ <account type="10" name="Andere Zuzahlungen in das Eigenkapital"/>
+ </account>
+ </account>
+ <account type="10" name="I. Gezeichnetes Kapital">
+ <account type="10" name="Gezeichnetes Kapital"/>
+ <account type="10" name="Ausstehende Einlagen auf das gezeichnete Kapital, nicht eingefordert"/>
+ </account>
+ </account>
+ </account>
+ <account type="10" name="B. Rückstellungen">
+ <account type="10" name="02. Steuerrückstellungen">
+ <account type="10" name="Körperschaftsteuerrückstellung"/>
+ <account type="10" name="Gewerbesteuerrückstellung"/>
+ <account type="10" name="Rückstellungen für latente Steuern"/>
+ <account type="10" name="Vermögensteuerrückstellung"/>
+ </account>
+ <account type="10" name="03. Sonstige Rückstellungen">
+ <account type="10" name="Rückstellungen für Gewährleistung"/>
+ <account type="10" name="Rückstellungen für Abraum- und Abfallbeseitigung"/>
+ <account type="10" name="Rückstellungen für unterlassene Aufwendungen für Instandhaltung, Nachholung in den ersten drei Monaten"/>
+ <account type="10" name="Rückstellungen für drohende Verluste aus schwebenden Geschäften"/>
+ <account type="10" name="Rückstellungen für unterlassene Aufwendungen für Instandhaltung, Nachholung innerhalb des 4. bis 12. Monats"/>
+ <account type="10" name="Rückstellungen für Umweltschutz"/>
+ <account type="10" name="Rückstellungen für Abschluß- und Prüfungskosten"/>
+ <account type="10" name="Aufwandsrückstellungen gemäß § 249 Abs. 2 HGB"/>
+ </account>
+ <account type="10" name="01. Rückstellungen für Pensionen und ähnliche Verpflichtungen">
+ <account type="10" name="Rückstellungen für pensionsähnliche Verpflichtungen"/>
+ <account type="10" name="Pensionsrückstellungen"/>
+ </account>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="b) soziale Abgaben und Aufwendungen für Altersversorgung und Unterstützung">
+ <account type="13" name="Aufwendungen für Unterstützung"/>
+ <account type="13" name="Pauschale Steuer auf sonstige Bezüge"/>
+ <account type="13" name="Beiträge zur Berufsgenossenschaft"/>
+ <account type="13" name="Gesetzlich soziale Aufwendungen">
+ <account type="13" name="Gesetzliche soziale Aufwendungen für Mitunternehmer 15 EStG"/>
+ </account>
+ <account type="13" name="Sonstige soziale Abgaben"/>
+ <account type="13" name="Freiwillige soziale Aufwendungen lohnsteuerfrei"/>
+ <account type="13" name="Versorgungskassen"/>
+ <account type="13" name="- davon für Altersversorgung">
+ <account type="13" name="Pauschale Steuer für Versicherungen"/>
+ <account type="13" name="Aufwendungen für Altersversorgung für Mitunternehmer 15 EStG"/>
+ <account type="13" name="Aufwendungen für Altersversorgung"/>
+ </account>
+ </account>
+ <account type="13" name="a) Löhne und Gehälter">
+ <account type="13" name="Löhne"/>
+ <account type="13" name="Pauschale Steuer auf sonstige Bezüge"/>
+ <account type="13" name="Fahrtkostenerstattung Wohnung / Arbeitsstätte"/>
+ <account type="13" name="Aushilfslöhne"/>
+ <account type="13" name="Vermögenswirksame Leistungen"/>
+ <account type="13" name="Krankengeldzuschüsse"/>
+ <account type="13" name="Gehälter">
+ <account type="13" name="Tantiemen"/>
+ <account type="13" name="Geschäftsführergehälter"/>
+ <account type="13" name="Vergütung an angestellte Mitunternehmer 15 EStG"/>
+ <account type="13" name="Geschäftsführergehälter der GmbH-Gesellschafter"/>
+ </account>
+ <account type="13" name="Freiwillige soziale Aufwendungen, lohnsteuerpflichtig"/>
+ <account type="13" name="Pauschale Steuer für Aushilfen"/>
+ <account type="13" name="Ehegattengehalt"/>
+ <account type="13" name="Zuschüsse der Agenturen für Arbeit"/>
+ <account type="13" name="Bedienungsgelder"/>
+ </account>
+ </account>
+ <account type="16" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Saldenvorträge Debitoren"/>
+ <account type="16" name="Saldenvorträge Sachkonten"/>
+ <account type="16" name="Saldenvorträge Kreditoren"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/de_DE/studium.kmt b/kmymoney2/templates/de_DE/studium.kmt
new file mode 100644
index 0000000..baa1df3
--- /dev/null
+++ b/kmymoney2/templates/de_DE/studium.kmt
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/de_DE/acctchrt_studium.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Studium</title>
+ <shortdesc>Konten für Studentinnen und Studenten</shortdesc>
+ <longdesc>BAFöG, Studiengebühren</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Bildung">
+ <account type="13" name="Studiengebühren"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Kredite">
+ <account type="10" name="BAFöG"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="BAFöG"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/dk/Makefile.am b/kmymoney2/templates/dk/Makefile.am
new file mode 100644
index 0000000..6402842
--- /dev/null
+++ b/kmymoney2/templates/dk/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/dk
+
+template_DATA = homeown.kmt homeloan.kmt common.kmt car.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/dk/car.kmt b/kmymoney2/templates/dk/car.kmt
new file mode 100644
index 0000000..cbce52d
--- /dev/null
+++ b/kmymoney2/templates/dk/car.kmt
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/da/acctchrt_car.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Bilejer</title>
+ <shortdesc>Udgifter vedrørende bil</shortdesc>
+ <longdesc>Udgifter i forbindelse med at holde bil. Vedligehold, drift og skatter.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Bil">
+ <account type="13" name="Parking"/>
+ <account type="13" name="Benzin"/>
+ <account type="13" name="Reparation og vedligehold"/>
+ <account type="13" name="Vægtafgift"/>
+ </account>
+ <account type="13" name="Forsikring">
+ <account type="13" name="Bilforsikring"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/dk/common.kmt b/kmymoney2/templates/dk/common.kmt
new file mode 100644
index 0000000..c4ecdb6
--- /dev/null
+++ b/kmymoney2/templates/dk/common.kmt
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/da/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Basiskonti</title>
+ <shortdesc>En samling grundlæggende konti</shortdesc>
+ <longdesc>De fleste brugere kan have nytte af disse konti. Almindelige brugte konti er medtaget (check, lønkonto, kontant, kreditkort, indkomst og almindelige udgifter)</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Andre indtægter"/>
+ <account type="12" name="Modtagne gaver"/>
+ <account type="12" name="Løn"/>
+ <account type="12" name="Renteindtægter">
+ <account type="12" name="Andre renter"/>
+ <account type="12" name="Lønkontorenter"/>
+ <account type="12" name="Checkrenter"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Åbningssaldi"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Aktuelle aktiver">
+ <account type="1" name="Checkkonto"/>
+ <account type="3" name="Kontanter på lommen"/>
+ <account type="1" name="Lønkonto"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Underholdning">
+ <account type="13" name="Musik/film"/>
+ <account type="13" name="Rejser"/>
+ <account type="13" name="Fritid"/>
+ </account>
+ <account type="13" name="Bøger"/>
+ <account type="13" name="Cykel"/>
+ <account type="13" name="Restaurant"/>
+ <account type="13" name="Gaver"/>
+ <account type="13" name="Medicin"/>
+ <account type="13" name="Velgørenhed"/>
+ <account type="13" name="Offentlig transport"/>
+ <account type="13" name="Bankgebyrer"/>
+ <account type="13" name="Uddannelse"/>
+ <account type="13" name="Forsyning">
+ <account type="13" name="Vand"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Affald"/>
+ <account type="13" name="El"/>
+ </account>
+ <account type="13" name="Tøj"/>
+ <account type="13" name="Abonnementer"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Forsikring">
+ <account type="13" name="Indboforsikring"/>
+ <account type="13" name="Livsforsikring"/>
+ <account type="13" name="Sygesikring"/>
+ </account>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Justering"/>
+ <account type="13" name="Skatter/afgifter">
+ <account type="13" name="Kommune"/>
+ <account type="13" name="Stat"/>
+ <account type="13" name="Amt"/>
+ <account type="13" name="Andre skatter"/>
+ </account>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Tøjvask/rensning"/>
+ <account type="13" name="Diverse"/>
+ <account type="13" name="Husholdning"/>
+ <account type="13" name="Antenne"/>
+ <account type="13" name="Hobby"/>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Forventede udgifter">
+ <account type="4" name="Kreditkort"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/dk/homeloan.kmt b/kmymoney2/templates/dk/homeloan.kmt
new file mode 100644
index 0000000..66d9ea9
--- /dev/null
+++ b/kmymoney2/templates/dk/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/da/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Realkreditlån</title>
+ <shortdesc>Konti i forbindelse med realkreditlån og tilhørende renter</shortdesc>
+ <longdesc>Du vil have nytte af disse konti, hvis du har et realkreditlån.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Renter">
+ <account type="13" name="Realkreditrenter"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Lån">
+ <account type="10" name="Realkreditlån"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/dk/homeown.kmt b/kmymoney2/templates/dk/homeown.kmt
new file mode 100644
index 0000000..98d0c55
--- /dev/null
+++ b/kmymoney2/templates/dk/homeown.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/da/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Boligejer</title>
+ <shortdesc>Udgifter i forbindelse med at eje en bolig</shortdesc>
+ <longdesc>Du vil have nytte af disse konti, hvis du ejer en bolig. Konti til at holde øje med udgifter til boligen er medtaget (forsikring, skatter, vedligehold)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Skatter/afgifter">
+ <account type="13" name="Ejendomsskat"/>
+ </account>
+ <account type="13" name="Forsikring">
+ <account type="13" name="Husforsikring"/>
+ </account>
+ <account type="13" name="Fællesudgifter"/>
+ <account type="13" name="Vedligehold af bolig"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/el_GR/Makefile.am b/kmymoney2/templates/el_GR/Makefile.am
new file mode 100644
index 0000000..42268ea
--- /dev/null
+++ b/kmymoney2/templates/el_GR/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/el_GR
+
+template_DATA = common.kmt brokerage.kmt carloan.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/el_GR/brokerage.kmt b/kmymoney2/templates/el_GR/brokerage.kmt
new file mode 100644
index 0000000..2b9b8cc
--- /dev/null
+++ b/kmymoney2/templates/el_GR/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/el_GR/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Λογαριασμοί Επενδύσεων</title>
+ <shortdesc>Λογαριασμός Χρηματιστηριακής με τους κατάλληλους λογαριασμούς επενδύσεων (μετοχή, ομόλογο, αμοιβαίο κεφάλαιο, αμοιβαίο κεφάλαιο δείκτη, τόκοι, μέρισμα)</shortdesc>
+ <longdesc>Θα θέλατε να επιλέξετε αυτό το σύνολο λογαριασμών αν έχετε επενδύσεις (μετοχή, ομολογία, αμοιβαίο κεφάλαιο, αμοιβαίο κεφάλαιο δείκτη, τόκοι μέρισμα).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Προμήθειες"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Έσοδα από Τόκους"/>
+ <account type="12" name="Έσοδα από Μέρισμα">
+ <account type="12" name="Τόκοι Ομολόγου"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Έπενδύσεις">
+ <account type="7" name="Λογαριασμός Χρηματιστή"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/el_GR/carloan.kmt b/kmymoney2/templates/el_GR/carloan.kmt
new file mode 100644
index 0000000..fdd9bd5
--- /dev/null
+++ b/kmymoney2/templates/el_GR/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/el_GR/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Δάνειο Αυτοκινήτου</title>
+ <shortdesc>Λογαριασμοί δανείου για την αγορά αυτοκινήτου</shortdesc>
+ <longdesc>Επιλέξτε αυτούς τους λογαριασμούς αν έχετε πάρει δάνειο για αγορά αυτοκινήτου (δάνειο αυτοκινήτου, τόκοι δανείου).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Τόκοι">
+ <account type="13" name="Τόκοι δανείου αυτοκινήτου"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Δάνεια">
+ <account type="10" name="Δάνειο αυτοκινήτου"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/el_GR/common.kmt b/kmymoney2/templates/el_GR/common.kmt
new file mode 100644
index 0000000..21f6259
--- /dev/null
+++ b/kmymoney2/templates/el_GR/common.kmt
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/el_GR/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Συνήθεις Λογαριασμοί</title>
+ <shortdesc>Ένα βασικό σύνολο λογαριασμών που χρησιμοποιούνται συχνά</shortdesc>
+ <longdesc>Οι περισσότεροι χρήστες θα ήθελαν να επιλέξουν αυτούς τους λογαριασμούς. Περιλαμβάνουν τους πιό συχνά χρησιμοποιούμενους λογαριασμούς (Επιταγές, αποταμίευση, μετρητά, πιστωτική κάρτα, εισόδημα , συνήθεις δαπάνες)</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Αρχικά υπόλοιπα"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Τρέχων ενεργητικό">
+ <account type="1" name="Λογαριασμός όψεως"/>
+ <account type="3" name="Μετρητά"/>
+ <account type="1" name="Λογαριασμός ταμιευτηρίου"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Γεύματα"/>
+ <account type="13" name="Δημόσια Μέσα μεταφοράς"/>
+ <account type="13" name="Εκπαίδευση"/>
+ <account type="13" name="Κοινή ωφέλεια">
+ <account type="13" name="Γκάζι"/>
+ <account type="13" name="Αποκομιδή σκουπιδιών"/>
+ <account type="13" name="Νερό"/>
+ <account type="13" name="Ηλεκτρικό ρεύμα"/>
+ </account>
+ <account type="13" name="Συνδρομές"/>
+ <account type="13" name="Τηλέφωνο"/>
+ <account type="13" name="Διαδίκτυο"/>
+ <account type="13" name="Παντοπωλείο"/>
+ <account type="13" name="Διασκέδαση">
+ <account type="13" name="Ταξίδια"/>
+ <account type="13" name="Ψυχαγωγία"/>
+ <account type="13" name="Μουσική/Ταινίες"/>
+ </account>
+ <account type="13" name="Βιβλία"/>
+ <account type="13" name="Δώρα"/>
+ <account type="13" name="Ιατρικές δαπάνες"/>
+ <account type="13" name="Δωρεές"/>
+ <account type="13" name="Αυτοκίνητο">
+ <account type="13" name="Καύσιμα"/>
+ <account type="13" name="Συντήρηση"/>
+ <account type="13" name="Στάθμευση"/>
+ <account type="13" name="Τέλη"/>
+ </account>
+ <account type="13" name="Τραπεζικά έξοδα"/>
+ <account type="13" name="Ρούχα"/>
+ <account type="13" name="Εφοδιασμός"/>
+ <account type="13" name="Ασφάλιση">
+ <account type="13" name="Ασφάλεια αυτοκινήτου"/>
+ <account type="13" name="Ασφάλεια Ζωής"/>
+ <account type="13" name="Ασφάλεια υγείας"/>
+ </account>
+ <account type="13" name="Προσαρμογή"/>
+ <account type="13" name="Φόροι">
+ <account type="13" name="Δήμος"/>
+ <account type="13" name="Κοινωνική ασφάλιση"/>
+ <account type="13" name="Εφορία"/>
+ <account type="13" name="Ιατροφαρμακευτική περίθαλψη"/>
+ <account type="13" name="Διάφοροι φόροι"/>
+ </account>
+ <account type="13" name="Υπολογιστής"/>
+ <account type="13" name="Καθαριστήριο/Πλυντήριο"/>
+ <account type="13" name="Διάφορα"/>
+ <account type="13" name="Καλωδιακές υπηρεσίες"/>
+ <account type="13" name="Hobbies"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Άλλα έσοδα"/>
+ <account type="12" name="Δώρα που λάβαμε"/>
+ <account type="12" name="Μισθός"/>
+ <account type="12" name="Εισόδημα από τόκους">
+ <account type="12" name="Τόκοι λογαριασμού όψεως"/>
+ <account type="12" name="Άλλα έσοδα"/>
+ <account type="12" name="Τόκοι αποταμίευσης"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Λογαριασμοί πληρωτέοι">
+ <account type="4" name="Πιστωτική κάρτα"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/Makefile.am b/kmymoney2/templates/en_GB/Makefile.am
new file mode 100644
index 0000000..527a495
--- /dev/null
+++ b/kmymoney2/templates/en_GB/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/en_GB
+
+template_DATA = homeown.kmt full.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt default_accounts.kmt renter.kmt common.kmt spouseretire.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt checkbook.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt uk-vat.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/en_GB/brokerage.kmt b/kmymoney2/templates/en_GB/brokerage.kmt
new file mode 100644
index 0000000..b0835e9
--- /dev/null
+++ b/kmymoney2/templates/en_GB/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Investment Accounts</title>
+ <shortdesc>Brokerage account with related investment accounts (stock, bond, mutual fund, index fund, interest, dividend)</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have investments (stock, bond, mutual fund, index fund, interest, dividend).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Commissions"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividend Income"/>
+ <account type="12" name="Interest Income">
+ <account type="12" name="Bond Interest"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investments">
+ <account type="7" name="Brokerage Account"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/business.kmt b/kmymoney2/templates/en_GB/business.kmt
new file mode 100644
index 0000000..8a36f33
--- /dev/null
+++ b/kmymoney2/templates/en_GB/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Business Accounts</title>
+ <shortdesc>Full chart of accounts for a business.</shortdesc>
+ <longdesc>Users running a business want to select this instead of other choices. This includes all the accounts you need to run a most businesses, including Payables, Receivables, Income, and Expenses.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="Credit Card"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Retained Earnings"/>
+ <account type="16" name="Opening Balances"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Equipment Rental"/>
+ <account type="13" name="Miscellaneous"/>
+ <account type="13" name="Repairs">
+ <account type="13" name="Equipment Repairs"/>
+ <account type="13" name="Building Repairs"/>
+ <account type="13" name="Computer Repairs"/>
+ <account type="13" name="Janitorial Expenses"/>
+ </account>
+ <account type="13" name="Postage and Delivery"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Depreciation"/>
+ <account type="13" name="Office Supplies"/>
+ <account type="13" name="Professional Fees">
+ <account type="13" name="Legal Fees"/>
+ <account type="13" name="Accounting"/>
+ </account>
+ <account type="13" name="Printing and Reproduction"/>
+ <account type="13" name="Dining"/>
+ <account type="13" name="Dues and Subscriptions"/>
+ <account type="13" name="Licenses and Permits"/>
+ <account type="13" name="Cash Discounts"/>
+ <account type="13" name="Payroll Expenses"/>
+ <account type="13" name="Outside Services"/>
+ <account type="13" name="Adjustment"/>
+ <account type="13" name="Travel and Entertainment">
+ <account type="13" name="Meals"/>
+ <account type="13" name="Travel"/>
+ <account type="13" name="Entertainment"/>
+ </account>
+ <account type="13" name="Charity"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Repair and Maintenance"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Fees"/>
+ </account>
+ <account type="13" name="Rent"/>
+ <account type="13" name="Utilities">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Garbage collection"/>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Cell Phone"/>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Electric"/>
+ <account type="13" name="Water"/>
+ <account type="13" name="Phone"/>
+ </account>
+ <account type="13" name="Insurance">
+ <account type="13" name="Disability Insurance"/>
+ <account type="13" name="Workers Comp"/>
+ <account type="13" name="Liability Insurance"/>
+ </account>
+ <account type="13" name="Bank Service Charge"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Federal"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="Property"/>
+ <account type="13" name="Local"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="Other Tax"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="FUTA"/>
+ </account>
+ <account type="13" name="Books"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Interest Income"/>
+ <account type="12" name="Sales"/>
+ <account type="12" name="Other Income"/>
+ <account type="12" name="Reimbursed Expenses"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Savings Account"/>
+ <account type="3" name="Petty Cash"/>
+ <account type="1" name="Checking Account"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/carloan.kmt b/kmymoney2/templates/en_GB/carloan.kmt
new file mode 100644
index 0000000..f7205a8
--- /dev/null
+++ b/kmymoney2/templates/en_GB/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Car Loan</title>
+ <shortdesc>Accounts for car loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a car loan (car loan, car loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Vehicle Loan Interest"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Loans">
+ <account type="10" name="Vehicle Loan"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/cdmoneymkt.kmt b/kmymoney2/templates/en_GB/cdmoneymkt.kmt
new file mode 100644
index 0000000..b75658b
--- /dev/null
+++ b/kmymoney2/templates/en_GB/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD and Money Market</title>
+ <shortdesc>Accounts for CD and money market investments</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have CDs or money market accounts (CD, CD interest, money market, money market interest).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Interest Income">
+ <account type="12" name="CD Interest"/>
+ <account type="12" name="Money Market Interest"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Money Market"/>
+ <account type="1" name="Bank CD"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/checkbook.kmt b/kmymoney2/templates/en_GB/checkbook.kmt
new file mode 100644
index 0000000..f6660bf
--- /dev/null
+++ b/kmymoney2/templates/en_GB/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>A Simple Checkbook</title>
+ <shortdesc>The minimal set of accounts to use GnuCash.</shortdesc>
+ <longdesc>Use this if you just want to balance your checkbook. Later on, you can start tracking income and expenses in more detail if you feel the need.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Opening Balances"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Checking Account"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/childcare.kmt b/kmymoney2/templates/en_GB/childcare.kmt
new file mode 100644
index 0000000..669edbe
--- /dev/null
+++ b/kmymoney2/templates/en_GB/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Childcare Expenses</title>
+ <shortdesc>An account for tracking childcare costs</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have childcare expenses.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Childcare"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/common.kmt b/kmymoney2/templates/en_GB/common.kmt
new file mode 100644
index 0000000..bbe873d
--- /dev/null
+++ b/kmymoney2/templates/en_GB/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Common Accounts</title>
+ <shortdesc>A basic set of accounts most commonly used</shortdesc>
+ <longdesc>Most users will want to select this set of accounts. It includes most commonly used accounts (checking, savings, cash, credit card, income, common expenses).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Other Income"/>
+ <account type="12" name="Gifts Received"/>
+ <account type="12" name="Salary"/>
+ <account type="12" name="Interest Income">
+ <account type="12" name="Other Interest"/>
+ <account type="12" name="Savings Interest"/>
+ <account type="12" name="Checking Interest"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Opening Balances"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Current Assets">
+ <account type="1" name="Checking Account"/>
+ <account type="3" name="Cash in Wallet"/>
+ <account type="1" name="Savings Account"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Entertainment">
+ <account type="13" name="Music/Movies"/>
+ <account type="13" name="Travel"/>
+ <account type="13" name="Recreation"/>
+ </account>
+ <account type="13" name="Books"/>
+ <account type="13" name="Dining"/>
+ <account type="13" name="Gifts"/>
+ <account type="13" name="Medical Expenses"/>
+ <account type="13" name="Charity"/>
+ <account type="13" name="Public Transportation"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Repair and Maintenance"/>
+ <account type="13" name="Fees"/>
+ </account>
+ <account type="13" name="Bank Service Charge"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Utilities">
+ <account type="13" name="Water"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Garbage collection"/>
+ <account type="13" name="Electric"/>
+ </account>
+ <account type="13" name="Supplies"/>
+ <account type="13" name="Clothes"/>
+ <account type="13" name="Subscriptions"/>
+ <account type="13" name="Phone"/>
+ <account type="13" name="Insurance">
+ <account type="13" name="Auto Insurance"/>
+ <account type="13" name="Life Insurance"/>
+ <account type="13" name="Health Insurance"/>
+ </account>
+ <account type="13" name="Online Services"/>
+ <account type="13" name="Adjustment"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Social Security"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Federal"/>
+ <account type="13" name="Medicare"/>
+ <account type="13" name="Other Tax"/>
+ </account>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Laundry/Dry Cleaning"/>
+ <account type="13" name="Miscellaneous"/>
+ <account type="13" name="Groceries"/>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Hobbies"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Credit Card"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/default_accounts.kmt b/kmymoney2/templates/en_GB/default_accounts.kmt
new file mode 100644
index 0000000..65172dc
--- /dev/null
+++ b/kmymoney2/templates/en_GB/default_accounts.kmt
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 default</title>
+ <shortdesc></shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Bills" type="13">
+ <account name="Telephone" type="13"/>
+ <account name="Rent" type="13"/>
+ <account name="Electricity" type="13"/>
+ <account name="TV" type="13"/>
+ <account name="SKY" type="13"/>
+ <account name="Council Tax" type="13"/>
+ <account name="Fuel Oil" type="13"/>
+ <account name="Gas" type="13"/>
+ <account name="Mortgage Interest" type="13"/>
+ <account name="Water &amp; Sewage" type="13"/>
+ </account>
+ <account name="Bank Charges" type="13">
+ <account name="Interest Paid" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Service Charge" type="13"/>
+ </account>
+ <account name="Car" type="13">
+ <account name="Car Maintenance" type="13"/>
+ <account name="Petrol" type="13"/>
+ </account>
+ <account name="Cash Withdrawal" type="13"/>
+ <account name="Charity" type="13">
+ <account name="Covenants" type="13"/>
+ <account name="Donations" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Settlements" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Child Care" type="13"/>
+ <account name="Christmas" type="13"/>
+ <account name="Clothing" type="13"/>
+ <account name="Education" type="13">
+ <account name="Books" type="13"/>
+ <account name="Fees" type="13"/>
+ <account name="Tuition" type="13"/>
+ </account>
+ <account name="Food" type="13">
+ <account name="Dining Out" type="13"/>
+ <account name="Groceries" type="13"/>
+ </account>
+ <account name="Gardening" type="13"/>
+ <account name="Healthcare" type="13">
+ <account name="Dental" type="13"/>
+ <account name="Doctor" type="13"/>
+ <account name="Hospital" type="13"/>
+ <account name="Optician" type="13"/>
+ <account name="Prescriptions" type="13"/>
+ </account>
+ <account name="Holidays" type="13">
+ <account name="Accomodation" type="13"/>
+ <account name="Travel" type="13"/>
+ </account>
+ <account name="Household" type="13">
+ <account name="Furnishings" type="13"/>
+ </account>
+ <account name="Insurance" type="13">
+ <account name="Home and Contents" type="13"/>
+ <account name="Life" type="13"/>
+ <account name="Medical" type="13"/>
+ <account name="Motor" type="13"/>
+ </account>
+ <account name="Job Expense" type="13">
+ <account name="Non-Reimbursed" type="13"/>
+ <account name="Reimbursed" type="13"/>
+ </account>
+ <account name="Leisure" type="13">
+ <account name="Books &amp; Magazines" type="13"/>
+ <account name="Entertaining" type="13"/>
+ <account name="Films &amp; Video Rentals" type="13"/>
+ <account name="Sporting Events" type="13"/>
+ <account name="Sports Goods" type="13"/>
+ <account name="Tapes &amp; CDs" type="13"/>
+ <account name="Theatre &amp; Concerts etc" type="13"/>
+ <account name="Toys &amp; Games" type="13"/>
+ </account>
+ <account name="Loan" type="13">
+ <account name="Loan Interest" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Motor" type="13">
+ <account name="Fuel" type="13"/>
+ <account name="Loan" type="13"/>
+ <account name="Service" type="13"/>
+ </account>
+ <account name="Other Expense" type="13">
+ <account name="Unknown" type="13"/>
+ </account>
+ <account name="Pet Care" type="13">
+ <account name="Food" type="13"/>
+ <account name="Supplies" type="13"/>
+ <account name="Vet's Bills" type="13"/>
+ </account>
+ <account name="Recreation" type="13"/>
+ <account name="Taxes" type="13">
+ <flag name="Tax"/>
+ <account name="Foreign savings" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Income Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Interest" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Local Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Nat Ins" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other Invest" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Unit trust" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Utilities" type="13">
+ <account name="Electricity" type="13"/>
+ <account name="Gas" type="13"/>
+ <account name="Telephone" type="13"/>
+ <account name="Water" type="13"/>
+ </account>
+ </account>
+ <account name="" type="12">
+ <account name="Alimony" type="12"/>
+ <account name="Bonus" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Capital gains" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Child Benefit" type="12"/>
+ <account name="Div Income" type="12">
+ <flag name="Tax"/>
+ <account name="Ord dividend" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Stock dividend" type="12"/>
+ </account>
+ <account name="Employment" type="12">
+ <flag name="Tax"/>
+ <account name="Benefits" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Foreign" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Lump sums" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other employ" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Salary &amp; wages" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Gift Received" type="12"/>
+ <account name="Int Inc" type="12">
+ <flag name="Tax"/>
+ <account name="Bank Interest" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Gross" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Net" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other savings" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Invest. income" type="12">
+ <flag name="Tax"/>
+ <account name="Dividend" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Foreign" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other savings" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts#Capital" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts#Dist. rec'd" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts#Estate" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="UK other" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="UK other#Unit trusts" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Investment Income" type="12">
+ <flag name="Tax"/>
+ <account name="Capital Gains" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Dividends" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Interest" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Tax-Exempt Interest" type="12"/>
+ </account>
+ <account name="Nat. Savings" type="12">
+ <account name="Capital bonds" type="12"/>
+ <account name="Deposit bonds" type="12"/>
+ <account name="Income bonds" type="12"/>
+ <account name="Invest. account" type="12"/>
+ <account name="Ord. account" type="12"/>
+ </account>
+ <account name="Old Age Pension" type="12">
+ <flag name="Tax"/>
+ <account name="Employer" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="State" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Other Income" type="12">
+ <account name="Student loan" type="12"/>
+ <account name="Child Support" type="12"/>
+ <account name="Employee Share Option" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Gifts Received" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Loan Principal Received" type="12"/>
+ <account name="Lottery or Premium Bond Prizes" type="12"/>
+ <account name="Tax Refund" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Unemployment Benefit" type="12"/>
+ </account>
+ <account name="Retirement Income" type="12">
+ <flag name="Tax"/>
+ <account name="Pensions &amp; Annuities" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="State Pension Benefits" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Social security" type="12">
+ <account name="Industrial" type="12"/>
+ <account name="Invalid" type="12"/>
+ <account name="Widowed" type="12"/>
+ </account>
+ <account name="Wages &amp; Salary" type="12">
+ <flag name="Tax"/>
+ <account name="Bonus" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Commission" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Employer Pension Contributions" type="12"/>
+ <account name="Gross Pay" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Net Pay" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Overtime" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/eduloan.kmt b/kmymoney2/templates/en_GB/eduloan.kmt
new file mode 100644
index 0000000..2c7adc3
--- /dev/null
+++ b/kmymoney2/templates/en_GB/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Education Loan</title>
+ <shortdesc>Accounts for school loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have an educational loan (education loan, education loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Education Loan Interest"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Loans">
+ <account type="10" name="Education Loan"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/fixedassets.kmt b/kmymoney2/templates/en_GB/fixedassets.kmt
new file mode 100644
index 0000000..dc78f8c
--- /dev/null
+++ b/kmymoney2/templates/en_GB/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Fixed Assets</title>
+ <shortdesc>Accounts for tracking large fixed assets</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have large fixed assets (house, vehicle, vacation home, other assets).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Fixed Assets">
+ <account type="9" name="Vehicle"/>
+ <account type="9" name="Other Asset"/>
+ <account type="9" name="House"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/full.kmt b/kmymoney2/templates/en_GB/full.kmt
new file mode 100644
index 0000000..4cb3989
--- /dev/null
+++ b/kmymoney2/templates/en_GB/full.kmt
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_full.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Full Chart</title>
+ <shortdesc>Full chart of accounts contains all default accounts.</shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Interest Income">
+ <account type="12" name="Savings Interest"/>
+ <account type="12" name="Money Market Interest"/>
+ <account type="12" name="Checking Interest"/>
+ <account type="12" name="CD Interest"/>
+ <account type="12" name="Other Interest"/>
+ <account type="12" name="Bond Interest"/>
+ </account>
+ <account type="12" name="Other Income"/>
+ <account type="12" name="Gifts Received"/>
+ <account type="12" name="Dividend Income"/>
+ <account type="12" name="Salary (Spouse)"/>
+ <account type="12" name="Salary"/>
+ <account type="12" name="Bonus"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Line of Credit"/>
+ <account type="10" name="Loans">
+ <account type="10" name="Vehicle Loan"/>
+ <account type="10" name="Mortgage Loan"/>
+ <account type="10" name="Other Loan"/>
+ <account type="10" name="Education Loan"/>
+ </account>
+ <account type="4" name="Credit Card"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Commissions"/>
+ <account type="13" name="Clothes"/>
+ <account type="13" name="Adjustment"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Dining"/>
+ <account type="13" name="Supplies"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Repair and Maintenance"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Fees"/>
+ </account>
+ <account type="13" name="Entertainment">
+ <account type="13" name="Music/Movies"/>
+ <account type="13" name="Recreation"/>
+ <account type="13" name="Travel"/>
+ </account>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Childcare"/>
+ <account type="13" name="Laundry/Dry Cleaning"/>
+ <account type="13" name="Bank Service Charge"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Property Tax"/>
+ <account type="13" name="Other Tax"/>
+ <account type="13" name="Social Security"/>
+ <account type="13" name="Federal"/>
+ <account type="13" name="Medicare"/>
+ </account>
+ <account type="13" name="Insurance">
+ <account type="13" name="Home Insurance"/>
+ <account type="13" name="Life Insurance"/>
+ <account type="13" name="Auto Insurance"/>
+ <account type="13" name="Health Insurance"/>
+ <account type="13" name="Rental Insurance"/>
+ </account>
+ <account type="13" name="Charity"/>
+ <account type="13" name="Home Repair"/>
+ <account type="13" name="Groceries"/>
+ <account type="13" name="Online Services"/>
+ <account type="13" name="Rent"/>
+ <account type="13" name="Taxes (Spouse)">
+ <account type="13" name="Social Security"/>
+ <account type="13" name="Other Tax"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Medicare"/>
+ <account type="13" name="Federal"/>
+ </account>
+ <account type="13" name="Interest">
+ <account type="13" name="Mortgage Interest"/>
+ <account type="13" name="Other Interest"/>
+ <account type="13" name="Education Loan Interest"/>
+ <account type="13" name="Vehicle Loan Interest"/>
+ </account>
+ <account type="13" name="Miscellaneous"/>
+ <account type="13" name="Subscriptions"/>
+ <account type="13" name="Public Transportation"/>
+ <account type="13" name="Medical Expenses"/>
+ <account type="13" name="Hobbies"/>
+ <account type="13" name="Gifts"/>
+ <account type="13" name="Books"/>
+ <account type="13" name="Utilities">
+ <account type="13" name="Water"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Garbage collection"/>
+ <account type="13" name="Electric"/>
+ </account>
+ <account type="13" name="Phone"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Fixed Assets">
+ <account type="9" name="House"/>
+ <account type="9" name="Other Asset"/>
+ <account type="9" name="Vehicle"/>
+ </account>
+ <account type="9" name="Current Assets">
+ <account type="1" name="Bank CD"/>
+ <account type="1" name="Money Market"/>
+ <account type="3" name="Cash in Wallet"/>
+ <account type="1" name="Savings Account"/>
+ <account type="1" name="Checking Account"/>
+ </account>
+ <account type="9" name="Investments">
+ <account type="7" name="Retirement"/>
+ <account type="7" name="Brokerage Account"/>
+ <account type="7" name="Spouse Retirement"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Opening Balances"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/homeloan.kmt b/kmymoney2/templates/en_GB/homeloan.kmt
new file mode 100644
index 0000000..7f16a19
--- /dev/null
+++ b/kmymoney2/templates/en_GB/homeloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Home Mortgage Loan</title>
+ <shortdesc>Accounts for home loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a home loan (mortgage loan, mortgage interest).</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Mortgage Loan"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Mortgage Interest"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/homeown.kmt b/kmymoney2/templates/en_GB/homeown.kmt
new file mode 100644
index 0000000..f4ecbbd
--- /dev/null
+++ b/kmymoney2/templates/en_GB/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Homeowner Expenses</title>
+ <shortdesc>Expenses associated with owning a home</shortdesc>
+ <longdesc>You would want to select this set of accounts if you own a home. This set provides a group of accounts to track home expenses (insurance, taxes, home repair).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Insurance">
+ <account type="13" name="Home Insurance"/>
+ </account>
+ <account type="13" name="Taxes">
+ <account type="13" name="Property Tax"/>
+ </account>
+ <account type="13" name="Home Repair"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/otherloan.kmt b/kmymoney2/templates/en_GB/otherloan.kmt
new file mode 100644
index 0000000..b439dfc
--- /dev/null
+++ b/kmymoney2/templates/en_GB/otherloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Other Loans</title>
+ <shortdesc>Accounts for tracking other loans and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have something other than a home loan (other loan, other loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interest">
+ <account type="13" name="Other Interest"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ <account type="10" name="">
+ <account type="10" name="Other Loan"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/renter.kmt b/kmymoney2/templates/en_GB/renter.kmt
new file mode 100644
index 0000000..5f1a942
--- /dev/null
+++ b/kmymoney2/templates/en_GB/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Renter Expenses</title>
+ <shortdesc>Expenses associated with renting a home</shortdesc>
+ <longdesc>You would want to select this set of accounts if you rent a home or apartment (rent, renter's insurance).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Rent"/>
+ <account type="13" name="Insurance">
+ <account type="13" name="Rental Insurance"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/retiremt.kmt b/kmymoney2/templates/en_GB/retiremt.kmt
new file mode 100644
index 0000000..2e4fe13
--- /dev/null
+++ b/kmymoney2/templates/en_GB/retiremt.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Retirement Accounts</title>
+ <shortdesc>Retirement account with related investment subaccounts</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have retirement accounts (stock, bond, mutual fund, index fund).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="Retirement"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/spouseinc.kmt b/kmymoney2/templates/en_GB/spouseinc.kmt
new file mode 100644
index 0000000..0f0cc8a
--- /dev/null
+++ b/kmymoney2/templates/en_GB/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Spouse Income</title>
+ <shortdesc>Accounts for tracking spouse's income separately</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a working spouse (salary (spouse), taxes (spouse)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Salary (Spouse)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Taxes (Spouse)">
+ <account type="13" name="Social Security"/>
+ <account type="13" name="Medicare"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="Federal"/>
+ <account type="13" name="Other Tax"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/spouseretire.kmt b/kmymoney2/templates/en_GB/spouseretire.kmt
new file mode 100644
index 0000000..8e0cb7e
--- /dev/null
+++ b/kmymoney2/templates/en_GB/spouseretire.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Spouse Retirement Accounts</title>
+ <shortdesc>Retirement account with related investment accounts for spouse</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have investments in a spouse's name (stock, bond, mutual fund, index fund, interest, dividend).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="Spouse Retirement"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_GB/uk-vat.kmt b/kmymoney2/templates/en_GB/uk-vat.kmt
new file mode 100644
index 0000000..161e3a1
--- /dev/null
+++ b/kmymoney2/templates/en_GB/uk-vat.kmt
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/en_GB/uk-vat.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>UK VAT Accounts</title>
+ <shortdesc>A basic set of accounts for tracking VAT in the UK.</shortdesc>
+ <longdesc>A basic set of accounts for tracking VAT in the UK.</longdesc>
+ <accounts>
+ <account type="1" name="">
+ <account type="1" name="Current Account"/>
+ <account type="1" name="Reserve Account"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Depreciation"/>
+ <account type="13" name="VAT Purchases">
+ <account type="13" name="Telecoms"/>
+ <account type="13" name="Subscriptions"/>
+ <account type="13" name="Travel/Accom"/>
+ <account type="13" name="Sundries"/>
+ <account type="13" name="Software"/>
+ <account type="13" name="Office"/>
+ <account type="13" name="Bank Charges"/>
+ <account type="13" name="EEC Reverse VAT"/>
+ <account type="13" name="Accountant"/>
+ </account>
+ <account type="13" name="Other non-VAT expenses"/>
+ <account type="13" name="Emoulements">
+ <account type="13" name="Employees">
+ <account type="13" name="NICs"/>
+ <account type="13" name="Net Salaries"/>
+ <account type="13" name="Stakeholder Contributions"/>
+ <account type="13" name="Income Tax"/>
+ </account>
+ <account type="13" name="Director's Fees"/>
+ <account type="13" name="Employer's NICs"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Director's Loan"/>
+ <account type="16" name="Opening Balances"/>
+ <account type="16" name="Grants"/>
+ <account type="16" name="Dividends">
+ <account type="16" name="Shareholder Dividends 1"/>
+ <account type="16" name="Director's Dividends 2"/>
+ <account type="16" name="Director's Dividends 1"/>
+ </account>
+ <account type="16" name="Corporation Tax"/>
+ </account>
+ <account type="3" name=""/>
+ <account type="10" name="">
+ <account type="10" name="Other"/>
+ <account type="10" name="Owed Tax/NI"/>
+ <account type="10" name="Owed Fees"/>
+ <account type="10" name="Owed Corporation Tax"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Sales">
+ <account type="12" name="World"/>
+ <account type="12" name="UK"/>
+ <account type="12" name="EEC">
+ <account type="12" name="Goods"/>
+ <account type="12" name="Services"/>
+ </account>
+ </account>
+ <account type="12" name="Misc"/>
+ <account type="12" name="Interest"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Capital Equipment">
+ <account type="9" name="Computer Equipment"/>
+ <account type="9" name="EC Reverse VAT Purchase"/>
+ </account>
+ <account type="9" name="Other"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Input"/>
+ <account type="13" name="Output">
+ <account type="13" name="EC"/>
+ <account type="13" name="Sales"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/0.6-default_accounts.kmt b/kmymoney2/templates/en_US/0.6-default_accounts.kmt
new file mode 100644
index 0000000..6cd1825
--- /dev/null
+++ b/kmymoney2/templates/en_US/0.6-default_accounts.kmt
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Use 0.6 default</title>
+ <shortdesc>default from KMyMoney 0.6</shortdesc>
+ <longdesc>This group contains a lot of categories. </longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Bills" type="13">
+ <account name="Telephone" type="13"/>
+ <account name="Rent" type="13"/>
+ <account name="Electricity" type="13"/>
+ <account name="TV" type="13"/>
+ <account name="Local Taxes" type="13"/>
+ <account name="Fuel Oil" type="13"/>
+ <account name="Natural Gas" type="13"/>
+ <account name="Mortgage" type="13">
+ <flag name="Tax"/>
+ <account name="Interest" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Principle" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="PMI" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Water &amp; Sewage" type="13"/>
+ </account>
+ <account name="Bank Charges" type="13">
+ <account name="Interest Paid" type="13"/>
+ <account name="Service Charge" type="13"/>
+ </account>
+ <account name="Business" type="13">
+ <account name="Auto" type="13">
+ <account name="Fuel" type="13"/>
+ <account name="Service" type="13"/>
+ <account name="Insurance" type="13"/>
+ <account name="Lease" type="13"/>
+ <account name="Loan" type="13"/>
+ <account name="Registration" type="13"/>
+ </account>
+ <account name="Capital Goods" type="13"/>
+ <account name="Legal Expenses" type="13"/>
+ <account name="Taxes" type="13">
+ <account name="Federal Taxes" type="13"/>
+ <account name="State Taxes" type="13"/>
+ <account name="Local Taxes" type="13"/>
+ <account name="Social Security" type="13"/>
+ <account name="Property Taxes" type="13"/>
+ </account>
+ <account name="Travel" type="13">
+ <account name="Accomodations" type="13"/>
+ <account name="Fares" type="13"/>
+ <account name="Car Rental" type="13"/>
+ </account>
+ <account name="Office Rent" type="13"/>
+ <account name="Office Supplies" type="13"/>
+ <account name="Other" type="13"/>
+ <account name="Utilities" type="13">
+ <account name="Electricity" type="13"/>
+ <account name="Gas" type="13"/>
+ <account name="Telephone" type="13"/>
+ <account name="Water" type="13"/>
+ <account name="Sewer" type="13"/>
+ <account name="Garbage &amp; Recycling" type="13"/>
+ </account>
+ <account name="Wages &amp; Salary" type="13">
+ <account name="Benefits" type="13"/>
+ <account name="Workman's Comp" type="13"/>
+ </account>
+ </account>
+ <account name="Car" type="13">
+ <account name="Fuel" type="13"/>
+ <account name="Service" type="13"/>
+ <account name="Insurance" type="13"/>
+ <account name="Lease" type="13"/>
+ <account name="Loan" type="13"/>
+ <account name="Registration" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Cash Withdrawal" type="13"/>
+ <account name="Charity" type="13">
+ <account name="Donations" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Child Care" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Clothing" type="13"/>
+ <account name="Education" type="13">
+ <flag name="Tax"/>
+ <account name="Books" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Fees" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Tuition" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Loans" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Board" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Food" type="13">
+ <account name="Dining Out" type="13"/>
+ <account name="Groceries" type="13"/>
+ </account>
+ <account name="Gardening" type="13"/>
+ <account name="Gifts" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Healthcare" type="13">
+ <flag name="Tax"/>
+ <account name="Dental" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Doctor" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Hospital" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Optician" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Prescriptions" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Holidays" type="13">
+ <account name="Accomodation" type="13"/>
+ <account name="Travel" type="13"/>
+ </account>
+ <account name="Household" type="13">
+ <account name="Furnishings" type="13"/>
+ <account name="Repairs" type="13"/>
+ </account>
+ <account name="Insurance" type="13">
+ <account name="Home and Contents" type="13"/>
+ <account name="Life" type="13"/>
+ <account name="Medical" type="13"/>
+ <account name="Auto" type="13"/>
+ <account name="Disability" type="13"/>
+ </account>
+ <account name="Job Expense" type="13">
+ <account name="Non-Reimbursed" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Reimbursed" type="13"/>
+ </account>
+ <account name="Leisure" type="13">
+ <account name="Books &amp; Magazines" type="13"/>
+ <account name="Entertaining" type="13"/>
+ <account name="Films &amp; Video Rentals" type="13"/>
+ <account name="Hobbies" type="13"/>
+ <account name="Sporting Events" type="13"/>
+ <account name="Sports Goods" type="13"/>
+ <account name="Tapes &amp; CDs" type="13"/>
+ <account name="Theatre &amp; Concerts etc" type="13"/>
+ <account name="Toys &amp; Games" type="13"/>
+ </account>
+ <account name="Legal Fees" type="13"/>
+ <account name="Loan" type="13">
+ <flag name="Tax"/>
+ <account name="Loan Interest" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Motor" type="13">
+ <account name="Fuel" type="13"/>
+ <account name="Loan" type="13"/>
+ <account name="Service" type="13"/>
+ </account>
+ <account name="Other Expense" type="13">
+ <account name="Unknown" type="13"/>
+ </account>
+ <account name="Personal Care" type="13"/>
+ <account name="Pet Care" type="13">
+ <account name="Food" type="13"/>
+ <account name="Supplies" type="13"/>
+ <account name="Vet's Bills" type="13"/>
+ </account>
+ <account name="Recreation" type="13"/>
+ <account name="Retirement Accounts" type="13">
+ <flag name="Tax"/>
+ <account name="IRA Contributions" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="529 Plan Contributions" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="401(k)403(b) Plan Contributions" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Taxes" type="13">
+ <flag name="Tax"/>
+ <account name="Federal Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="State Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Local Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other Invest" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other Tax" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="Property Taxes" type="13">
+ <flag name="Tax"/>
+ </account>
+ <account name="AMT" type="13">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Utilities" type="13">
+ <account name="Electricity" type="13"/>
+ <account name="Gas" type="13"/>
+ <account name="Telephone" type="13"/>
+ <account name="Water" type="13"/>
+ <account name="Sewer" type="13"/>
+ <account name="Garbage &amp; Recycling" type="13"/>
+ </account>
+ </account>
+ <account name="" type="12">
+ <account name="Alimony" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Bonus" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Business" type="12">
+ <flag name="Tax"/>
+ <account name="Revenue" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Short-Term Capital gains" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Long-Term Capital gains" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Child Support" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Disability" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Div Income" type="12">
+ <flag name="Tax"/>
+ <account name="Ord dividend" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Stock dividend" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Employment" type="12">
+ <flag name="Tax"/>
+ <account name="Benefits" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Foreign" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Lump sums" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other employ" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Salary &amp; wages" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Gift Received" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Int Inc" type="12">
+ <flag name="Tax"/>
+ <account name="Bank Interest" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Gross" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Net" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other savings" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Invest. income" type="12">
+ <flag name="Tax"/>
+ <account name="1st option" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Dividend" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Foreign" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other savings" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts#Capital" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts#Dist. rec'd" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Other trusts#Estate" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Investment Income" type="12">
+ <flag name="Tax"/>
+ <account name="Short-Term Capital Gains" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Long-Term Capital Gains" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Dividends" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Interest" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Tax-Exempt Interest" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Pension" type="12">
+ <flag name="Tax"/>
+ <account name="Employer" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Other Income" type="12">
+ <flag name="Tax"/>
+ <account name="Student loan" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Child Support" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Employee Share Option" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Gifts Received" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Loan Principal Received" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Lottery or Premium Bond Prizes" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Tax Refund" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Unemployment Benefit" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Retirement Income" type="12">
+ <flag name="Tax"/>
+ <account name="Pensions &amp; Annuities" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="State Pension Benefits" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="401(k)/403(b) Distributions" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="IRA Distributions" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ <account name="Social Security Benefits" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Wages &amp; Salary" type="12">
+ <flag name="Tax"/>
+ <account name="Bonus" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Commission" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Employer Pension Contributions" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Gross Pay" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Net Pay" type="12">
+ <flag name="Tax"/>
+ </account>
+ <account name="Overtime" type="12">
+ <flag name="Tax"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/0.8-default_accounts.kmt b/kmymoney2/templates/en_US/0.8-default_accounts.kmt
new file mode 100644
index 0000000..4ef7746
--- /dev/null
+++ b/kmymoney2/templates/en_US/0.8-default_accounts.kmt
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Use 0.8 default</title>
+ <shortdesc>default from KMyMoney 0.8</shortdesc>
+ <longdesc>This was the default category group for most of the 0.7 and 0.8 series. This group contains a lot of categories.</longdesc>
+
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Employment" >
+ <account type="12" name="Benefits" />
+ <account type="12" name="Bonus" />
+ <account type="12" name="Other employment income" />
+ <account type="12" name="Pension" />
+ <account type="12" name="Wages &amp; Salary" />
+ </account>
+ <account type="12" name="Investment Income" >
+ <account type="12" name="Short-Term Capital Gains" />
+ <account type="12" name="Long-Term Capital Gains" />
+ <account type="12" name="Dividends" />
+ <account type="12" name="Interest" />
+ <account type="12" name="Tax-Exempt Interest" />
+ </account>
+ <account type="12" name="Banking" >
+ <account type="12" name="Interest Earned" />
+ <account type="12" name="Loan Principle Received" />
+ </account>
+ <account type="12" name="Other Income" >
+ <account type="12" name="Alimony" />
+ <account type="12" name="Child Support" />
+ <account type="12" name="Disability" />
+ <account type="12" name="Gifts Received" />
+ <account type="12" name="Lottery or Premium Bond Prizes" />
+ <account type="12" name="Tax Refund" />
+ <account type="12" name="Unemployment Benefit" />
+ </account>
+ <account type="12" name="Retirement Income" >
+ <account type="12" name="Pensions &amp; Annuities" />
+ <account type="12" name="State Pension Benefits" />
+ <account type="12" name="401(k)/403(b) Distributions" />
+ <account type="12" name="IRA Distributions" />
+ <account type="12" name="Social Security Benefits" />
+ </account>
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Bills &amp; monthly payments" >
+ <account type="13" name="Utilities" >
+ <account type="13" name="Electricity" />
+ <account type="13" name="Fuel Oil" />
+ <account type="13" name="Natural Gas" />
+ <account type="13" name="Water &amp; Sewage" />
+ <account type="13" name="Garbage &amp; Recycling" />
+ </account>
+ <account type="13" name="Telephone" >
+ <account type="13" name="Local" />
+ <account type="13" name="Long Distance" />
+ <account type="13" name="Wireless" />
+ </account>
+ <account type="13" name="Rent" />
+ <account type="13" name="Mortgage" >
+ <account type="13" name="Interest" />
+ <account type="13" name="Principle" />
+ <account type="13" name="PMI (Private Mortgage Insurance)" />
+ </account>
+ <account type="13" name="Cable / Satelite TV" />
+ <account type="13" name="Internet" />
+ </account>
+ <account type="13" name="Bank Charges" >
+ <account type="13" name="Interest Paid" />
+ <account type="13" name="Service Charges" />
+ <account type="13" name="Insufficient Funds fee" />
+ </account>
+ <account type="13" name="Cash Withdrawal" />
+ <account type="13" name="Child Care/Sitters" />
+ <account type="13" name="Clothing" />
+ <account type="13" name="Education" >
+ <account type="13" name="Books" />
+ <account type="13" name="Fees" />
+ <account type="13" name="Tuition" />
+ <account type="13" name="Loans" />
+ </account>
+ <account type="13" name="Food" >
+ <account type="13" name="Dining Out" />
+ <account type="13" name="Groceries" />
+ </account>
+ <account type="13" name="Home Maintainance" >
+ <account type="13" name="Repairs" />
+ <account type="13" name="Improvements" />
+ <account type="13" name="Yard &amp; Garden" />
+ </account>
+ <account type="13" name="Home Furnishing" >
+ <account type="13" name="Furniture" />
+ <account type="13" name="Decorating" />
+ </account>
+ <account type="13" name="Gifts" />
+ <account type="13" name="Healthcare" >
+ <account type="13" name="Dental" />
+ <account type="13" name="Doctor" />
+ <account type="13" name="Hospital" />
+ <account type="13" name="Prescriptions" />
+ <account type="13" name="Chiropractic" />
+ <account type="13" name="Other" />
+ </account>
+ <account type="13" name="Personal Care" />
+ <account type="13" name="Vacation &amp; Holiday" >
+ <account type="13" name="Accomodations" />
+ <account type="13" name="Travel" />
+ <account type="13" name="Other" />
+ <account type="13" name="Meals" />
+ </account>
+ <account type="13" name="Insurance" >
+ <account type="13" name="Home and Contents" />
+ <account type="13" name="Life" />
+ <account type="13" name="Medical" />
+ <account type="13" name="Auto" />
+ <account type="13" name="Disability" />
+ </account>
+ <account type="13" name="Job Expense" >
+ <account type="13" name="Non-Reimbursed" />
+ <account type="13" name="Reimbursed" />
+ </account>
+ <account type="13" name="Recreation &amp; Leisure" >
+ <account type="13" name="Entertainment" />
+ <account type="13" name="Hobbies" />
+ <account type="13" name="Sports" />
+ </account>
+ <account type="13" name="Legal Fees" />
+ <account type="13" name="Other Misc. Expenses" />
+ <account type="13" name="Pet Care" >
+ <account type="13" name="Food" />
+ <account type="13" name="Supplies" />
+ <account type="13" name="Vet's Bills" />
+ </account>
+ <account type="13" name="Retirement Accounts" >
+ <account type="13" name="IRA Contributions" />
+ <account type="13" name="529 Plan Contributions" />
+ <account type="13" name="401(k)403(b) Plan Contributions" />
+ </account>
+ <account type="13" name="Taxes" >
+ <account type="13" name="State" />
+ <account type="13" name="Federal" />
+ <account type="13" name="Medicare" />
+ <account type="13" name="Personal property taxes" />
+ <account type="13" name="Other taxes" />
+ <account type="13" name="Soc. Sec." />
+ <account type="13" name="EIC" />
+ </account>
+ <account type="13" name="Transportation" >
+ <account type="13" name="Car / Auto" >
+ <account type="13" name="Fuel" />
+ <account type="13" name="Service" />
+ <account type="13" name="Insurance" />
+ <account type="13" name="Lease" />
+ <account type="13" name="Loan" />
+ <account type="13" name="Registration" />
+ </account>
+ <account type="13" name="Public Transportation" />
+ </account>
+ <account type="13" name="Household" />
+ <account type="13" name="Charity" />
+ <account type="13" name="Accountant &amp; Tax Preparation" />
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/Base-Blank.kmt b/kmymoney2/templates/en_US/Base-Blank.kmt
new file mode 100644
index 0000000..272d593
--- /dev/null
+++ b/kmymoney2/templates/en_US/Base-Blank.kmt
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+<title>Base -Blank</title>
+ <shortdesc>No Categories</shortdesc>
+ <longdesc>Use this group if you plan on importing all your categories from another program or you want to create all of your categories from scratch.</longdesc>
+ <accounts>
+ <account type="12" name="" />
+ <account type="13" name="" />
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/Base-Detailed.kmt b/kmymoney2/templates/en_US/Base-Detailed.kmt
new file mode 100644
index 0000000..fdeb835
--- /dev/null
+++ b/kmymoney2/templates/en_US/Base-Detailed.kmt
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Base -Detail</title>
+ <shortdesc>A little bit more detail</shortdesc>
+ <longdesc> Use this group if you like to see more detail and do not want to take the time to create all of the categories yourself. You may wish to add some additional groups if you own a home, have kids, etc.</longdesc>
+
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Job" >
+ <account type="12" name="Bonus" />
+ <account type="12" name="Wages or Salary" />
+ </account>
+ <account type="12" name="Other income" />
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Food" >
+ <account type="13" name="Dining out" />
+ <account type="13" name="Groceries" />
+ </account>
+ <account type="13" name="Housing" >
+ <account type="13" name="Rent" />
+ <account type="13" name="Repairs and Maintenance" />
+ <account type="13" name="Furnishings" />
+ </account>
+ <account type="13" name="Miscellaneous/Other" >
+ <account type="13" name="Accountant/Tax Preparation" />
+ </account>
+ <account type="13" name="Health/Medical" >
+ <account type="13" name="Dental" />
+ <account type="13" name="Doctor" />
+ <account type="13" name="Hospital" />
+ <account type="13" name="Prescriptions" />
+ <account type="13" name="Chiropractic" />
+ <account type="13" name="Optometrist" />
+ <account type="13" name="Health Insurance" />
+ <account type="13" name="Disability Insurance" />
+ </account>
+ <account type="13" name="Transportation" >
+ <account type="13" name="Car/Auto" >
+ <account type="13" name="Fuel" />
+ <account type="13" name="Service/Repairs" />
+ <account type="13" name="Auto Insurance" />
+ <account type="13" name="Registration/Taxes" />
+ <account type="13" name="Maintenance" />
+ <account type="13" name="Payment" />
+ </account>
+ <account type="13" name="Public Transportation" />
+ </account>
+ <account type="13" name="Personal" >
+ <account type="13" name="Life Insurance" />
+ <account type="13" name="Education/School" />
+ <account type="13" name="Fitness/Gym" />
+ <account type="13" name="Appearance/Grooming" />
+ <account type="13" name="Miscellaneous/Other" />
+ <account type="13" name="Gifts" />
+ </account>
+ <account type="13" name="Recreation" >
+ <account type="13" name="Vacation" />
+ <account type="13" name="Entertainment" />
+ <account type="13" name="Hobbies" />
+ </account>
+ <account type="13" name="Utilities" >
+ <account type="13" name="Electricity" />
+ <account type="13" name="Water" />
+ <account type="13" name="Natural Gas" />
+ <account type="13" name="Phone" >
+ <account type="13" name="Wireless" />
+ <account type="13" name="Local" />
+ <account type="13" name="Long Distance" />
+ </account>
+ <account type="13" name="Cable/Satellite" />
+ <account type="13" name="Internet" />
+ <account type="13" name="Garbage/Recycling" />
+ </account>
+ <account type="13" name="Charity" />
+ <account type="13" name="Clothing" >
+ <account type="13" name="Cleaning/Laundry" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/Base-Simple.kmt b/kmymoney2/templates/en_US/Base-Simple.kmt
new file mode 100644
index 0000000..c57c9c5
--- /dev/null
+++ b/kmymoney2/templates/en_US/Base-Simple.kmt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+<title>Base -Simple</title>
+ <shortdesc>Small and simple set of categories</shortdesc>
+ <longdesc>If you just want to keep things as basic and easy as possible, you should choose this category group.</longdesc>
+
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Job" />
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Food" />
+ <account type="13" name="Housing" />
+ <account type="13" name="Miscellaneous/Other" />
+ <account type="13" name="Health/Medical" />
+ <account type="13" name="Transportation" />
+ <account type="13" name="Personal" />
+ <account type="13" name="Recreation" />
+ <account type="13" name="Utilities" />
+ <account type="13" name="Charity" />
+ <account type="13" name="Clothing" />
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/CMakeLists.txt b/kmymoney2/templates/en_US/CMakeLists.txt
new file mode 100644
index 0000000..553d99e
--- /dev/null
+++ b/kmymoney2/templates/en_US/CMakeLists.txt
@@ -0,0 +1,17 @@
+INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR} )
+
+
+########### install files ###############
+
+INSTALL(FILES old-default_accounts.kmt default_categories-template.kmt ScheduleC_business.kmt ScheduleE_rental-property.kmt
+ DESTINATION share/apps/kmymoney2/templates/en_US
+)
+
+
+
+#original Makefile.am contents follow:
+
+#templatedir=$(kde_datadir)/kmymoney2/templates/en_US
+#template_DATA = old-default_accounts.kmt default_categories-template.kmt ScheduleC_business.kmt ScheduleE_rental-property.kmt
+#
+#EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/en_US/House.kmt b/kmymoney2/templates/en_US/House.kmt
new file mode 100644
index 0000000..7e0d0b4
--- /dev/null
+++ b/kmymoney2/templates/en_US/House.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>House</title>
+ <shortdesc>For home owners</shortdesc>
+ <longdesc>Some categories you may want if you own a home or plan on buying a home.</longdesc>
+ <accounts>
+ <account type="12" name="" />
+ <account type="13" name="" >
+ <account type="13" name="Housing" >
+ <account type="13" name="Mortgage" />
+ <account type="13" name="Mortgage Insurance" />
+ <account type="13" name="Property taxes" />
+ <account type="13" name="Homeowners Insurance" />
+ <account type="13" name="Repairs and Maintenance" />
+ <account type="13" name="Yard and Garden" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/Makefile.am b/kmymoney2/templates/en_US/Makefile.am
new file mode 100644
index 0000000..84160d5
--- /dev/null
+++ b/kmymoney2/templates/en_US/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/en_US
+
+template_DATA = kids.kmt Pets.kmt Base-Blank.kmt ScheduleE_rental-property.kmt Retirement.kmt ScheduleC_business.kmt Base-Detailed.kmt ScheduleBandD.kmt ScheduleA_itemized-deductions.kmt Base-Simple.kmt ScheduleF_farming.kmt House.kmt 0.6-default_accounts.kmt 0.8-default_accounts.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/en_US/Pets.kmt b/kmymoney2/templates/en_US/Pets.kmt
new file mode 100644
index 0000000..c59f520
--- /dev/null
+++ b/kmymoney2/templates/en_US/Pets.kmt
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Pets</title>
+ <shortdesc>Categories for pets</shortdesc>
+ <longdesc>Some categories that can be used if you have a pet. Use with one of the base category groups.</longdesc>
+ <accounts>
+ <account type="12" name="" />
+ <account type="13" name="" >
+ <account type="13" name="Pets" >
+ <account type="13" name="Pet Food" />
+ <account type="13" name="Pet Supplies" />
+ <account type="13" name="Veterinary" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/Retirement.kmt b/kmymoney2/templates/en_US/Retirement.kmt
new file mode 100644
index 0000000..1fa2d45
--- /dev/null
+++ b/kmymoney2/templates/en_US/Retirement.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+<title>Retirement</title>
+ <shortdesc>Categories for retirement.</shortdesc>
+ <longdesc>If you are retired and receive retirement income this group contains various kinds of retirement income categories. Use it with one of the base category groups.</longdesc>
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Retirement" >
+ <account type="12" name="Pensions" />
+ <account type="12" name="State Pension Benefits" />
+ <account type="12" name="401(k)/403(b) Distributions" />
+ <account type="12" name="IRA Distributions" />
+ <account type="12" name="Social Security Benefits" />
+ <account type="12" name="Annuities" />
+ </account>
+ </account>
+ <account type="13" name="" />
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/ScheduleA_itemized-deductions.kmt b/kmymoney2/templates/en_US/ScheduleA_itemized-deductions.kmt
new file mode 100644
index 0000000..c5adbdf
--- /dev/null
+++ b/kmymoney2/templates/en_US/ScheduleA_itemized-deductions.kmt
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>ScheduleA Itemized Deductions</title>
+ <shortdesc>If you file an itemized tax return</shortdesc>
+ <longdesc>Use this group if you file an itemized tax return. This group contains categories that correspond to IRS Schedule A and will hopefully make preparing your taxes easier. Use it with one of the base category groups.</longdesc>
+ <accounts>
+ <account type="12" name="" >
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Housing" >
+ <account type="13" name="Mortgage or Rent" />
+ <account type="13" name="Property taxes" />
+ <account type="13" name="Mortgage Insurance" />
+ <account type="13" name="Mortgage Interest/Points" />
+ </account>
+ <account type="13" name="Miscellaneous/Other" >
+ <account type="13" name="Accountant/Tax Preparation" />
+ <account type="13" name="Casualty/Theft loss" />
+ <account type="13" name="Unreimbursed Employee Expenses" >
+ <account type="13" name="Safety Equipment" />
+ <account type="13" name="Tools/Supplies" />
+ <account type="13" name="Uniforms" />
+ <account type="13" name="Protective Clothing" />
+ <account type="13" name="Physical Exams" />
+ <account type="13" name="Dues" />
+ <account type="13" name="Subscriptions" />
+ <account type="13" name="job Search Costs" />
+ <account type="13" name="Business use of home" />
+ <account type="13" name="Educational Expenses" />
+ </account>
+ <account type="13" name="Taxes" >
+ <account type="13" name="Other Taxes" />
+ <account type="13" name="State and Local" />
+ </account>
+ </account>
+ <account type="13" name="Health/Medical" >
+ <account type="13" name="Dental" />
+ </account>
+ <account type="13" name="Transportation" >
+ <account type="13" name="Car/Auto" >
+ <account type="13" name="Registration/Taxes" />
+ </account>
+ </account>
+ <account type="13" name="Charity" >
+ <account type="13" name="Gifts by Cash/Check" />
+ <account type="13" name="Other (non-cash/check)" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/ScheduleBandD.kmt b/kmymoney2/templates/en_US/ScheduleBandD.kmt
new file mode 100644
index 0000000..8bf4f6a
--- /dev/null
+++ b/kmymoney2/templates/en_US/ScheduleBandD.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>ScheduleB and D</title>
+ <shortdesc>Categories from IRS Schedules B and D</shortdesc>
+ <longdesc>Use this group if you want some categories that correspond to IRS Schedules B and D for reporting Interest earned, Dividends, and Capital Gains and Losses. Use with one of the base category groups.</longdesc>
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Capital Gains" >
+ <account type="12" name="Long Term" />
+ <account type="12" name="Short Term" />
+ </account>
+ <account type="12" name="Interest Earned" />
+ <account type="12" name="Dividends" />
+ <account type="12" name="Foreign Accounts/Trusts" />
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Capital Losses" >
+ <account type="13" name="Long Term" />
+ <account type="13" name="Short Term" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/ScheduleC_business.kmt b/kmymoney2/templates/en_US/ScheduleC_business.kmt
new file mode 100644
index 0000000..edccca7
--- /dev/null
+++ b/kmymoney2/templates/en_US/ScheduleC_business.kmt
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>ScheduleC business</title>
+ <shortdesc>Categories from IRS Schedule C</shortdesc>
+ <longdesc>Use this group if you plan to use KMyMoney for a simple business or to track business expenses. This group contains categories that correspond to IRS Schedule C and will make preparing your taxes easier. Can be used alone or with one of the base category groups.</longdesc>
+
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Business" >
+ <account type="12" name="Revenue" />
+ <account type="12" name="Interest Income" />
+ <account type="12" name="Services Income" />
+ </account>
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Business" >
+ <account type="13" name="Auto" >
+ <account type="13" name="Fuel" />
+ <account type="13" name="Service" />
+ <account type="13" name="Insurance" />
+ <account type="13" name="Registration" />
+ </account>
+ <account type="13" name="Cost of Goods Sold" />
+ <account type="13" name="Legal And Professional" />
+ <account type="13" name="Taxes" >
+ <account type="13" name="Federal Taxes" />
+ <account type="13" name="State Taxes" />
+ <account type="13" name="Local Taxes" />
+ <account type="13" name="Social Security" />
+ <account type="13" name="Property Taxes" />
+ </account>
+ <account type="13" name="Travel, Meals, and Entertainment" >
+ <account type="13" name="Travel" />
+ <account type="13" name="Fares" />
+ <account type="13" name="Meals" />
+ </account>
+ <account type="13" name="Rent or Lease" >
+ <account type="13" name="Vehicles, Machinery, Equipment" />
+ <account type="13" name="Other Business Property" />
+ </account>
+ <account type="13" name="Supplies" >
+ <account type="13" name="Hardware" />
+ <account type="13" name="Software" />
+ <account type="13" name="Office" />
+ </account>
+ <account type="13" name="Other" />
+ <account type="13" name="Utilities" >
+ <account type="13" name="Electricity" />
+ <account type="13" name="Gas" />
+ <account type="13" name="Telephone/Internet/Fax" />
+ <account type="13" name="Water" />
+ <account type="13" name="Sewer" />
+ <account type="13" name="Garbage/Recycling" />
+ </account>
+ <account type="13" name="Wages/Salary" />
+ <account type="13" name="Advertising" />
+ <account type="13" name="Contract Labor" />
+ <account type="13" name="Commisions and Fees" />
+ <account type="13" name="Employee Benefit Programs" />
+ <account type="13" name="Insurance (other than Health)" />
+ <account type="13" name="Interest" >
+ <account type="13" name="Mortgage" />
+ <account type="13" name="Other" />
+ </account>
+ <account type="13" name="Pension and Profit-Sharing Plans" />
+ <account type="13" name="Repairs and Maintenance" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/ScheduleE_rental-property.kmt b/kmymoney2/templates/en_US/ScheduleE_rental-property.kmt
new file mode 100644
index 0000000..30ca08b
--- /dev/null
+++ b/kmymoney2/templates/en_US/ScheduleE_rental-property.kmt
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>ScheduleE rental property</title>
+ <shortdesc>Categories from IRS Schedule E</shortdesc>
+ <longdesc>Use this group if you own rental properties or receive royalties and are required to use IRS Schedule E</longdesc>
+
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Rental Income" >
+ <account type="12" name="Rent" />
+ <account type="12" name="Security Deposit" />
+ <account type="12" name="Late Fee" />
+ <account type="12" name="Damages Paid" />
+ <account type="12" name="Application Fee" />
+ <account type="12" name="Pet Fee" />
+ </account>
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Rental Expense" >
+ <account type="13" name="Advertising" />
+ <account type="13" name="Auto and Travel" />
+ <account type="13" name="Cleaning and Maintenance" />
+ <account type="13" name="Commissions" />
+ <account type="13" name="Property Insurance" />
+ <account type="13" name="Legal and Professional" />
+ <account type="13" name="Management Fees" >
+ <account type="13" name="Office Rent" />
+ </account>
+ <account type="13" name="Rental Mortgage Interest" />
+ <account type="13" name="Other Interest" />
+ <account type="13" name="Repairs" />
+ <account type="13" name="Supplies" />
+ <account type="13" name="Utilities" />
+ <account type="13" name="Other" >
+ <account type="13" name="Office Supplies" />
+ <account type="13" name="Postage" />
+ </account>
+ <account type="13" name="Property Taxes" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/ScheduleF_farming.kmt b/kmymoney2/templates/en_US/ScheduleF_farming.kmt
new file mode 100644
index 0000000..67a6065
--- /dev/null
+++ b/kmymoney2/templates/en_US/ScheduleF_farming.kmt
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+<title>ScheduleF farming</title>
+ <shortdesc>Categories from IRS Schedule F</shortdesc>
+ <longdesc>Use this group if you farm. The categories in this group correspond with IRS Schedule F which should make preparing your taxes easier.</longdesc>
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Farming" >
+ <account type="12" name="Sales of produced goods" />
+ <account type="12" name="Cooperative distributions" />
+ <account type="12" name="Agricultural program payments" />
+ <account type="12" name="Commodity Credit Corporation loans" />
+ <account type="12" name="Crop insurance proceeds/Crop disaster payments" />
+ <account type="12" name="Custom hire income" />
+ <account type="12" name="Other income" />
+ </account>
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Farming" >
+ <account type="13" name="Car and Truck" />
+ <account type="13" name="Chemicals" />
+ <account type="13" name="Conservation" />
+ <account type="13" name="Custom hire" />
+ <account type="13" name="Employee benefits" />
+ <account type="13" name="Feed" />
+ <account type="13" name="Fertilizers and Lime" />
+ <account type="13" name="Freight and Trucking" />
+ <account type="13" name="Fuel and Oil" />
+ <account type="13" name="Insurance" />
+ <account type="13" name="Mortgage" />
+ <account type="13" name="Hired Labor" />
+ <account type="13" name="Pension and profit sharing plans" />
+ <account type="13" name="Repairs and Maintenance" />
+ <account type="13" name="Seeds and Plants" />
+ <account type="13" name="Storage and Warehousing" />
+ <account type="13" name="Supplies" />
+ <account type="13" name="Taxes" />
+ <account type="13" name="Utilities" />
+ <account type="13" name="Veterinary, breeding, and medicine" />
+ <account type="13" name="Other" />
+ <account type="13" name="Rent or Lease" >
+ <account type="13" name="Vehicles, Macinery, Equipment" />
+ <account type="13" name="Other" />
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/en_US/kids.kmt b/kmymoney2/templates/en_US/kids.kmt
new file mode 100644
index 0000000..15bc677
--- /dev/null
+++ b/kmymoney2/templates/en_US/kids.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+<title>Kids</title>
+ <shortdesc>For those with kids</shortdesc>
+ <longdesc>If you have kids, this group has some categories related to kids. Use it with one of the base category groups.</longdesc>
+ <accounts>
+ <account type="12" name="" />
+ <account type="13" name="" >
+ <account type="13" name="Food" >
+ <account type="13" name="School Lunch" />
+ </account>
+ <account type="13" name="Personal" >
+ <account type="13" name="Kids" >
+ <account type="13" name="Education/School" />
+ <account type="13" name="Sports/Activities" />
+ <account type="13" name="Day Care" />
+ <account type="13" name="Baby Sitting" />
+ </account>
+ </account>
+ <account type="13" name="Clothing" >
+ <account type="13" name="Kids" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/Makefile.am b/kmymoney2/templates/es_AR/Makefile.am
new file mode 100644
index 0000000..2414c0c
--- /dev/null
+++ b/kmymoney2/templates/es_AR/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/es_AR
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt default_accounts.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/es_AR/brokerage.kmt b/kmymoney2/templates/es_AR/brokerage.kmt
new file mode 100644
index 0000000..c6910ed
--- /dev/null
+++ b/kmymoney2/templates/es_AR/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de Inversión</title>
+ <shortdesc>Cuenta de corredor de bolsa con las cuentas de inversiones asociadas</shortdesc>
+ <longdesc>Deberá escoger este juego de cuentas si tiene inversiones (acciones, bonos, fondos de inversión, fondos indexados, intereses, dividendos).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Comisiones"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Ingresos por dividendos"/>
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Intereses de bonos"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Cuenta de inversión"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/carloan.kmt b/kmymoney2/templates/es_AR/carloan.kmt
new file mode 100644
index 0000000..7f778f8
--- /dev/null
+++ b/kmymoney2/templates/es_AR/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo de automóvil</title>
+ <shortdesc>Cuentas para pago en cuotas de automóvil e intereses asociados</shortdesc>
+ <longdesc>Debería seleccionar este juego de cuentas si está pagando su automóvil en cuotas (cuotas de automóvil, intereses por cuotas de automóvil).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Intereses pago cuotas vehículo"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Vehículo a cuotas"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/cdmoneymkt.kmt b/kmymoney2/templates/es_AR/cdmoneymkt.kmt
new file mode 100644
index 0000000..39194ac
--- /dev/null
+++ b/kmymoney2/templates/es_AR/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Pagarés y mercado monetario</title>
+ <shortdesc>Cuentas para pagarés, e inversiones de mercado monetario</shortdesc>
+ <longdesc>Debería seleccionar este juego de cuentas si maneja pagarés o cuentas de mercado monetario (pagarés, intereses de pagarés, mercado monetario, intereses de mercado monetario).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Interés de pagarés"/>
+ <account type="12" name="Interés de mercado monetario"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activo circulante">
+ <account type="1" name="Mercado monetario"/>
+ <account type="1" name="Pagaré de banco"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/childcare.kmt b/kmymoney2/templates/es_AR/childcare.kmt
new file mode 100644
index 0000000..64e0066
--- /dev/null
+++ b/kmymoney2/templates/es_AR/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de guardería</title>
+ <shortdesc>Cuenta para gestionar gastos de guardería</shortdesc>
+ <longdesc>Deberá seleccionar este juego de cuentas si tiene gastos de guardería.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Guardería"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/common.kmt b/kmymoney2/templates/es_AR/common.kmt
new file mode 100644
index 0000000..78a931d
--- /dev/null
+++ b/kmymoney2/templates/es_AR/common.kmt
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas comunes</title>
+ <shortdesc>Un juego básico de cuentas mayoritariamente utilizadas</shortdesc>
+ <longdesc>La mayoría de usuarios deseará escoger este juego de cuentas. Incluye las cuentas más comunmente utilizadas (cuenta corriente, de ahorros, metálico, tarjeta de crédito, ingresos, gastos comunes).</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Balances de apertura"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activo circulante">
+ <account type="1" name="Cuenta corriente"/>
+ <account type="3" name="Efectivo"/>
+ <account type="1" name="Cuenta de ahorros"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Restaurantes"/>
+ <account type="13" name="Transporte público"/>
+ <account type="13" name="Educación"/>
+ <account type="13" name="Servicios">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Barrido y Limpieza"/>
+ <account type="13" name="Agua"/>
+ <account type="13" name="Electricidad"/>
+ </account>
+ <account type="13" name="Suscripciones"/>
+ <account type="13" name="Teléfono"/>
+ <account type="13" name="Servicios Internet"/>
+ <account type="13" name="Comestibles"/>
+ <account type="13" name="Entretenimiento">
+ <account type="13" name="Viajes"/>
+ <account type="13" name="Recreación"/>
+ <account type="13" name="Música/Películas"/>
+ </account>
+ <account type="13" name="Libros"/>
+ <account type="13" name="Regalos"/>
+ <account type="13" name="Gastos médicos">
+ <account type="13" name="Medicina Prepaga"/>
+ <account type="13" name="Obra Social"/>
+ </account>
+ <account type="13" name="Obras benéficas"/>
+ <account type="13" name="Automóvil">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Reparación y mantenimiento"/>
+ <account type="13" name="Estacionamiento"/>
+ <account type="13" name="Cuotas"/>
+ </account>
+ <account type="13" name="Cargos bancarios"/>
+ <account type="13" name="Ropa"/>
+ <account type="13" name="Artículos de oficina"/>
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de automóvil"/>
+ <account type="13" name="Seguro de vida"/>
+ <account type="13" name="Seguro de retiro"/>
+ </account>
+ <account type="13" name="Ajustes"/>
+ <account type="13" name="Impuestos">
+ <account type="13" name="Municipales"/>
+ <account type="13" name="Seguridad Social"/>
+ <account type="13" name="Ganancias"/>
+ <account type="13" name="Bienes Personales"/>
+ <account type="13" name="Otros impuestos"/>
+ </account>
+ <account type="13" name="Informática"/>
+ <account type="13" name="Lavandería"/>
+ <account type="13" name="Otros gastos"/>
+ <account type="13" name="TV Cable"/>
+ <account type="13" name="Hobbies"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Bonos extra"/>
+ <account type="12" name="Otros ingresos"/>
+ <account type="12" name="Regalos recibidos"/>
+ <account type="12" name="Sueldo"/>
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Intereses de cuenta corriente"/>
+ <account type="12" name="Otros intereses"/>
+ <account type="12" name="Intereses cuenta de ahorros"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Cuentas por pagar">
+ <account type="4" name="Tarjeta de crédito"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/currency.kmt b/kmymoney2/templates/es_AR/currency.kmt
new file mode 100644
index 0000000..f0abe85
--- /dev/null
+++ b/kmymoney2/templates/es_AR/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuenta de conversión monetaria</title>
+ <shortdesc>Cuenta para convertir y comerciar con moneda extranjera</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si convierte monedas extranjeras. Note: La cuenta se encuentra en USD; edite la cuenta para alterar la moneda</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/default_accounts.kmt b/kmymoney2/templates/es_AR/default_accounts.kmt
new file mode 100644
index 0000000..b97a618
--- /dev/null
+++ b/kmymoney2/templates/es_AR/default_accounts.kmt
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney</title>
+ <shortdesc>Cuentas predeterminadas</shortdesc>
+ <longdesc>Estas son cuentas y categorías que vienen de manera predeterminada</longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Alimentos y bebidas no alcohólicas" type="13">
+ <account name="Alimentos" type="13"/>
+ <account name="Bebidas no alcohólicas" type="13"/>
+ </account>
+ <account name="Bebidas alcohólicas, tabaco y estupefacientes" type="13">
+ <account name="Bebidas alcohólicas" type="13"/>
+ <account name="Tabaco" type="13"/>
+ <account name="Estupefacientes" type="13"/>
+ </account>
+ <account name="Ropa y calzado" type="13">
+ <account name="Ropa" type="13"/>
+ <account name="Calzado" type="13"/>
+ </account>
+ <account name="Alojamiento, agua, electricidad, gas y otros combustibles" type="13">
+ <account name="Alquileres efectivos de la vivienda" type="13"/>
+ <account name="Alquileres imputados a la vivienda" type="13"/>
+ <account name="Conservación y reparación de la vivienda" type="13"/>
+ <account name="Suministro de agua, y servicios diversos" type="13"/>
+ <account name="Electricidad, gas y otros combustibles" type="13"/>
+ </account>
+ <account name="Muebles, cosas del hogar y mantenimiento de la casa" type="13">
+ <account name="Muebles y accesorios, alfombras y otros materiales para pisos" type="13"/>
+ <account name="Productos textiles para el hogar" type="13"/>
+ <account name="Artefactos para el hogar" type="13"/>
+ <account name="Mercancías de vidrio y cristal, vajilla y utensilios para el hogar" type="13"/>
+ <account name="Herramientas y útiles para el hogar y jardín" type="13"/>
+ <account name="Bienes y servicios para la conservación ordinaria del hogar" type="13"/>
+ </account>
+ <account name="Salud" type="13">
+ <account name="Productos, artefactos y equipo médico" type="13"/>
+ <account name="Servicios para pacientes externos" type="13"/>
+ <account name="Servicios de hospital" type="13"/>
+ </account>
+ <account name="Transporte" type="13">
+ <account name="Adquisición de vehículos" type="13"/>
+ <account name="Funcionamiento de equipos de transporte personal" type="13"/>
+ <account name="Servicios de transporte" type="13"/>
+ </account>
+ <account name="Comunicaciones" type="13">
+ <account name="Servicios postales" type="13"/>
+ <account name="Equipo telefónico y de fax" type="13"/>
+ <account name="Servicios telefónicos y de fax" type="13"/>
+ </account>
+ <account name="Ocio y cultura" type="13">
+ <account name="Equipos audiovisuales, fotográficos y de procesamiento de información" type="13"/>
+ <account name="Otros productos duraderos importantes para ocio y cultura" type="13"/>
+ <account name="Otros artículos y equipo para ocio, jardines y animales domésticos" type="13"/>
+ <account name="Servicios de ocio y culturales" type="13"/>
+ <account name="Periódicos, libros y papeles y utiles de oficina" type="13"/>
+ <account name="Paquetes turísticos" type="13"/>
+ </account>
+ <account name="Educación" type="13">
+ <account name="Enseñanza preescolar y primaria" type="13"/>
+ <account name="Enseñanza secundaria" type="13"/>
+ <account name="Enseñanza postsecundaria, no terciaria" type="13"/>
+ <account name="Enseñanza terciaria" type="13"/>
+ <account name="Enseñanza no atribuible a ningún nivel" type="13"/>
+ </account>
+ <account name="Restaurantes y hoteles" type="13">
+ <account name="Servicios de catering" type="13"/>
+ <account name="Servicios de alojamiento" type="13"/>
+ </account>
+ <account name="Bienes y servicios diversos" type="13">
+ <account name="Cuidado personal" type="13"/>
+ <account name="Efectos personales" type="13"/>
+ <account name="Protección social" type="13"/>
+ <account name="Seguros" type="13"/>
+ <account name="Servicios financieros" type="13"/>
+ <account name="Otros servicios" type="13"/>
+ </account>
+ </account>
+
+ <account name="" type="12">
+ <account name="Otros Ingresos" type="12">
+ <account name="Becas" type="12"/>
+ <account name="Regalos Recibidos" type="12"/>
+ <account name="Loterías" type="12"/>
+ <account name="Devolución de Impuestos" type="12"/>
+ <account name="Pensión Recibida para Hijos" type="12"/>
+ </account>
+ <account name="Seguridad Social" type="12">
+ <account name="Pensión de Jubilación" type="12"/>
+ <account name="Pensión no Contributiva" type="12"/>
+ <account name="Bajas laborales" type="12"/>
+ <account name="Seguro Desempleo" type="12"/>
+ </account>
+ <account name="Rendimientos de Inversiones" type="12">
+ <account name="Dividendos" type="12"/>
+ <account name="Ganancias de Capital" type="12"/>
+ <account name="Intereses" type="12"/>
+ </account>
+ <account name="Salario" type="12">
+ <account name="Bonos" type="12"/>
+ <account name="Comisiones" type="12"/>
+ <account name="Primas de Producción" type="12"/>
+ <account name="Salario Bruto" type="12"/>
+ <account name="Salario Neto" type="12"/>
+ <account name="Horas Extras" type="12"/>
+ </account>
+ </account>
+ <account name="" type="9">
+ <account name="Activo líquido" type="1">
+ <account name="Dinero en mano" type="1"/>
+ <account name="Cuenta corriente" type="1"/>
+ </account>
+ <account name="Activo fijo" type="1">
+ <account name="Coche" type="9"/>
+ <account name="Casa" type="9"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/eduloan.kmt b/kmymoney2/templates/es_AR/eduloan.kmt
new file mode 100644
index 0000000..b556dbb
--- /dev/null
+++ b/kmymoney2/templates/es_AR/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo para educación</title>
+ <shortdesc>Cuentas para préstamos para estudios e intereses asociados</shortdesc>
+ <longdesc>Deseará seleccionar este conjunto de cuentas si posee un préstamo para educación (préstamo para educación, intereses de préstamo para educación)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Intereses de préstamo para educación"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Préstamo para educación"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/fixedassets.kmt b/kmymoney2/templates/es_AR/fixedassets.kmt
new file mode 100644
index 0000000..70f530d
--- /dev/null
+++ b/kmymoney2/templates/es_AR/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Activos fijos</title>
+ <shortdesc>Cuentas para gestionar varios activos fijos</shortdesc>
+ <longdesc>Deberá seleccionar esta cuenta si tiene varios activos fijos (casa, vehículo, casa de vacaciones, otros activos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Activo fijo">
+ <account type="9" name="Vehículo"/>
+ <account type="9" name="Otros activos"/>
+ <account type="9" name="Casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/homeloan.kmt b/kmymoney2/templates/es_AR/homeloan.kmt
new file mode 100644
index 0000000..474d7ac
--- /dev/null
+++ b/kmymoney2/templates/es_AR/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo hipotecario</title>
+ <shortdesc>Cuentas para préstamo hipotecario e interés asociado</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si tiene contratado un préstamo hipotecario (préstamo hipotecario, interés hipoteca).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Interés de hipoteca"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Préstamo hipotecario"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/homeown.kmt b/kmymoney2/templates/es_AR/homeown.kmt
new file mode 100644
index 0000000..f0d2613
--- /dev/null
+++ b/kmymoney2/templates/es_AR/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de propietario de casa</title>
+ <shortdesc>Gastos asociados a la propiedad de una casa</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si posee una casa. Este juego le proporciona un grupo de cuentas para controlar los gastos domésticos (seguro, impuestos, reparaciones).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de hogar"/>
+ </account>
+ <account type="13" name="Impuestos">
+ <account type="13" name="Contribución"/>
+ </account>
+ <account type="13" name="Reparaciones domésticas"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/otherloan.kmt b/kmymoney2/templates/es_AR/otherloan.kmt
new file mode 100644
index 0000000..a329180
--- /dev/null
+++ b/kmymoney2/templates/es_AR/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Otros préstamos</title>
+ <shortdesc>Cuentas para controlar otros préstamos, junto con su interés asociado</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si tiene un préstamo distinto a un préstamo hipotecario (otro préstamo, interés de otro préstamo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Otro interés"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Otro préstamo"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/renter.kmt b/kmymoney2/templates/es_AR/renter.kmt
new file mode 100644
index 0000000..1124e07
--- /dev/null
+++ b/kmymoney2/templates/es_AR/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de inquilino</title>
+ <shortdesc>Gastos asociados a alquilar una casa</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si alquila una casa o apartamento (alquiler, seguro de inquilino).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Alquiler"/>
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de inquilino"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/retiremt.kmt b/kmymoney2/templates/es_AR/retiremt.kmt
new file mode 100644
index 0000000..8965978
--- /dev/null
+++ b/kmymoney2/templates/es_AR/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de jubilación</title>
+ <shortdesc>Cuenta de jubilación con subcuentas de inversiones relacionadas</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si tiene cuentas de jubilación (de acciones, bonos, fondos de inversión, fondos de índice).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Jubilación"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/spouseinc.kmt b/kmymoney2/templates/es_AR/spouseinc.kmt
new file mode 100644
index 0000000..cd288c3
--- /dev/null
+++ b/kmymoney2/templates/es_AR/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Ingresos de cónyuge</title>
+ <shortdesc>Cuentas para controlar los ingresos del cónyuge de manera separada</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si su cónyuge trabaja (sueldo (cónyuge), impuestos (cónyuge)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Sueldo (Cónyuge)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Impuestos (Cónyuge)">
+ <account type="13" name="Municipales"/>
+ <account type="13" name="Seguridad Social"/>
+ <account type="13" name="Ganancias"/>
+ <account type="13" name="Bienes Personales"/>
+ <account type="13" name="Otros impuestos"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_AR/spouseretire.kmt b/kmymoney2/templates/es_AR/spouseretire.kmt
new file mode 100644
index 0000000..91bcbb4
--- /dev/null
+++ b/kmymoney2/templates/es_AR/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de jubilación de cónyuge</title>
+ <shortdesc>Cuenta de jubilación con cuentas de inversión asociadas para cónyuge</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si tiene inversiones a nombre de su cónyuge (acciones, bonos, fondos de inversión, fondos de índice, intereses, dividendos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Jubilación de cónyuge"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/Makefile.am b/kmymoney2/templates/es_ES/Makefile.am
new file mode 100644
index 0000000..1d46036
--- /dev/null
+++ b/kmymoney2/templates/es_ES/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/es_ES
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt default_accounts.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/es_ES/brokerage.kmt b/kmymoney2/templates/es_ES/brokerage.kmt
new file mode 100644
index 0000000..c6910ed
--- /dev/null
+++ b/kmymoney2/templates/es_ES/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de Inversión</title>
+ <shortdesc>Cuenta de corredor de bolsa con las cuentas de inversiones asociadas</shortdesc>
+ <longdesc>Deberá escoger este juego de cuentas si tiene inversiones (acciones, bonos, fondos de inversión, fondos indexados, intereses, dividendos).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Comisiones"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Ingresos por dividendos"/>
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Intereses de bonos"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Cuenta de inversión"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/carloan.kmt b/kmymoney2/templates/es_ES/carloan.kmt
new file mode 100644
index 0000000..0161c39
--- /dev/null
+++ b/kmymoney2/templates/es_ES/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo de automóvil</title>
+ <shortdesc>Cuentas para pago a plazos de automóvil e intereses asociados</shortdesc>
+ <longdesc>Debería seleccionar este juego de cuentas si está pagando a plazos su automóvil (plazos de automóvil, intereses por plazos de automóvil).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Intereses pago plazos vehículo"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Vehículo a plazos"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/cdmoneymkt.kmt b/kmymoney2/templates/es_ES/cdmoneymkt.kmt
new file mode 100644
index 0000000..39194ac
--- /dev/null
+++ b/kmymoney2/templates/es_ES/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Pagarés y mercado monetario</title>
+ <shortdesc>Cuentas para pagarés, e inversiones de mercado monetario</shortdesc>
+ <longdesc>Debería seleccionar este juego de cuentas si maneja pagarés o cuentas de mercado monetario (pagarés, intereses de pagarés, mercado monetario, intereses de mercado monetario).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Interés de pagarés"/>
+ <account type="12" name="Interés de mercado monetario"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activo circulante">
+ <account type="1" name="Mercado monetario"/>
+ <account type="1" name="Pagaré de banco"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/childcare.kmt b/kmymoney2/templates/es_ES/childcare.kmt
new file mode 100644
index 0000000..64e0066
--- /dev/null
+++ b/kmymoney2/templates/es_ES/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de guardería</title>
+ <shortdesc>Cuenta para gestionar gastos de guardería</shortdesc>
+ <longdesc>Deberá seleccionar este juego de cuentas si tiene gastos de guardería.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Guardería"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/common.kmt b/kmymoney2/templates/es_ES/common.kmt
new file mode 100644
index 0000000..ccd8889
--- /dev/null
+++ b/kmymoney2/templates/es_ES/common.kmt
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas comunes</title>
+ <shortdesc>Un juego básico de cuentas mayoritariamente utilizadas</shortdesc>
+ <longdesc>La mayoría de usuarios deseará escoger este juego de cuentas. Incluye las cuentas más comunmente utilizadas (cuenta corriente, de ahorros, metálico, tarjeta de crédito, ingresos, gastos comunes).</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Balances de apertura"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activo circulante">
+ <account type="1" name="Cuenta corriente"/>
+ <account type="3" name="Metálico"/>
+ <account type="1" name="Cuenta de ahorros"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Restaurantes"/>
+ <account type="13" name="Transporte público"/>
+ <account type="13" name="Educación"/>
+ <account type="13" name="Servicios">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Recogida de basura"/>
+ <account type="13" name="Agua"/>
+ <account type="13" name="Electricidad"/>
+ </account>
+ <account type="13" name="Suscripciones"/>
+ <account type="13" name="Teléfono"/>
+ <account type="13" name="Servicios Internet"/>
+ <account type="13" name="Comestibles"/>
+ <account type="13" name="Ocio">
+ <account type="13" name="Viajes"/>
+ <account type="13" name="Recreación"/>
+ <account type="13" name="Música/Películas"/>
+ </account>
+ <account type="13" name="Libros"/>
+ <account type="13" name="Regalos"/>
+ <account type="13" name="Gastos médicos"/>
+ <account type="13" name="Obras benéficas"/>
+ <account type="13" name="Automóvil">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Reparación y mantenimiento"/>
+ <account type="13" name="Aparcamiento"/>
+ <account type="13" name="Cuotas"/>
+ </account>
+ <account type="13" name="Cargo de servicio bancario"/>
+ <account type="13" name="Ropa"/>
+ <account type="13" name="Material de oficina"/>
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de automóvil"/>
+ <account type="13" name="Seguro de vida"/>
+ <account type="13" name="Seguro sanitario"/>
+ </account>
+ <account type="13" name="Ajustes"/>
+ <account type="13" name="Impuestos">
+ <account type="13" name="Municipales"/>
+ <account type="13" name="Seguridad Social"/>
+ <account type="13" name="IRPF"/>
+ <account type="13" name="Retenciones"/>
+ <account type="13" name="Otros impuestos"/>
+ </account>
+ <account type="13" name="Informática"/>
+ <account type="13" name="Lavandería"/>
+ <account type="13" name="Otros gastos"/>
+ <account type="13" name="TV Cable"/>
+ <account type="13" name="Hobbies"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Pagas extra"/>
+ <account type="12" name="Otros ingresos"/>
+ <account type="12" name="Regalos recibidos"/>
+ <account type="12" name="Sueldo"/>
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Intereses de cuenta corriente"/>
+ <account type="12" name="Otros intereses"/>
+ <account type="12" name="Intereses cuenta de ahorros"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Cuentas por pagar">
+ <account type="4" name="Tarjeta de crédito"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/currency.kmt b/kmymoney2/templates/es_ES/currency.kmt
new file mode 100644
index 0000000..f0abe85
--- /dev/null
+++ b/kmymoney2/templates/es_ES/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuenta de conversión monetaria</title>
+ <shortdesc>Cuenta para convertir y comerciar con moneda extranjera</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si convierte monedas extranjeras. Note: La cuenta se encuentra en USD; edite la cuenta para alterar la moneda</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/default_accounts.kmt b/kmymoney2/templates/es_ES/default_accounts.kmt
new file mode 100644
index 0000000..383b43d
--- /dev/null
+++ b/kmymoney2/templates/es_ES/default_accounts.kmt
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney</title>
+ <shortdesc>Cuentas predeterminadas</shortdesc>
+ <longdesc>Estas son cuentas y categorías que vienen de manera predeterminada para esta versión de KMyMoney</longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Alimentos y bebidas no alcohólicas" type="13">
+ <account name="Alimentos" type="13"/>
+ <account name="Bebidas no alcohólicas" type="13"/>
+ </account>
+ <account name="Bebidas alcohólicas, tabaco y estupefacientes" type="13">
+ <account name="Bebidas alcohólicas" type="13"/>
+ <account name="Tabaco" type="13"/>
+ <account name="Estupefacientes" type="13"/>
+ </account>
+ <account name="Ropa y calzado" type="13">
+ <account name="Ropa" type="13"/>
+ <account name="Calzado" type="13"/>
+ </account>
+ <account name="Alojamiento, agua, electricidad, gas y otros combustibles" type="13">
+ <account name="Alquileres efectivos de la vivienda" type="13"/>
+ <account name="Alquileres imputados a la vivienda" type="13"/>
+ <account name="Conservación y reparación de la vivienda" type="13"/>
+ <account name="Suministro de agua, y servicios diversos" type="13"/>
+ <account name="Electricidad, gas y otros combustibles" type="13"/>
+ </account>
+ <account name="Muebles, cosas del hogar y mantenimiento de la casa" type="13">
+ <account name="Muebles y accesorios, alfombras y otros materiales para pisos" type="13"/>
+ <account name="Productos textiles para el hogar" type="13"/>
+ <account name="Artefactos para el hogar" type="13"/>
+ <account name="Mercancías de vidrio y cristal, vajilla y utensilios para el hogar" type="13"/>
+ <account name="Herramientas y útiles para el hogar y jardín" type="13"/>
+ <account name="Bienes y servicios para la conservación ordinaria del hogar" type="13"/>
+ </account>
+ <account name="Salud" type="13">
+ <account name="Productos, artefactos y equipo médico" type="13"/>
+ <account name="Servicios para pacientes externos" type="13"/>
+ <account name="Servicios de hospital" type="13"/>
+ </account>
+ <account name="Transporte" type="13">
+ <account name="Adquisición de vehículos" type="13"/>
+ <account name="Funcionamiento de equipos de transporte personal" type="13"/>
+ <account name="Servicios de transporte" type="13"/>
+ </account>
+ <account name="Comunicaciones" type="13">
+ <account name="Servicios postales" type="13"/>
+ <account name="Equipo telefónico y de fax" type="13"/>
+ <account name="Servicios telefónicos y de fax" type="13"/>
+ </account>
+ <account name="Ocio y cultura" type="13">
+ <account name="Equipos audiovisuales, fotográficos y de procesamiento de información" type="13"/>
+ <account name="Otros productos duraderos importantes para ocio y cultura" type="13"/>
+ <account name="Otros artículos y equipo para ocio, jardines y animales domésticos" type="13"/>
+ <account name="Servicios de ocio y culturales" type="13"/>
+ <account name="Periódicos, libros y papeles y utiles de oficina" type="13"/>
+ <account name="Paquetes turísticos" type="13"/>
+ </account>
+ <account name="Educación" type="13">
+ <account name="Enseñanza preescolar y primaria" type="13"/>
+ <account name="Enseñanza secundaria" type="13"/>
+ <account name="Enseñanza postsecundaria, no terciaria" type="13"/>
+ <account name="Enseñanza terciaria" type="13"/>
+ <account name="Enseñanza no atribuible a ningún nivel" type="13"/>
+ </account>
+ <account name="Restaurantes y hoteles" type="13">
+ <account name="Servicios de catering" type="13"/>
+ <account name="Servicios de alojamiento" type="13"/>
+ </account>
+ <account name="Bienes y servicios diversos" type="13">
+ <account name="Cuidado personal" type="13"/>
+ <account name="Efectos personales n.e.p." type="13"/>
+ <account name="Protección social" type="13"/>
+ <account name="Seguros" type="13"/>
+ <account name="Servicios financieros n.e.p." type="13"/>
+ <account name="Otros servicios n.e.p." type="13"/>
+ </account>
+ </account>
+
+ <account name="" type="12">
+ <account name="Otros Ingresos" type="12">
+ <account name="Becas" type="12"/>
+ <account name="Regalos Recibidos" type="12"/>
+ <account name="Loterías" type="12"/>
+ <account name="Devolución de Impuestos" type="12"/>
+ <account name="Pensión Recibida para Hijos" type="12"/>
+ </account>
+ <account name="Seguridad Social" type="12">
+ <account name="Pensión de Jubilación" type="12"/>
+ <account name="Pensión no Contributiva" type="12"/>
+ <account name="Bajas laborales" type="12"/>
+ <account name="Seguro Desempleo" type="12"/>
+ </account>
+ <account name="Rendimientos de Inversiones" type="12">
+ <account name="Dividendos" type="12"/>
+ <account name="Ganancias de Capital" type="12"/>
+ <account name="Intereses" type="12"/>
+ </account>
+ <account name="Salario" type="12">
+ <account name="Bonus" type="12"/>
+ <account name="Comisiones" type="12"/>
+ <account name="Primas de Producción" type="12"/>
+ <account name="Salario Bruto" type="12"/>
+ <account name="Salario Neto" type="12"/>
+ <account name="Horas Extras" type="12"/>
+ </account>
+ </account>
+ <account name="" type="9">
+ <account name="Activo líquido" type="1">
+ <account name="Dinero en mano" type="1"/>
+ <account name="Cuenta corriente" type="1"/>
+ </account>
+ <account name="Activo fijo" type="1">
+ <account name="Coche" type="9"/>
+ <account name="Casa" type="9"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/eduloan.kmt b/kmymoney2/templates/es_ES/eduloan.kmt
new file mode 100644
index 0000000..b556dbb
--- /dev/null
+++ b/kmymoney2/templates/es_ES/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo para educación</title>
+ <shortdesc>Cuentas para préstamos para estudios e intereses asociados</shortdesc>
+ <longdesc>Deseará seleccionar este conjunto de cuentas si posee un préstamo para educación (préstamo para educación, intereses de préstamo para educación)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Intereses de préstamo para educación"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Préstamo para educación"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/fixedassets.kmt b/kmymoney2/templates/es_ES/fixedassets.kmt
new file mode 100644
index 0000000..70f530d
--- /dev/null
+++ b/kmymoney2/templates/es_ES/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Activos fijos</title>
+ <shortdesc>Cuentas para gestionar varios activos fijos</shortdesc>
+ <longdesc>Deberá seleccionar esta cuenta si tiene varios activos fijos (casa, vehículo, casa de vacaciones, otros activos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Activo fijo">
+ <account type="9" name="Vehículo"/>
+ <account type="9" name="Otros activos"/>
+ <account type="9" name="Casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/homeloan.kmt b/kmymoney2/templates/es_ES/homeloan.kmt
new file mode 100644
index 0000000..474d7ac
--- /dev/null
+++ b/kmymoney2/templates/es_ES/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo hipotecario</title>
+ <shortdesc>Cuentas para préstamo hipotecario e interés asociado</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si tiene contratado un préstamo hipotecario (préstamo hipotecario, interés hipoteca).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Interés de hipoteca"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Préstamo hipotecario"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/homeown.kmt b/kmymoney2/templates/es_ES/homeown.kmt
new file mode 100644
index 0000000..f0d2613
--- /dev/null
+++ b/kmymoney2/templates/es_ES/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de propietario de casa</title>
+ <shortdesc>Gastos asociados a la propiedad de una casa</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si posee una casa. Este juego le proporciona un grupo de cuentas para controlar los gastos domésticos (seguro, impuestos, reparaciones).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de hogar"/>
+ </account>
+ <account type="13" name="Impuestos">
+ <account type="13" name="Contribución"/>
+ </account>
+ <account type="13" name="Reparaciones domésticas"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/otherloan.kmt b/kmymoney2/templates/es_ES/otherloan.kmt
new file mode 100644
index 0000000..a329180
--- /dev/null
+++ b/kmymoney2/templates/es_ES/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Otros préstamos</title>
+ <shortdesc>Cuentas para controlar otros préstamos, junto con su interés asociado</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si tiene un préstamo distinto a un préstamo hipotecario (otro préstamo, interés de otro préstamo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Otro interés"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Otro préstamo"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/renter.kmt b/kmymoney2/templates/es_ES/renter.kmt
new file mode 100644
index 0000000..1124e07
--- /dev/null
+++ b/kmymoney2/templates/es_ES/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de inquilino</title>
+ <shortdesc>Gastos asociados a alquilar una casa</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si alquila una casa o apartamento (alquiler, seguro de inquilino).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Alquiler"/>
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de inquilino"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/retiremt.kmt b/kmymoney2/templates/es_ES/retiremt.kmt
new file mode 100644
index 0000000..8965978
--- /dev/null
+++ b/kmymoney2/templates/es_ES/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de jubilación</title>
+ <shortdesc>Cuenta de jubilación con subcuentas de inversiones relacionadas</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si tiene cuentas de jubilación (de acciones, bonos, fondos de inversión, fondos de índice).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Jubilación"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/spouseinc.kmt b/kmymoney2/templates/es_ES/spouseinc.kmt
new file mode 100644
index 0000000..632216f
--- /dev/null
+++ b/kmymoney2/templates/es_ES/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Ingresos de cónyuge</title>
+ <shortdesc>Cuentas para controlar los ingresos del cónyuge de manera separada</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si su cónyuge trabaja (sueldo (cónyuge), impuestos (cónyuge)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Sueldo (Cónyuge)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Impuestos (Cónyuge)">
+ <account type="13" name="Seguridad Social"/>
+ <account type="13" name="Retenciones"/>
+ <account type="13" name="Municipales"/>
+ <account type="13" name="IRPF"/>
+ <account type="13" name="Otros impuestos"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_ES/spouseretire.kmt b/kmymoney2/templates/es_ES/spouseretire.kmt
new file mode 100644
index 0000000..91bcbb4
--- /dev/null
+++ b/kmymoney2/templates/es_ES/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_ES/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de jubilación de cónyuge</title>
+ <shortdesc>Cuenta de jubilación con cuentas de inversión asociadas para cónyuge</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si tiene inversiones a nombre de su cónyuge (acciones, bonos, fondos de inversión, fondos de índice, intereses, dividendos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Jubilación de cónyuge"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/Makefile.am b/kmymoney2/templates/es_MX/Makefile.am
new file mode 100644
index 0000000..a96e0d8
--- /dev/null
+++ b/kmymoney2/templates/es_MX/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/es_MX
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/es_MX/brokerage.kmt b/kmymoney2/templates/es_MX/brokerage.kmt
new file mode 100644
index 0000000..7a7e4e4
--- /dev/null
+++ b/kmymoney2/templates/es_MX/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de Inversión</title>
+ <shortdesc>Cuenta de corredor de bolsa con las cuentas de inversiones asociadas</shortdesc>
+ <longdesc>Deberá escoger este juego de cuentas si tiene inversiones (acciones, bonos, fondos de inversión, fondos indexados, intereses, dividendos).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Comisiones"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Ingresos por dividendos"/>
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Intereses de bonos"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Cuenta de inversión"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/carloan.kmt b/kmymoney2/templates/es_MX/carloan.kmt
new file mode 100644
index 0000000..601056d
--- /dev/null
+++ b/kmymoney2/templates/es_MX/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo de automóvil</title>
+ <shortdesc>Cuentas para pago a plazos de automóvil e intereses asociados</shortdesc>
+ <longdesc>Debería seleccionar este juego de cuentas si está pagando a plazos su automóvil (plazos de automóvil, intereses por plazos de automóvil).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Intereses pago plazos vehículo"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Vehículo a plazos"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/cdmoneymkt.kmt b/kmymoney2/templates/es_MX/cdmoneymkt.kmt
new file mode 100644
index 0000000..464259a
--- /dev/null
+++ b/kmymoney2/templates/es_MX/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Pagarés y mercado monetario</title>
+ <shortdesc>Cuentas para pagarés, e inversiones de mercado monetario</shortdesc>
+ <longdesc>Debería seleccionar este juego de cuentas si maneja pagarés o cuentas de mercado monetario (pagarés, intereses de pagarés, mercado monetario, intereses de mercado monetario).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Interés de pagarés"/>
+ <account type="12" name="Interés de mercado de dinero"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activo circulante">
+ <account type="1" name="Mercado de dinero"/>
+ <account type="1" name="Pagaré de banco"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/childcare.kmt b/kmymoney2/templates/es_MX/childcare.kmt
new file mode 100644
index 0000000..d3c1035
--- /dev/null
+++ b/kmymoney2/templates/es_MX/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de guardería</title>
+ <shortdesc>Cuenta para gestionar gastos de guardería</shortdesc>
+ <longdesc>Deberá seleccionar este juego de cuentas si tiene gastos de guardería.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Guardería"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/common.kmt b/kmymoney2/templates/es_MX/common.kmt
new file mode 100644
index 0000000..301b436
--- /dev/null
+++ b/kmymoney2/templates/es_MX/common.kmt
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas comunes</title>
+ <shortdesc>Un juego básico de cuentas mayoritariamente utilizadas</shortdesc>
+ <longdesc>La mayoría de usuarios deseará escoger este juego de cuentas. Incluye las cuentas más comúnmente utilizadas (cuenta de ahorros, efectivo, tarjeta de crédito, ingresos, gastos comunes).</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Balances de apertura"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activo circulante">
+ <account type="1" name="Cuenta de Cheques"/>
+ <account type="3" name="Efectivo"/>
+ <account type="1" name="Cuenta de ahorros"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Restaurantes"/>
+ <account type="13" name="Transporte público"/>
+ <account type="13" name="Educación"/>
+ <account type="13" name="Servicios">
+ <account type="13" name="Gas"/>
+ <account type="13" name="Recolección de basura"/>
+ <account type="13" name="Agua"/>
+ <account type="13" name="Electricidad"/>
+ </account>
+ <account type="13" name="Suscripciones"/>
+ <account type="13" name="Teléfono"/>
+ <account type="13" name="Servicios de Internet"/>
+ <account type="13" name="Despensa"/>
+ <account type="13" name="Ocio">
+ <account type="13" name="Viajes"/>
+ <account type="13" name="Entretenimiento"/>
+ <account type="13" name="Música/Películas"/>
+ </account>
+ <account type="13" name="Libros"/>
+ <account type="13" name="Regalos"/>
+ <account type="13" name="Gastos médicos"/>
+ <account type="13" name="Obras de caridad"/>
+ <account type="13" name="Automóvil">
+ <account type="13" name="Gasolina"/>
+ <account type="13" name="Reparación y mantenimiento"/>
+ <account type="13" name="Estacionamiento"/>
+ <account type="13" name="Casetas de Peaje"/>
+ </account>
+ <account type="13" name="Cargo de servicio bancario"/>
+ <account type="13" name="Ropa"/>
+ <account type="13" name="Material de oficina"/>
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro del automóvil"/>
+ <account type="13" name="Seguro de vida"/>
+ <account type="13" name="Seguro Social"/>
+ </account>
+ <account type="13" name="Ajustes"/>
+ <account type="13" name="Impuestos">
+ <account type="13" name="IMSS"/>
+ <account type="13" name="Municipales"/>
+ <account type="13" name="Federales">
+ <account type="13" name="IVA"/>
+ <account type="13" name="IETU"/>
+ <account type="13" name="ISR"/>
+ <account type="13" name="Tenencia"/>
+ <account type="13" name="PTU"/>
+ </account>
+ <account type="13" name="Retenciones"/>
+ <account type="13" name="Otros impuestos"/>
+ </account>
+ <account type="13" name="Computadora"/>
+ <account type="13" name="Lavandería"/>
+ <account type="13" name="Otros gastos"/>
+ <account type="13" name="TV Cable"/>
+ <account type="13" name="Hobbies"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Pagos extra"/>
+ <account type="12" name="Otros ingresos"/>
+ <account type="12" name="Regalos recibidos"/>
+ <account type="12" name="Sueldo"/>
+ <account type="12" name="Ingresos por intereses">
+ <account type="12" name="Intereses cuenta de cheques"/>
+ <account type="12" name="Otros intereses"/>
+ <account type="12" name="Intereses cuenta de ahorros"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Cuentas por pagar">
+ <account type="4" name="Tarjeta de crédito"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/currency.kmt b/kmymoney2/templates/es_MX/currency.kmt
new file mode 100644
index 0000000..6dce52d
--- /dev/null
+++ b/kmymoney2/templates/es_MX/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuenta de Compra-Venta de monedas</title>
+ <shortdesc>Cuenta para compra/venta de moneda extranjera</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si realiza compra/venta de monedas extranjeras. Note: La cuenta se encuentra en USD; edite la cuenta para alterar la moneda</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/eduloan.kmt b/kmymoney2/templates/es_MX/eduloan.kmt
new file mode 100644
index 0000000..5c7f7ba
--- /dev/null
+++ b/kmymoney2/templates/es_MX/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo para educación</title>
+ <shortdesc>Cuentas para préstamos para estudios e intereses asociados</shortdesc>
+ <longdesc>Deseará seleccionar este conjunto de cuentas si posee un préstamo para educación (préstamo para educación, intereses de préstamo para educación)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Intereses de préstamo para educación"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Préstamo para educación"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/fixedassets.kmt b/kmymoney2/templates/es_MX/fixedassets.kmt
new file mode 100644
index 0000000..ecef92a
--- /dev/null
+++ b/kmymoney2/templates/es_MX/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Activos fijos</title>
+ <shortdesc>Cuentas para gestionar varios activos fijos</shortdesc>
+ <longdesc>Deberá seleccionar esta cuenta si tiene varios activos fijos (casa, vehículo, casa de vacaciones, otros activos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Activo fijo">
+ <account type="9" name="Vehículo"/>
+ <account type="9" name="Otros activos"/>
+ <account type="9" name="Casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/homeloan.kmt b/kmymoney2/templates/es_MX/homeloan.kmt
new file mode 100644
index 0000000..747257e
--- /dev/null
+++ b/kmymoney2/templates/es_MX/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Préstamo hipotecario</title>
+ <shortdesc>Cuentas para préstamo hipotecario e interés asociado</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si tiene contratado un préstamo hipotecario (préstamo hipotecario, interés hipoteca).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Interés de hipoteca"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Préstamo hipotecario"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/homeown.kmt b/kmymoney2/templates/es_MX/homeown.kmt
new file mode 100644
index 0000000..cc7e15b
--- /dev/null
+++ b/kmymoney2/templates/es_MX/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de propietario de casa</title>
+ <shortdesc>Gastos asociados a la propiedad de una casa</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si posee una casa. Este juego le proporciona un grupo de cuentas para controlar los gastos domésticos (seguro, impuestos, reparaciones).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro contra siniestros"/>
+ </account>
+ <account type="13" name="Impuestos">
+ <account type="13" name="Predial"/>
+ </account>
+ <account type="13" name="Reparaciones domésticas"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/otherloan.kmt b/kmymoney2/templates/es_MX/otherloan.kmt
new file mode 100644
index 0000000..d31bc3e
--- /dev/null
+++ b/kmymoney2/templates/es_MX/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Otros préstamos</title>
+ <shortdesc>Cuentas para controlar otros préstamos, junto con su interés asociado</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si tiene un préstamo distinto a un préstamo hipotecario (otro préstamo, interés de otro préstamo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intereses">
+ <account type="13" name="Otro interés"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Préstamos">
+ <account type="10" name="Otro préstamo"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/renter.kmt b/kmymoney2/templates/es_MX/renter.kmt
new file mode 100644
index 0000000..3b9d624
--- /dev/null
+++ b/kmymoney2/templates/es_MX/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gastos de inquilino</title>
+ <shortdesc>Gastos asociados a alquilar una casa</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si alquila una casa o apartamento (alquiler, seguro de inquilino).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Alquiler"/>
+ <account type="13" name="Seguros">
+ <account type="13" name="Seguro de inquilino"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/retiremt.kmt b/kmymoney2/templates/es_MX/retiremt.kmt
new file mode 100644
index 0000000..3d2af47
--- /dev/null
+++ b/kmymoney2/templates/es_MX/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de jubilación</title>
+ <shortdesc>Cuenta de jubilación con subcuentas de inversiones relacionadas</shortdesc>
+ <longdesc>Deseará escoger este juego de cuentas si tiene cuentas de jubilación (de acciones, bonos, fondos de inversión, fondos de índice).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Jubilación"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/spouseinc.kmt b/kmymoney2/templates/es_MX/spouseinc.kmt
new file mode 100644
index 0000000..5f1ace5
--- /dev/null
+++ b/kmymoney2/templates/es_MX/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Ingresos de cónyuge</title>
+ <shortdesc>Cuentas para controlar los ingresos del cónyuge de manera separada</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si su cónyuge trabaja (sueldo (cónyuge), impuestos (cónyuge)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Sueldo (Cónyuge)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Impuestos (Cónyuge)">
+ <account type="13" name="Seguridad Social"/>
+ <account type="13" name="Retenciones"/>
+ <account type="13" name="Municipales"/>
+ <account type="13" name="IRPF"/>
+ <account type="13" name="Otros impuestos"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/es_MX/spouseretire.kmt b/kmymoney2/templates/es_MX/spouseretire.kmt
new file mode 100644
index 0000000..4f8847b
--- /dev/null
+++ b/kmymoney2/templates/es_MX/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/es_MX/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Cuentas de jubilación de cónyuge</title>
+ <shortdesc>Cuenta de jubilación con cuentas de inversión asociadas para cónyuge</shortdesc>
+ <longdesc>Deseará seleccionar este juego de cuentas si tiene inversiones a nombre de su cónyuge (acciones, bonos, fondos de inversión, fondos de índice, intereses, dividendos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Inversiones">
+ <account type="7" name="Jubilación de cónyuge"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/Makefile.am b/kmymoney2/templates/fr_CA/Makefile.am
new file mode 100644
index 0000000..12b76ad
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/fr_CA
+
+template_DATA = retraite.kmt revenus.kmt garderie.kmt courtage.kmt conjointrev.kmt chequier.kmt cdmarchemon.kmt etudeemprunt.kmt automobile.kmt conjointretraite.kmt basecommune.kmt proprietaire.kmt actifsfixes.kmt locataire.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/fr_CA/actifsfixes.kmt b/kmymoney2/templates/fr_CA/actifsfixes.kmt
new file mode 100644
index 0000000..6326f8a
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/actifsfixes.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_actifsfixes.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Actifs fixes</title>
+ <shortdesc>Comptes pour la gestion de vos actifs fixes.importants.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous possédez des immobilisations ou actifs fixes importants tels que résidence, chalet, auto ou autres actifs.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Actifs fixes">
+ <account type="9" name="Autres biens immobilisés"/>
+ <account type="9" name="Véhicule"/>
+ <account type="9" name="Résidence"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/automobile.kmt b/kmymoney2/templates/fr_CA/automobile.kmt
new file mode 100644
index 0000000..06c80b2
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/automobile.kmt
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_automobile.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Véhicule</title>
+ <shortdesc>Frais relatifs à votre véhicule.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous devez suivre les frais relatifs à la possession et à l'utilisation d'une auto (assurances, carburant, emprunt, intérêts, ...).</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Auto"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Assurances">
+ <account type="13" name="Auto"/>
+ </account>
+ <account type="13" name="Intérêts">
+ <account type="13" name="Auto"/>
+ </account>
+ <account type="13" name="Auto">
+ <account type="13" name="Carburant"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Permis"/>
+ <account type="13" name="Entretien"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs fixes">
+ <account type="9" name="Véhicule"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/basecommune.kmt b/kmymoney2/templates/fr_CA/basecommune.kmt
new file mode 100644
index 0000000..2e98c22
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/basecommune.kmt
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_basecommune.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Base de comptes communs</title>
+ <shortdesc>Ensemble des comptes de base les plus couramment utilisés</shortdesc>
+ <longdesc>La plupart des utilisateurs sélectionneront ce groupe/hiérarchie de comptes. Il inclut des comptes de base couramment utilisés par les particuliers, tels que compte chèques, compte d'éargne, encaisse, carte de crédit. revenus et dépenses.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Marge de crédit"/>
+ <account type="10" name="Carte de crédit"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Autres"/>
+ <account type="12" name="Cadeaux reçus"/>
+ <account type="12" name="Intérêts">
+ <account type="12" name="Chèques"/>
+ <account type="12" name="Épargne"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Transports publics"/>
+ <account type="13" name="Frais médicaux"/>
+ <account type="13" name="Cadeaux"/>
+ <account type="13" name="Divers"/>
+ <account type="13" name="Divertissements">
+ <account type="13" name="Loisirs"/>
+ <account type="13" name="Passe-temps"/>
+ <account type="13" name="Voyages"/>
+ <account type="13" name="Musique/Films"/>
+ </account>
+ <account type="13" name="Cotisations"/>
+ <account type="13" name="Buanderie"/>
+ <account type="13" name="Vêtements"/>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Informatique"/>
+ <account type="13" name="Livres"/>
+ <account type="13" name="Garderie"/>
+ <account type="13" name="Assurances">
+ <account type="13" name="Santé"/>
+ <account type="13" name="Vie"/>
+ </account>
+ <account type="13" name="Ajustements"/>
+ <account type="13" name="Frais bancaires"/>
+ <account type="13" name="Restaurant"/>
+ <account type="13" name="Formation"/>
+ <account type="13" name="Services">
+ <account type="13" name="Téléphone"/>
+ <account type="13" name="Gaz"/>
+ <account type="13" name="Câble"/>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Électricité"/>
+ <account type="13" name="Ordures"/>
+ <account type="13" name="Cellulaire"/>
+ <account type="13" name="Eau"/>
+ </account>
+ <account type="13" name="Fournitures"/>
+ <account type="13" name="Dons"/>
+ <account type="13" name="Intérêts">
+ <account type="13" name="Marge de crédit"/>
+ <account type="13" name="Carte de crédit"/>
+ </account>
+ <account type="13" name="Alimentation"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Ouverture"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Liquidités">
+ <account type="1" name="Épargne"/>
+ <account type="3" name="Encaisse"/>
+ <account type="1" name="Chèques"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/cdmarchemon.kmt b/kmymoney2/templates/fr_CA/cdmarchemon.kmt
new file mode 100644
index 0000000..eebae64
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/cdmarchemon.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_cdmarchemon.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD/CPG et marché monéraire</title>
+ <shortdesc>Comptes corrrespondant aux certificats de dépôt et au marché monétaire.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes (CD/CPG , marché monétaire et intérêts) si vous détenez des certificats de dépôt et d'autres titres du marché monétaire.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Liquidités">
+ <account type="1" name="Marché monétaire"/>
+ <account type="1" name="CD/CPG bancaires"/>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Intérêts">
+ <account type="12" name="CD/CPG"/>
+ <account type="12" name="Marché monétaire"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/chequier.kmt b/kmymoney2/templates/fr_CA/chequier.kmt
new file mode 100644
index 0000000..20b3a50
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/chequier.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_chequier.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Chéquier</title>
+ <shortdesc>Ensemble de comptes incontournables pour utiliser GnuCash.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous ne voulez suivre que le solde de votre compte en banque. Si le besoin s'en fait sentir plus tard, vous pourrez commencer un suivi plus serré de vos revenus et dépenses en ajoutant de nouveaux groupes de comptes.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Ouverture"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Liquidités">
+ <account type="1" name="Chèques"/>
+ </account>
+ </account>
+ <account type="12" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/conjointretraite.kmt b/kmymoney2/templates/fr_CA/conjointretraite.kmt
new file mode 100644
index 0000000..2588c7b
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/conjointretraite.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_conjointretraite.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Retraite Conjoint(e)</title>
+ <shortdesc>Compte de placements pour retraite du (de la) conjoint(e) et autres comptes associés.</shortdesc>
+ <longdesc>Sélectionnez ce groupe si vous faites le suivi d'un compte de placements (actions, obligations, fonds communs et fonds d'indices boursiers) pour la retraite de votre conjoint(e).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Placements">
+ <account type="9" name="Retraite - Conjoint(e)">
+ <account type="9" name="Obligations"/>
+ <account type="9" name="Fonds commun"/>
+ <account type="9" name="Actions"/>
+ <account type="9" name="Fonds d'indices boursiers"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/conjointrev.kmt b/kmymoney2/templates/fr_CA/conjointrev.kmt
new file mode 100644
index 0000000..841f7e3
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/conjointrev.kmt
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_conjointrev.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Revenus - Conjoint(e)</title>
+ <shortdesc>Comptes pour le suivi distinct des revenus du (de la) conjoint(e)</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous voulez suivre séparément les revenus et dépenses d'emploi du (de la) conjoint(e).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Taxes et impôts">
+ <account type="13" name="Emploi - Conjoint(e)">
+ <account type="13" name="Fédéral"/>
+ <account type="13" name="Assurance emploi"/>
+ <account type="13" name="RRQ/RCP"/>
+ <account type="13" name="RAMQ/Medicare"/>
+ <account type="13" name="Provincial"/>
+ </account>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Emploi - Conjoint(e)">
+ <account type="12" name="Frais remboursés"/>
+ <account type="12" name="Primes"/>
+ <account type="12" name="Salaire"/>
+ <account type="12" name="Commissions"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/courtage.kmt b/kmymoney2/templates/fr_CA/courtage.kmt
new file mode 100644
index 0000000..071782f
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/courtage.kmt
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_courtage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Courtage et placements</title>
+ <shortdesc>Compte de courtage et comptes de placements correspondants</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous possédez des titres de placements (actions, obligations, fonds communs de placement, fonds d'indices boursiers).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Frais de courtage"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividences"/>
+ <account type="12" name="Intérêts">
+ <account type="12" name="Obligations"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Placements">
+ <account type="9" name="Courtage">
+ <account type="9" name="Fonds d'indices boursiers"/>
+ <account type="9" name="Actions"/>
+ <account type="9" name="Fonds commun"/>
+ <account type="9" name="Obligations"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/etudeemprunt.kmt b/kmymoney2/templates/fr_CA/etudeemprunt.kmt
new file mode 100644
index 0000000..6409676
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/etudeemprunt.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_etudeemprunt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Emprunt pour études</title>
+ <shortdesc>Emprunt pour études et frais d'intérêts associés.</shortdesc>
+ <longdesc>Selectionnez ce groupe si vous devez gérer un emprunt pour études.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Études"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Études"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/garderie.kmt b/kmymoney2/templates/fr_CA/garderie.kmt
new file mode 100644
index 0000000..e802eaf
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/garderie.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_garderie.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Enfant à charge</title>
+ <shortdesc>Un compte pour le suivi de vos frais pour un enfant à charge.</shortdesc>
+ <longdesc>Sélectionnez ce groupe si vous avez un jeune enfant .</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Garderie"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/locataire.kmt b/kmymoney2/templates/fr_CA/locataire.kmt
new file mode 100644
index 0000000..54b1e77
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/locataire.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_locataire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Location d'un logis</title>
+ <shortdesc>Frais associés à la location d'une résidence ou d'un logis.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de compte si vous louez une résidence ou un logis (Loyer, assurances, ...).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Assurances">
+ <account type="13" name="Locataire"/>
+ </account>
+ <account type="13" name="Loyer"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/proprietaire.kmt b/kmymoney2/templates/fr_CA/proprietaire.kmt
new file mode 100644
index 0000000..e03f076
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/proprietaire.kmt
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_proprietaire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Propriétaire d'une résidence</title>
+ <shortdesc>Dépenses du propriétaire d'une résidence.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous êtes propriétaire d'une résidence, et voulez en suivre les frais associés (hypothèque, intérêts, entretien et réparations, taxes, ...).</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Hypothèque"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Assurances">
+ <account type="13" name="Résidence"/>
+ </account>
+ <account type="13" name="Taxes et impôts">
+ <account type="13" name="Impôt foncier"/>
+ </account>
+ <account type="13" name="Intérêts">
+ <account type="13" name="Hypothèque"/>
+ </account>
+ <account type="13" name="Entretien de la résidence"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs fixes">
+ <account type="9" name="Résidence"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/retraite.kmt b/kmymoney2/templates/fr_CA/retraite.kmt
new file mode 100644
index 0000000..8b69ddd
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/retraite.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_retraite.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Retraite</title>
+ <shortdesc>Compte de placements pour votre retraite et autres comptes associés.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous faites le suivi d'un compte de placements (actions, obligations, fonds communs et fonds d'indices boursiers) pour votre retraite.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Placements">
+ <account type="9" name="Retraite">
+ <account type="9" name="Obligations"/>
+ <account type="9" name="Fonds d'indices boursiers"/>
+ <account type="9" name="Fonds commun"/>
+ <account type="9" name="Actions"/>
+ </account>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CA/revenus.kmt b/kmymoney2/templates/fr_CA/revenus.kmt
new file mode 100644
index 0000000..0d62ea2
--- /dev/null
+++ b/kmymoney2/templates/fr_CA/revenus.kmt
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CA/acctchrt_revenus.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Revenus d'emploi</title>
+ <shortdesc>Comptes pour le suivi des revenus d'emploi.</shortdesc>
+ <longdesc>Sélectionnez ce groupe de comptes si vous voulez faire le suivi de vos revenus et dépenses d'emploi.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Taxes et impôts">
+ <account type="13" name="Emploi">
+ <account type="13" name="RAMQ/Medicare"/>
+ <account type="13" name="Provincial"/>
+ <account type="13" name="RRQ/RPC"/>
+ <account type="13" name="Fédéral"/>
+ <account type="13" name="Assurance emploi"/>
+ </account>
+ </account>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Emploi">
+ <account type="12" name="Frais remboursés"/>
+ <account type="12" name="Commisssions"/>
+ <account type="12" name="Salaire"/>
+ <account type="12" name="Primes"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/Makefile.am b/kmymoney2/templates/fr_CH/Makefile.am
new file mode 100644
index 0000000..6676bdf
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/fr_CH
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/fr_CH/brokerage.kmt b/kmymoney2/templates/fr_CH/brokerage.kmt
new file mode 100644
index 0000000..fc5331e
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'investissement</title>
+ <shortdesc>Compte de bourse/titres avec les comptes d'investissement apparentés (action, obligation, fond commun, fond d'indices, intérêt, dividende)</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des investissements (action, obligation, fond commun, fond d'indices, intérêt, dividende).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Commissions"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Revenu de dividende"/>
+ <account type="12" name="Revenu d'intérêts">
+ <account type="12" name="Intérêts d'obligation"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investissements">
+ <account type="7" name="Compte de bourse/titre"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/business.kmt b/kmymoney2/templates/fr_CH/business.kmt
new file mode 100644
index 0000000..cbd7ec5
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'affaires</title>
+ <shortdesc>Hiérarchie complète de comptes pour les affaires.</shortdesc>
+ <longdesc>Les utilisateurs gérant une entreprise sélectionneront ceci au lieu des autres choix. Ceci inclut tous les comptes dont vous avez besoin dans la plupart des activités, y compris les paiements différés, les rentrées et les sorties.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="Carte de crédit"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Gains enregistrés"/>
+ <account type="16" name="Soldes initiaux"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Location d'équipement"/>
+ <account type="13" name="Divers"/>
+ <account type="13" name="Réparations">
+ <account type="13" name="Réparations des équipements"/>
+ <account type="13" name="Réparations des immeubles"/>
+ <account type="13" name="Réparations des ordinateurs"/>
+ <account type="13" name="Dépenses d'entretien"/>
+ </account>
+ <account type="13" name="Poste et livraisons"/>
+ <account type="13" name="Formation"/>
+ <account type="13" name="Dépréciation"/>
+ <account type="13" name="Fournitures de bureau"/>
+ <account type="13" name="Charges professionelles">
+ <account type="13" name="Charges légales"/>
+ <account type="13" name="Comptabilité"/>
+ </account>
+ <account type="13" name="Impression et Reproduction"/>
+ <account type="13" name="Repas"/>
+ <account type="13" name="Cotisations et abonnements"/>
+ <account type="13" name="Licences et autorisations"/>
+ <account type="13" name="Remises"/>
+ <account type="13" name="Dépenses de personnel"/>
+ <account type="13" name="Services extérieurs"/>
+ <account type="13" name="Ajustement"/>
+ <account type="13" name="Voyages et divertissements">
+ <account type="13" name="Repas"/>
+ <account type="13" name="Voyages"/>
+ <account type="13" name="Divertissements"/>
+ </account>
+ <account type="13" name="Charité"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Réparations et entretien"/>
+ <account type="13" name="Carburant"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Frais"/>
+ </account>
+ <account type="13" name="Location"/>
+ <account type="13" name="Services">
+ <account type="13" name="Gaz"/>
+ <account type="13" name="Ordures ménagères"/>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Téléphone portable"/>
+ <account type="13" name="Câble"/>
+ <account type="13" name="Électricité"/>
+ <account type="13" name="Eau"/>
+ <account type="13" name="Téléphone"/>
+ </account>
+ <account type="13" name="Assurance">
+ <account type="13" name="Assurance incapacité"/>
+ <account type="13" name="Personnel"/>
+ <account type="13" name="Assurance responsabilité"/>
+ </account>
+ <account type="13" name="Frais bancaires"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Federal"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="Immobilier"/>
+ <account type="13" name="Local"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="Autres Taxes"/>
+ <account type="13" name="État/Département"/>
+ <account type="13" name="URSSAF"/>
+ </account>
+ <account type="13" name="Livres"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Revenus d'intérêts"/>
+ <account type="12" name="Ventes"/>
+ <account type="12" name="Autres rentrées"/>
+ <account type="12" name="Dépenses remboursées"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs actuels">
+ <account type="1" name="Compte d'épargne"/>
+ <account type="3" name="Liquidités"/>
+ <account type="1" name="Compte chèque"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/carloan.kmt b/kmymoney2/templates/fr_CH/carloan.kmt
new file mode 100644
index 0000000..0c90f7e
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Emprunt automobile</title>
+ <shortdesc>Comptes d'emprunt automobile et des intérets associés</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un emprunt automobile (emprunt automobile, intérêts d'emprunt automobile).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Intérêts emprunt automobile"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Emprunt automobile"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/cdmoneymkt.kmt b/kmymoney2/templates/fr_CH/cdmoneymkt.kmt
new file mode 100644
index 0000000..3675695
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD et marché monétaire</title>
+ <shortdesc>Comptes pour CD et investissements sur marché monétaire</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des CDs ou comptes de marché monétaire(CD, intérêt CD, marché monétaire, intérêt du marché monétaire).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Revenu d'intérêts">
+ <account type="12" name="Intérêt CD"/>
+ <account type="12" name="Intérêt du marché monétaire"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs actuels">
+ <account type="1" name="Marché monétaire"/>
+ <account type="1" name="CD bancaire"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/childcare.kmt b/kmymoney2/templates/fr_CH/childcare.kmt
new file mode 100644
index 0000000..e6dbce9
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dépenses de garderie</title>
+ <shortdesc>Un compte de suivi des coûts de garderie d'enfants</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des dépenses de garderie.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Garderie"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/common.kmt b/kmymoney2/templates/fr_CH/common.kmt
new file mode 100644
index 0000000..f5c90fa
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/common.kmt
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes communs</title>
+ <shortdesc>Un ensemble de base de comptes les plus habituellement utilisés</shortdesc>
+ <longdesc>La plupart des utilisateurs devront sélectionner cet ensemble de comptes. Il comprend la plupart des comptes communément utilisés (courant, épargne, liquidités carte de crédit, revenu, dépenses habituelles).</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Soldes initiaux"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs actuels">
+ <account type="1" name="Compte courant"/>
+ <account type="3" name="Argent du porte-monnaie"/>
+ <account type="1" name="Compte d'épargne"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Restaurant"/>
+ <account type="13" name="Transports publics"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Utilitaires">
+ <account type="13" name="Gaz"/>
+ <account type="13" name="Collecte d'ordures"/>
+ <account type="13" name="Eau"/>
+ <account type="13" name="Electricité"/>
+ </account>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Téléphone"/>
+ <account type="13" name="Services en ligne"/>
+ <account type="13" name="Alimentaire"/>
+ <account type="13" name="Loisirs">
+ <account type="13" name="Voyage"/>
+ <account type="13" name="Divertissements"/>
+ <account type="13" name="Musique/Films"/>
+ </account>
+ <account type="13" name="Livres"/>
+ <account type="13" name="Dons/Cadeaux"/>
+ <account type="13" name="Dépenses médicales"/>
+ <account type="13" name="Charité"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Carburant"/>
+ <account type="13" name="Maintenance et réparation"/>
+ <account type="13" name="Stationnement"/>
+ <account type="13" name="Frais"/>
+ </account>
+ <account type="13" name="Frais de service bancaire"/>
+ <account type="13" name="Vêtements"/>
+ <account type="13" name="Fournisseurs"/>
+ <account type="13" name="Assurances">
+ <account type="13" name="Assurance automobile"/>
+ <account type="13" name="Assurance vie"/>
+ <account type="13" name="Assurance santé"/>
+ </account>
+ <account type="13" name="Ajustement"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Etat/Province"/>
+ <account type="13" name="Assurance de base"/>
+ <account type="13" name="Impôts"/>
+ <account type="13" name="Complémentaire maladie"/>
+ <account type="13" name="Autres taxes"/>
+ </account>
+ <account type="13" name="Informatique"/>
+ <account type="13" name="Laverie/Pressing"/>
+ <account type="13" name="Divers"/>
+ <account type="13" name="Télévision"/>
+ <account type="13" name="Passe-temps"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Autre revenu"/>
+ <account type="12" name="Dons reçus"/>
+ <account type="12" name="Salaire"/>
+ <account type="12" name="Revenu d'intérêts">
+ <account type="12" name="Intérets du compte courant"/>
+ <account type="12" name="Autres intérêts"/>
+ <account type="12" name="Intérêts d'épargne"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Comptes de dettes">
+ <account type="4" name="Carte de crédit"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/currency.kmt b/kmymoney2/templates/fr_CH/currency.kmt
new file mode 100644
index 0000000..97ddbda
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Compte de commerce de devises/monnaies</title>
+ <shortdesc>Compte pour le commerce et la conversion d'une monnaie étrangère</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous convertissez des monnaies étrangères. Note: compte actuellement en DEM; editer le compte pour changer la monnaie.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investissements"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/eduloan.kmt b/kmymoney2/templates/fr_CH/eduloan.kmt
new file mode 100644
index 0000000..382e5ea
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Emprunt Etudiant</title>
+ <shortdesc>Comptes pour pour les emprunts étudiants et les intérêts associés.</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un emprunt étudiant (emprunt étudiant, intérêts d'emprunt étudiant).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Intérêts d'emprunt étudiant"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="emprunt étudiant"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/fixedassets.kmt b/kmymoney2/templates/fr_CH/fixedassets.kmt
new file mode 100644
index 0000000..79ca4f6
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Actifs fixes</title>
+ <shortdesc>Comptes pour le suivi d'actifs fixes importants</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des actifs fixes importants (maison, véhicule, résidence secondaire, autres actifs).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Actifs fixes">
+ <account type="9" name="véhicule"/>
+ <account type="9" name="Autre actif"/>
+ <account type="9" name="Maison"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/homeloan.kmt b/kmymoney2/templates/fr_CH/homeloan.kmt
new file mode 100644
index 0000000..85d5816
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hypothèque d'emprunt immobilier</title>
+ <shortdesc>Comptes pour emprunt immobilier et les intérets associés.</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un emprunt immobilier(Hypothèque d'un emprunt, Hypothèque sur des intérêts).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Hypothèque d'intérêts"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Hypothèque d'emprunt"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/homeown.kmt b/kmymoney2/templates/fr_CH/homeown.kmt
new file mode 100644
index 0000000..25ac283
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dépenses de propriétaire immobilier</title>
+ <shortdesc>Dépenses associés avec la possesion d'un logement</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un logement. Cet ensemble fournit un groupe de comptes pour suivre les dépenses du logement (assurance, taxes, entretien du logement).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Assurances">
+ <account type="13" name="Assurance habitation"/>
+ </account>
+ <account type="13" name="Taxes">
+ <account type="13" name="Taxe d'habitation"/>
+ </account>
+ <account type="13" name="Entretien logement"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/otherloan.kmt b/kmymoney2/templates/fr_CH/otherloan.kmt
new file mode 100644
index 0000000..d245c73
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Autres emprunts</title>
+ <shortdesc>Comptes pour le suivi d'autres emprunts et de leurs intérêts associés</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez quelque chose d'autre qu'un emprunt immobilier (autre emprunt, autres intérêts d'emprunt).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Autres intérets"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Autre emprunt"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/renter.kmt b/kmymoney2/templates/fr_CH/renter.kmt
new file mode 100644
index 0000000..41896a9
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dépenses de location</title>
+ <shortdesc>Dépenses associées avec la location d'un logement</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous louez une maison ou un appartement (location, assurance du locataire).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Location"/>
+ <account type="13" name="Assurances">
+ <account type="13" name="Assurance locative"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/retiremt.kmt b/kmymoney2/templates/fr_CH/retiremt.kmt
new file mode 100644
index 0000000..7a0d082
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'épargne retraite</title>
+ <shortdesc>Compte d'épargne retraite avec ses sous-comptes d'investissements relatifs</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des comptes d'épargne retraite (actions, obligations, fonds communs, fonds d'indices).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investissements">
+ <account type="7" name="Retraite"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/spouseinc.kmt b/kmymoney2/templates/fr_CH/spouseinc.kmt
new file mode 100644
index 0000000..d0b7318
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Revenus de l'épouse</title>
+ <shortdesc>Comptes pour le suivi des revenus de l'épouse séparément</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez une épouse travaillant (salaire (épouse), impôts (épouse)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Salaire (épouse)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Taxes (épouse)">
+ <account type="13" name="Sécurité sociale"/>
+ <account type="13" name="Complémentaire maladie"/>
+ <account type="13" name="Etat/Province"/>
+ <account type="13" name="Impôts"/>
+ <account type="13" name="Autres taxes"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_CH/spouseretire.kmt b/kmymoney2/templates/fr_CH/spouseretire.kmt
new file mode 100644
index 0000000..afe7db7
--- /dev/null
+++ b/kmymoney2/templates/fr_CH/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_CH/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'épargne retraite de l'épouse</title>
+ <shortdesc>Compte d'épargne retraite avec ses sous-comptes d'investissements relatifs de l'épouse</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des comptes d'épargne retraite de l'épouse(actions, obligations, fonds communs, fonds d'indices, intérêts, dividendes).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investissements">
+ <account type="7" name="Retraite de l'épouse"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/Makefile.am b/kmymoney2/templates/fr_FR/Makefile.am
new file mode 100644
index 0000000..b320632
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/fr_FR
+
+template_DATA = homeown.kmt comptes_par_default.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/fr_FR/brokerage.kmt b/kmymoney2/templates/fr_FR/brokerage.kmt
new file mode 100644
index 0000000..91700fc
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'investissement</title>
+ <shortdesc>Compte de bourse/titres avec les comptes d'investissement apparentés (action, obligation, fond commun, fond d'indices, intérêt, dividende)</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des investissements (action, obligation, fond commun, fond d'indices, intérêt, dividende).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Commissions"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Revenu de dividende"/>
+ <account type="12" name="Revenu d'intérêts">
+ <account type="12" name="Intérêts d'obligation"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investissements">
+ <account type="7" name="Compte de bourse/titre"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/business.kmt b/kmymoney2/templates/fr_FR/business.kmt
new file mode 100644
index 0000000..87537ba
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'affaires</title>
+ <shortdesc>Hiérarchie complète de comptes pour les affaires.</shortdesc>
+ <longdesc>Les utilisateurs gérant une entreprise sélectionneront ceci au lieu des autres choix. Ceci inclut tous les comptes dont vous avez besoin dans la plupart des activités, y compris les paiements différés, les rentrées et les sorties.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="Carte de crédit"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Gains enregistrés"/>
+ <account type="16" name="Soldes initiaux"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Location d'équipement"/>
+ <account type="13" name="Divers"/>
+ <account type="13" name="Réparations">
+ <account type="13" name="Réparations des équipements"/>
+ <account type="13" name="Réparations des immeubles"/>
+ <account type="13" name="Réparations des ordinateurs"/>
+ <account type="13" name="Dépenses d'entretien"/>
+ </account>
+ <account type="13" name="Poste et livraisons"/>
+ <account type="13" name="Formation"/>
+ <account type="13" name="Dépréciation"/>
+ <account type="13" name="Fournitures de bureau"/>
+ <account type="13" name="Charges professionelles">
+ <account type="13" name="Charges légales"/>
+ <account type="13" name="Comptabilité"/>
+ </account>
+ <account type="13" name="Impression et Reproduction"/>
+ <account type="13" name="Repas"/>
+ <account type="13" name="Cotisations et abonnements"/>
+ <account type="13" name="Licences et autorisations"/>
+ <account type="13" name="Remises"/>
+ <account type="13" name="Dépenses de personnel"/>
+ <account type="13" name="Services extérieurs"/>
+ <account type="13" name="Ajustement"/>
+ <account type="13" name="Voyages et divertissements">
+ <account type="13" name="Repas"/>
+ <account type="13" name="Voyages"/>
+ <account type="13" name="Divertissements"/>
+ </account>
+ <account type="13" name="Charité"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Réparations et entretien"/>
+ <account type="13" name="Carburant"/>
+ <account type="13" name="Parking"/>
+ <account type="13" name="Frais"/>
+ </account>
+ <account type="13" name="Location"/>
+ <account type="13" name="Services">
+ <account type="13" name="Gaz"/>
+ <account type="13" name="Ordures ménagères"/>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Téléphone portable"/>
+ <account type="13" name="Câble"/>
+ <account type="13" name="Électricité"/>
+ <account type="13" name="Eau"/>
+ <account type="13" name="Téléphone"/>
+ </account>
+ <account type="13" name="Assurance">
+ <account type="13" name="Assurance incapacité"/>
+ <account type="13" name="Personnel"/>
+ <account type="13" name="Assurance responsabilité"/>
+ </account>
+ <account type="13" name="Frais bancaires"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Federal"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="Immobilier"/>
+ <account type="13" name="Local"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="Autres Taxes"/>
+ <account type="13" name="État/Département"/>
+ <account type="13" name="URSSAF"/>
+ </account>
+ <account type="13" name="Livres"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Revenus d'intérêts"/>
+ <account type="12" name="Ventes"/>
+ <account type="12" name="Autres rentrées"/>
+ <account type="12" name="Dépenses remboursées"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs actuels">
+ <account type="1" name="Compte d'épargne"/>
+ <account type="3" name="Liquidités"/>
+ <account type="1" name="Compte chèque"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/carloan.kmt b/kmymoney2/templates/fr_FR/carloan.kmt
new file mode 100644
index 0000000..5f89bad
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Emprunt automobile</title>
+ <shortdesc>Comptes d'emprunt automobile et des intérets associés</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un emprunt automobile (emprunt automobile, intérêts d'emprunt automobile).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Intérêts emprunt automobile"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Emprunt automobile"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/cdmoneymkt.kmt b/kmymoney2/templates/fr_FR/cdmoneymkt.kmt
new file mode 100644
index 0000000..ed8d459
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD et marché monétaire</title>
+ <shortdesc>Comptes pour CD et investissements sur marché monétaire</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des CDs ou comptes de marché monétaire(CD, intérêt CD, marché monétaire, intérêt du marché monétaire).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Revenu d'intérêts">
+ <account type="12" name="Intérêt CD"/>
+ <account type="12" name="Intérêt du marché monétaire"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs actuels">
+ <account type="1" name="Marché monétaire"/>
+ <account type="1" name="CD bancaire"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/childcare.kmt b/kmymoney2/templates/fr_FR/childcare.kmt
new file mode 100644
index 0000000..c6c03d6
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dépenses de garderie</title>
+ <shortdesc>Un compte de suivi des coûts de garderie d'enfants</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des dépenses de garderie.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Garderie"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/common.kmt b/kmymoney2/templates/fr_FR/common.kmt
new file mode 100644
index 0000000..ff43989
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/common.kmt
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes communs</title>
+ <shortdesc>Un ensemble de base de comptes les plus habituellement utilisés</shortdesc>
+ <longdesc>La plupart des utilisateurs devront sélectionner cet ensemble de comptes. Il comprend la plupart des comptes communément utilisés (chèques, épargne, liquidités carte de crédit, revenu, dépenses habituelles).</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Soldes initiaux"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Actifs actuels">
+ <account type="1" name="Compte chèques"/>
+ <account type="3" name="Argent du porte-monnaie"/>
+ <account type="1" name="Compte d'épargne"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Restaurant"/>
+ <account type="13" name="Transports publics"/>
+ <account type="13" name="Education"/>
+ <account type="13" name="Utilitaires">
+ <account type="13" name="Gaz"/>
+ <account type="13" name="Collecte d'ordures"/>
+ <account type="13" name="Eau"/>
+ <account type="13" name="Electricité"/>
+ </account>
+ <account type="13" name="Abonnements"/>
+ <account type="13" name="Téléphone"/>
+ <account type="13" name="Services en ligne"/>
+ <account type="13" name="Alimentaire"/>
+ <account type="13" name="Loisirs">
+ <account type="13" name="Voyage"/>
+ <account type="13" name="Divertissements"/>
+ <account type="13" name="Musique/Films"/>
+ </account>
+ <account type="13" name="Livres"/>
+ <account type="13" name="Dons/Cadeaux"/>
+ <account type="13" name="Dépenses médicales"/>
+ <account type="13" name="Charité"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Carburant"/>
+ <account type="13" name="Maintenance et réparation"/>
+ <account type="13" name="Stationnement"/>
+ <account type="13" name="Frais"/>
+ </account>
+ <account type="13" name="Frais de service bancaire"/>
+ <account type="13" name="Vêtements"/>
+ <account type="13" name="Fournisseurs"/>
+ <account type="13" name="Assurances">
+ <account type="13" name="Assurance automobile"/>
+ <account type="13" name="Assurance vie"/>
+ <account type="13" name="Assurance santé"/>
+ </account>
+ <account type="13" name="Ajustement"/>
+ <account type="13" name="Taxes">
+ <account type="13" name="Etat/Province"/>
+ <account type="13" name="Sécurité sociale"/>
+ <account type="13" name="Impôts"/>
+ <account type="13" name="Complémentaire maladie"/>
+ <account type="13" name="Autres taxes"/>
+ </account>
+ <account type="13" name="Informatique"/>
+ <account type="13" name="Laverie/Pressing"/>
+ <account type="13" name="Divers"/>
+ <account type="13" name="Cable"/>
+ <account type="13" name="Passe-temps"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Autre revenu"/>
+ <account type="12" name="Dons reçus"/>
+ <account type="12" name="Salaire"/>
+ <account type="12" name="Revenu d'intérêts">
+ <account type="12" name="Intérets du compte chèque"/>
+ <account type="12" name="Autres intérêts"/>
+ <account type="12" name="Intérêts d'épargne"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Comptes de dettes">
+ <account type="4" name="Carte de crédit"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/comptes_par_default.kmt b/kmymoney2/templates/fr_FR/comptes_par_default.kmt
new file mode 100644
index 0000000..b3b66bb
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/comptes_par_default.kmt
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 default</title>
+ <shortdesc></shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Alimentation" type="13">
+ <account name="Restaurant" type="13"/>
+ <account name="Epicerie" type="13"/>
+ <account name="Supermarché" type="13"/>
+ <account name="Cantine" type="13"/>
+ </account>
+ <account name="Animaux" type="13">
+ <account name="Alimentation" type="13"/>
+ <account name="Fournitures" type="13"/>
+ <account name="Vétérinaire" type="13"/>
+ <account name="Toilettage" type="13"/>
+ </account>
+ <account name="Assurance" type="13">
+ <account name="Automobile" type="13"/>
+ <account name="Habitation" type="13"/>
+ <account name="Responsabilité civile" type="13"/>
+ <account name="Santé" type="13"/>
+ <account name="Vie" type="13"/>
+ </account>
+ <account name="Automobile" type="13">
+ <account name="Achat" type="13"/>
+ <account name="Amendes" type="13"/>
+ <account name="Assurance" type="13"/>
+ <account name="Carburant" type="13"/>
+ <account name="Contrôle technique" type="13"/>
+ <account name="Péage" type="13"/>
+ <account name="Réparations" type="13"/>
+ <account name="Stationnement" type="13"/>
+ </account>
+ <account name="Dépenses professionelles" type="13">
+ <account name="Non-remboursées" type="13"/>
+ <account name="Remboursées" type="13"/>
+ </account>
+ <account name="Dons" type="13">
+ <account name="Cadeaux" type="13"/>
+ <account name="Donations" type="13"/>
+ <account name="Caritatif" type="13"/>
+ </account>
+ <account name="Education" type="13">
+ <account name="Frais scolaires" type="13"/>
+ <account name="Leçons" type="13"/>
+ <account name="Fournitures" type="13"/>
+ </account>
+ <account name="Enfants" type="13">
+ <account name="Crêche et nourrice" type="13"/>
+ </account>
+ <account name="Frais bancaires" type="13">
+ <account name="Intérêts" type="13"/>
+ <account name="Services bancaires" type="13"/>
+ <account name="Pénalités bancaires" type="13"/>
+ </account>
+ <account name="Frais généraux" type="13">
+ <account name="Charges de loyer" type="13"/>
+ <account name="Chauffage" type="13"/>
+ <account name="Eau" type="13"/>
+ <account name="Electricité" type="13"/>
+ <account name="Gaz" type="13"/>
+ <account name="Internet" type="13"/>
+ <account name="Loyer" type="13"/>
+ <account name="Rembousement de prêt" type="13"/>
+ <account name="Téléphone" type="13"/>
+ <account name="Téléphone portable" type="13"/>
+ <account name="Câble et satellite" type="13"/>
+ </account>
+ <account name="Soins" type="13">
+ <account name="Coiffeur" type="13"/>
+ <account name="Esthétique" type="13"/>
+ <account name="Habillement" type="13"/>
+ </account>
+ <account name="Loisirs" type="13">
+ <account name="Billard" type="13"/>
+ <account name="Bowling" type="13"/>
+ <account name="Cassettes et CDs" type="13"/>
+ <account name="Cinéma" type="13"/>
+ <account name="Discothèque" type="13"/>
+ <account name="Divertissement" type="13"/>
+ <account name="Equipements sportifs" type="13"/>
+ <account name="Informatique" type="13"/>
+ <account name="Jeux et jouets" type="13"/>
+ <account name="Livres et Magazines" type="13"/>
+ <account name="Musées et expositions" type="13"/>
+ <account name="Parc d'attraction" type="13"/>
+ <account name="Spectacles" type="13"/>
+ <account name="Sport" type="13"/>
+ <account name="Vidéo" type="13"/>
+ </account>
+ <account name="Maison" type="13">
+ <account name="Ameublement" type="13"/>
+ <account name="Entretien" type="13"/>
+ <account name="Equipement" type="13"/>
+ <account name="Jardinage" type="13"/>
+ <account name="Personnel de maison" type="13"/>
+ <account name="Travaux" type="13"/>
+ </account>
+ <account name="Prêt" type="13">
+ <account name="Intérêts de prêt" type="13"/>
+ <account name="Amortissement de prêt" type="13"/>
+ <account name="Remboursement anticipé de prêt" type="13"/>
+ <account name="Frais de remboursement anticipé" type="13"/>
+ <account name="Assurance" type="13"/>
+ <account name="Frais de dossier" type="13"/>
+ </account>
+ <account name="Retrait d'espèces" type="13"/>
+ <account name="Santé" type="13">
+ <account name="Dentiste" type="13"/>
+ <account name="Hôpital" type="13"/>
+ <account name="Médecin généraliste" type="13"/>
+ <account name="Médecin spécialiste" type="13"/>
+ <account name="Opticien" type="13"/>
+ <account name="Pharmacie" type="13"/>
+ </account>
+ <account name="Taxes et impôts" type="13">
+ <account name="Autres taxes" type="13"/>
+ <account name="Intérêts de retard" type="13"/>
+ <account name="Impôts sur le revenu" type="13"/>
+ <account name="Redevance télévisuelle" type="13"/>
+ <account name="Taxe foncière" type="13"/>
+ <account name="Taxe d'habitation" type="13"/>
+ <account name="ISF" type="13"/>
+ </account>
+ <account name="Transport" type="13">
+ <account name="Train" type="13"/>
+ <account name="Transports en commun" type="13"/>
+ </account>
+ <account name="Vacances" type="13">
+ <account name="Logement" type="13"/>
+ <account name="Frais divers" type="13"/>
+ <account name="Voyage" type="13"/>
+ </account>
+ <account name="Retenues sur salaire" type="13">
+ <account name="Véhicule de fonction" type="13"/>
+ <account name="Chèques déjeuner" type="13"/>
+ <account name="Autres avantages en nature" type="13"/>
+ <account name="Remboursement d'acompte" type="13"/>
+ <account name="Remboursement d'avance" type="13"/>
+ <account name="Saisie Opposition" type="13"/>
+ </account>
+ <account name="Autres dépenses" type="13">
+ <account name="Cadeaux" type="13"/>
+ </account>
+ </account>
+ <account name="" type="12">
+ <account name="Revenus du travail" type="12">
+ <account name="Salaire brut" type="12"/>
+ <account name="Salaire net" type="12"/>
+ <account name="Commissions" type="12"/>
+ <account name="Prime" type="12"/>
+ <account name="Avance sur paie" type="12"/>
+ <account name="Acompte sur paie" type="12"/>
+ <account name="Heures supplémentaires" type="12"/>
+ <account name="Participation aux bénéfices" type="12"/>
+ <account name="Participation aux résultats" type="12"/>
+ <account name="Plus-values de Stock-Options" type="12"/>
+ <account name="Remboursements de frais professionnels" type="12"/>
+ </account>
+ <account name="Rentes et pensions" type="12">
+ <account name="Retraite du régime général" type="12"/>
+ <account name="Retraite complémentaire" type="12"/>
+ <account name="Rentes viagères" type="12"/>
+ <account name="Rentes temporaires" type="12"/>
+ </account>
+ <account name="Allocations et Sécurité sociale" type="12">
+ <account name="Remboursement de frais de santé" type="12"/>
+ <account name="Allocations familiales" type="12"/>
+ <account name="ASSEDICs" type="12"/>
+ <account name="Indemnités Journalières" type="12"/>
+ <account name="Veuvage" type="12"/>
+ <account name="Invalidité" type="12"/>
+ <account name="Bourses d'étude" type="12"/>
+ <account name="Allocations de logement" type="12"/>
+ <account name="Prêts d'honneur" type="12"/>
+ </account>
+ <account name="Revenus d'investissement" type="12">
+ <account name="Plus-values Boursières" type="12"/>
+ <account name="Intérêts de livret A et Bleu" type="12"/>
+ <account name="Intérêts de livret B" type="12"/>
+ <account name="Intérêts de CoDevI" type="12"/>
+ <account name="Intérêts de LEP" type="12"/>
+ <account name="Intérêts de livrets bancaires" type="12"/>
+ <account name="Coupon" type="12"/>
+ <account name="Dividende" type="12"/>
+ <account name="Prime d'Etat sur Epargne Logement" type="12"/>
+ </account>
+ <account name="Autres revenus" type="12">
+ <account name="Cadeaux recus" type="12"/>
+ <account name="Déblocage de prêt" type="12"/>
+ <account name="Gains aux jeux" type="12"/>
+ <account name="Crédits d'impôts" type="12"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/currency.kmt b/kmymoney2/templates/fr_FR/currency.kmt
new file mode 100644
index 0000000..57c3ea6
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Compte de commerce de devises/monnaies</title>
+ <shortdesc>Compte pour le commerce et la conversion d'une monnaie étrangère</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous convertissez des monnaies étrangères. Note: compte actuellement en DEM; editer le compte pour changer la monnaie.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investissements"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/eduloan.kmt b/kmymoney2/templates/fr_FR/eduloan.kmt
new file mode 100644
index 0000000..369cc81
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Emprunt Etudiant</title>
+ <shortdesc>Comptes pour pour les emprunts étudiants et les intérêts associés.</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un emprunt étudiant (emprunt étudiant, intérêts d'emprunt étudiant).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Intérêts d'emprunt étudiant"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="emprunt étudiant"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/fixedassets.kmt b/kmymoney2/templates/fr_FR/fixedassets.kmt
new file mode 100644
index 0000000..cfa5e78
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Actifs fixes</title>
+ <shortdesc>Comptes pour le suivi d'actifs fixes importants</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des actifs fixes importants (maison, véhicule, résidence secondaire, autres actifs).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Actifs fixes">
+ <account type="9" name="véhicule"/>
+ <account type="9" name="Autre actif"/>
+ <account type="9" name="Maison"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/homeloan.kmt b/kmymoney2/templates/fr_FR/homeloan.kmt
new file mode 100644
index 0000000..7c5fbc3
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hypothèque d'emprunt immobilier</title>
+ <shortdesc>Comptes pour emprunt immobilier et les intérets associés.</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un emprunt immobilier(Hypothèque d'un emprunt, Hypothèque sur des intérêts).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Hypothèque d'intérêts"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Hypothèque d'emprunt"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/homeown.kmt b/kmymoney2/templates/fr_FR/homeown.kmt
new file mode 100644
index 0000000..0cd1fc9
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dépenses de propriétaire immobilier</title>
+ <shortdesc>Dépenses associés avec la possesion d'un logement</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez un logement. Cet ensemble fournit un groupe de comptes pour suivre les dépenses du logement (assurance, taxes, entretien du logement).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Assurances">
+ <account type="13" name="Assurance habitation"/>
+ </account>
+ <account type="13" name="Taxes">
+ <account type="13" name="Taxe d'habitation"/>
+ </account>
+ <account type="13" name="Entretien logement"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/otherloan.kmt b/kmymoney2/templates/fr_FR/otherloan.kmt
new file mode 100644
index 0000000..bea8f36
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Autres emprunts</title>
+ <shortdesc>Comptes pour le suivi d'autres emprunts et de leurs intérêts associés</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez quelque chose d'autre qu'un emprunt immobilier (autre emprunt, autres intérêts d'emprunt).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Intérêts">
+ <account type="13" name="Autres intérets"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Emprunts">
+ <account type="10" name="Autre emprunt"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/renter.kmt b/kmymoney2/templates/fr_FR/renter.kmt
new file mode 100644
index 0000000..b5c338f
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dépenses de location</title>
+ <shortdesc>Dépenses associées avec la location d'un logement</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous louez une maison ou un appartement (location, assurance du locataire).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Location"/>
+ <account type="13" name="Assurances">
+ <account type="13" name="Assurance locative"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/retiremt.kmt b/kmymoney2/templates/fr_FR/retiremt.kmt
new file mode 100644
index 0000000..d3786a8
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'épargne retraite</title>
+ <shortdesc>Compte d'épargne retraite avec ses sous-comptes d'investissements relatifs</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des comptes d'épargne retraite (actions, obligations, fonds communs, fonds d'indices).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investissements">
+ <account type="7" name="Retraite"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/spouseinc.kmt b/kmymoney2/templates/fr_FR/spouseinc.kmt
new file mode 100644
index 0000000..85247e3
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Revenus de l'épouse</title>
+ <shortdesc>Comptes pour le suivi des revenus de l'épouse séparément</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez une épouse travaillant (salaire (épouse), impôts (épouse)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Salaire (épouse)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Taxes (épouse)">
+ <account type="13" name="Sécurité sociale"/>
+ <account type="13" name="Complémentaire maladie"/>
+ <account type="13" name="Etat/Province"/>
+ <account type="13" name="Impôts"/>
+ <account type="13" name="Autres taxes"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/fr_FR/spouseretire.kmt b/kmymoney2/templates/fr_FR/spouseretire.kmt
new file mode 100644
index 0000000..53e9eca
--- /dev/null
+++ b/kmymoney2/templates/fr_FR/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/fr_FR/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Comptes d'épargne retraite de l'épouse</title>
+ <shortdesc>Compte d'épargne retraite avec ses sous-comptes d'investissements relatifs de l'épouse</shortdesc>
+ <longdesc>Vous devriez sélectionner cet ensemble de comptes si vous avez des comptes d'épargne retraite de l'épouse(actions, obligations, fonds communs, fonds d'indices, intérêts, dividendes).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investissements">
+ <account type="7" name="Retraite de l'épouse"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/gl_ES/Makefile.am b/kmymoney2/templates/gl_ES/Makefile.am
new file mode 100644
index 0000000..74c4db6
--- /dev/null
+++ b/kmymoney2/templates/gl_ES/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/gl_ES
+
+template_DATA = default_accounts.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/gl_ES/default_accounts.kmt b/kmymoney2/templates/gl_ES/default_accounts.kmt
new file mode 100644
index 0000000..80432f4
--- /dev/null
+++ b/kmymoney2/templates/gl_ES/default_accounts.kmt
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas de uso xeral</title>
+ <shortdesc>Contas de ingresos, gastos, e activos de exemplo</shortdesc>
+ <longdesc>As contas de gasto definidas neste modelo seguen a estrutura das empregadas a nível europeu desde 1998 para definir o índice harmonizado de prezos no consumidor, as de ingresos son un subconxunto das que o autor deste ficheiro usou con maior frecuencia, ao igual que as de activos. Non se inclúe nengún pasivo. Para máis información acerca das categorías de gasto consulte: http://eur-lex.europa.eu/LexUriServ/site/pt/oj/1998/l_214/l_21419980731pt00120022.pdf</longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Alimentos e bebidas non alcohólicas" type="13" description="">
+ <account name="Alimentos" type="13"/>
+ <account name="Bebidas non alcohólicas" type="13"/>
+ </account>
+ <account name="Bebidas alcohólicas, tabaco e estupefacientes" type="13">
+ <account name="Bebidas alcohólicas" type="13"/>
+ <account name="Tabaco" type="13"/>
+ <account name="Estupefacientes" type="13"/>
+ </account>
+ <account name="Roupa e calzado" type="13">
+ <account name="Roupa" type="13"/>
+ <account name="Calzado" type="13"/>
+ </account>
+ <account name="Aloxamento, auga, electricidade, gas e outros combustíbeis" type="13">
+ <account name="Alugueres efectivos da vivenda" type="13"/>
+ <account name="Alugueres imputados da vivenda" type="13"/>
+ <account name="Conservación e reparación da vivenda" type="13"/>
+ <account name="Subministración de auga, e servizos diversos" type="13"/>
+ <account name="Electricidade, gas e outros combustíbeis" type="13"/>
+ </account>
+ <account name="Móbeis, cousas do lar e mantimento da casa" type="13">
+ <account name="Móbeis e acesorios, alfombras e outros materiais para pisos" type="13"/>
+ <account name="Produtos textís para o fogar" type="13"/>
+ <account name="Artefactos para o fogar" type="13"/>
+ <account name="Mercadorías de vidro e cristal, vaixela e utensilios para o fogar" type="13"/>
+ <account name="Ferramentas e úteis para o fogar e xardín" type="13"/>
+ <account name="Bens e servizos para a conservación ordinaria do fogar" type="13"/>
+ </account>
+ <account name="Saúde" type="13">
+ <account name="Produtos, artefactos e equipo médico" type="13"/>
+ <account name="Servizos para pacientes externos" type="13"/>
+ <account name="Servizos de hospital" type="13"/>
+ </account>
+ <account name="Transporte" type="13">
+ <account name="Adquisición de vehículos" type="13"/>
+ <account name="Funcionamentos de equipos de transporte persoal" type="13"/>
+ <account name="Servizos de transporte" type="13"/>
+ </account>
+ <account name="Comunicacións" type="13">
+ <account name="Servizos postais" type="13"/>
+ <account name="Equipo telefónico e de fax" type="13"/>
+ <account name="Servizos telefónicos e de fax" type="13"/>
+ </account>
+ <account name="Lecer e cultura" type="13">
+ <account name="Equipos audiovisuais, fotográficos e de procesamento de información" type="13"/>
+ <account name="Outros produtos duradeiros importantes para lecer e cultura" type="13"/>
+ <account name="Outras mercadorías e equipación para lecer, xardíns e animais domésticos" type="13"/>
+ <account name="Servizos de recreación e culturais" type="13"/>
+ <account name="Periódicos, libros e papeis e úteis de oficina" type="13"/>
+ <account name="Paquetes turísticos" type="13"/>
+ </account>
+ <account name="Educación" type="13">
+ <account name="Ensinanza preescolar e primaria" type="13"/>
+ <account name="Ensinanza secundaria" type="13"/>
+ <account name="Ensinanza postsecundaria, non terciaria" type="13"/>
+ <account name="Ensinanza terciaria" type="13"/>
+ <account name="Ensinanza non atribuíbel a nengún nível" type="13"/>
+ </account>
+ <account name="Restaurantes e hoteis" type="13">
+ <account name="Servizos de catering" type="13"/>
+ <account name="Servizos de aloxamento" type="13"/>
+ </account>
+ <account name="Bens e servizos diversos" type="13">
+ <account name="Coidado persoal" type="13"/>
+ <account name="Artigos persoais n.e.p." type="13"/>
+ <account name="Protección social" type="13"/>
+ <account name="Seguros" type="13"/>
+ <account name="Servizos financeiros n.e.p." type="13"/>
+ <account name="Outros servizos n.e.p." type="13"/>
+ </account>
+ </account>
+
+ <account name="" type="12">
+ <account name="Outros Ingresos" type="12">
+ <account name="Becas" type="12"/>
+ <account name="Agasallos Recebidos" type="12"/>
+ <account name="Loterias" type="12"/>
+ <account name="Devoluzón de Impostos" type="12"/>
+ <account name="Pensión Recebida para Fillos" type="12"/>
+ </account>
+ <account name="Seguridade Social" type="12">
+ <account name="Pensión de Xubilazón" type="12"/>
+ <account name="Pensión non contributiva" type="12"/>
+ <account name="Baixa laboral" type="12"/>
+ <account name="Seguro Desemprego" type="12"/>
+ </account>
+ <account name="Rendimentos de Investimentos" type="12">
+ <account name="Dividendos" type="12"/>
+ <account name="Gañancias de Capital" type="12"/>
+ <account name="Xuros" type="12"/>
+ </account>
+ <account name="Salario" type="12">
+ <account name="Bonus" type="12"/>
+ <account name="Comisións" type="12"/>
+ <account name="Primas de Produzón" type="12"/>
+ <account name="Salario Bruto" type="12"/>
+ <account name="Salario Neto" type="12"/>
+ <account name="Horas Extras" type="12"/>
+ </account>
+ </account>
+
+ <account name="" type="9">
+ <account name="Activo líquido" type="1">
+ <account name="Cartos en mao" type="1"/>
+ <account name="Conta corrente" type="1"/>
+ </account>
+ <account name="Activo fixo" type="1">
+ <account name="Coche" type="9"/>
+ <account name="Casa" type="9"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/header_template b/kmymoney2/templates/header_template
new file mode 100644
index 0000000..18f3519
--- /dev/null
+++ b/kmymoney2/templates/header_template
@@ -0,0 +1,30 @@
+/***************************************************************************
+ |FILENAME| - description
+ -------------------
+ begin : |DATE|
+ copyright : (C) 2000-|YEAR| by |AUTHOR|
+ email : |EMAIL|
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
diff --git a/kmymoney2/templates/hu_HU/Makefile.am b/kmymoney2/templates/hu_HU/Makefile.am
new file mode 100644
index 0000000..be0f096
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/hu_HU
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt checkbook.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/hu_HU/brokerage.kmt b/kmymoney2/templates/hu_HU/brokerage.kmt
new file mode 100644
index 0000000..441e889
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Befektetési számlák</title>
+ <shortdesc>Brókerszámla a hozzá tartozó befektetési számlákkal (részvény, kötvény, befektetési alap, hozam, kamat, osztalék)</shortdesc>
+ <longdesc>Jelölje ki e számlahalmazt, ha foglalkozik befektetésekkel (részvény, kötvény, befektetési alap, hozam, kamat, osztalék)!</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Jutalék"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Osztalék"/>
+ <account type="12" name="Kamat">
+ <account type="12" name="Kötvény kamat"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Befektetések">
+ <account type="7" name="Brókerszámla"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/business.kmt b/kmymoney2/templates/hu_HU/business.kmt
new file mode 100644
index 0000000..9f2cd71
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Vállalkozás-számlák</title>
+ <shortdesc>Teljes számlakészlet vállalkozásoknak.</shortdesc>
+ <longdesc>Vállalkozóknak inkább ez ajánlott, a többi lehetőség helyett. Ez tartalmazza az összes számlát, amelyre egy vállalkozásnak leggyakrabban szüksége van. Tartalmazza Kötelezettségek-, Követelések-, Bevétel- és Költségszámlákat.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="Hitelkártya"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Céltartalékok"/>
+ <account type="16" name="Nyitóegyenlegek"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Felszerelés kölcsönzés"/>
+ <account type="13" name="Különféle"/>
+ <account type="13" name="Javítások">
+ <account type="13" name="Felszerelés javítások"/>
+ <account type="13" name="Épületjavítás"/>
+ <account type="13" name="Számítógép javítások"/>
+ <account type="13" name="Épület-karbantartás"/>
+ </account>
+ <account type="13" name="Postaköltség és futárszolgálat"/>
+ <account type="13" name="Képzés"/>
+ <account type="13" name="Értékcsökkenés"/>
+ <account type="13" name="Irodaszerek"/>
+ <account type="13" name="Szakértői illetmény">
+ <account type="13" name="Jogi költségek"/>
+ <account type="13" name="Könyvelés"/>
+ </account>
+ <account type="13" name="Nyomtatás és fénymásolás"/>
+ <account type="13" name="Étkezés"/>
+ <account type="13" name="Tagdíjak és előfizetések"/>
+ <account type="13" name="Jogosítványok és engedélyek"/>
+ <account type="13" name="Árengedmények"/>
+ <account type="13" name="Munkabér"/>
+ <account type="13" name="Külső szolgáltatások"/>
+ <account type="13" name="Kiigazítás"/>
+ <account type="13" name="Utazás és Szórakozás">
+ <account type="13" name="Étkezések"/>
+ <account type="13" name="Utazás"/>
+ <account type="13" name="Szórakozás"/>
+ </account>
+ <account type="13" name="Jótékonyság"/>
+ <account type="13" name="Autó">
+ <account type="13" name="Javítás és karbantartás"/>
+ <account type="13" name="Üzemanyag"/>
+ <account type="13" name="Parkolás"/>
+ <account type="13" name="Díjak"/>
+ </account>
+ <account type="13" name="Bérleti díj"/>
+ <account type="13" name="Rezsi">
+ <account type="13" name="Gáz"/>
+ <account type="13" name="Szemétszállítás"/>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Mobil telefon"/>
+ <account type="13" name="Kábel TV"/>
+ <account type="13" name="Villany"/>
+ <account type="13" name="Víz"/>
+ <account type="13" name="Telefon"/>
+ </account>
+ <account type="13" name="Biztosítás">
+ <account type="13" name="Rokkantsági biztosítás"/>
+ <account type="13" name="Felelősségbiztosítás"/>
+ </account>
+ <account type="13" name="Bankköltség"/>
+ <account type="13" name="Adók">
+ <account type="13" name="Nyereségadó"/>
+ <account type="13" name="TBJ"/>
+ <account type="13" name="Munkavállalói járulék"/>
+ <account type="13" name="Ingatlanadó"/>
+ <account type="13" name="Helyi adók"/>
+ <account type="13" name="IJ"/>
+ <account type="13" name="Egyéb adók"/>
+ <account type="13" name="ÁFA"/>
+ <account type="13" name="EVA"/>
+ </account>
+ <account type="13" name="Könyvek"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Kamatbevétel"/>
+ <account type="12" name="Eladások"/>
+ <account type="12" name="Egyéb bevétel"/>
+ <account type="12" name="Visszatérített költségek"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Forgóeszközök">
+ <account type="1" name="Betétszámla"/>
+ <account type="3" name="Készpénz"/>
+ <account type="1" name="Folyószámla"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/carloan.kmt b/kmymoney2/templates/hu_HU/carloan.kmt
new file mode 100644
index 0000000..b921733
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Autóhitel</title>
+ <shortdesc>Számlák autóhitelhez és annak kamataihoz</shortdesc>
+ <longdesc>Akkor érdemes ezt kiválasztani, ha ön vásárol autót hitelre (autóhitel, autóhitelkamat).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kamat">
+ <account type="13" name="Járműhitelkamat"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Hitelek">
+ <account type="10" name="Járműhitel"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/cdmoneymkt.kmt b/kmymoney2/templates/hu_HU/cdmoneymkt.kmt
new file mode 100644
index 0000000..7010dbc
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD és pénzpiaci</title>
+ <shortdesc>Számlák befektetési jegyekhez és pénzpiaci befektetésekhez</shortdesc>
+ <longdesc>Akkor érdemes kiválasztani, ha önnek van befektetési jegye vagy pénzpiaci számlája (CD, CD-kamat, pénzpiaci, pénzpiaci kamat)</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Kamatbevétel">
+ <account type="12" name="CD-kamat"/>
+ <account type="12" name="Pénzpiaci kamat"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Forgóeszközök">
+ <account type="1" name="Pénzpiaci"/>
+ <account type="1" name="CD"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/checkbook.kmt b/kmymoney2/templates/hu_HU/checkbook.kmt
new file mode 100644
index 0000000..6fa2240
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Egyszerű folyószámla</title>
+ <shortdesc>Minimális számlakészlet GnuCash használatához.</shortdesc>
+ <longdesc>Akkor érdemes ezt kiválasztani, ha csak a folyószámlája forgalmát kívánja ellenőrizni. Később elkezdheti a bevételei és költségei alaposabb nyomonkövetését, ha szükségét érzi.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Nyitóegyenlegek"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Forgóeszközök">
+ <account type="1" name="Folyószámla"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/childcare.kmt b/kmymoney2/templates/hu_HU/childcare.kmt
new file mode 100644
index 0000000..04e6adf
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gyerektartás költségei</title>
+ <shortdesc>Számla gyerektartás költségeinek nyomonkövetéséhez</shortdesc>
+ <longdesc>Akkor érdemes kiválasztani ezt ha önnek vannak gyerektartási költségei.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Gyerektartás"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/common.kmt b/kmymoney2/templates/hu_HU/common.kmt
new file mode 100644
index 0000000..f9870b3
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/common.kmt
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Gyakori számlák</title>
+ <shortdesc>A leggyakrabban használt alapvető számlák</shortdesc>
+ <longdesc>A legtöbb felhasználónak ezt célszerű választani. Magában foglalja a leggyakrabban használt számlákat (folyószámla, betét, készpénz, hitelkártya, bevétel, gyakori költségek).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Jutalom"/>
+ <account type="12" name="Más bevétel"/>
+ <account type="12" name="Kapott ajándék"/>
+ <account type="12" name="Fizetés"/>
+ <account type="12" name="Kamatbevétel">
+ <account type="12" name="Más kamat"/>
+ <account type="12" name="Betétkamat"/>
+ <account type="12" name="Folyószámlakamat"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Nyitóegyenlegek"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Forgóeszközök">
+ <account type="1" name="Folyószámla"/>
+ <account type="3" name="Készpénz"/>
+ <account type="1" name="Betétszámla"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Szórakozás">
+ <account type="13" name="Zene/filmek"/>
+ <account type="13" name="Utazás"/>
+ <account type="13" name="Pihenés"/>
+ </account>
+ <account type="13" name="Könyvek"/>
+ <account type="13" name="Étkezés"/>
+ <account type="13" name="Ajándékok"/>
+ <account type="13" name="Gyógykezelés"/>
+ <account type="13" name="Jótékonyság"/>
+ <account type="13" name="Tömegközlekedés"/>
+ <account type="13" name="Autó">
+ <account type="13" name="Üzemanyag"/>
+ <account type="13" name="Parkolás"/>
+ <account type="13" name="Javítás és karbantartás"/>
+ <account type="13" name="Díjak"/>
+ </account>
+ <account type="13" name="Bankköltség"/>
+ <account type="13" name="Képzés"/>
+ <account type="13" name="Rezsi">
+ <account type="13" name="Víz"/>
+ <account type="13" name="Gáz"/>
+ <account type="13" name="Hulladékgyűjtés"/>
+ <account type="13" name="Villany"/>
+ </account>
+ <account type="13" name="Kellékek"/>
+ <account type="13" name="Ruhák"/>
+ <account type="13" name="Előfizetések"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Biztosítás">
+ <account type="13" name="Autó biztosítás"/>
+ <account type="13" name="Életbiztosítás"/>
+ <account type="13" name="Egészségbiztosítás"/>
+ </account>
+ <account type="13" name="Online szolgáltatások"/>
+ <account type="13" name="Kiigazítás"/>
+ <account type="13" name="Adók">
+ <account type="13" name="TBJ"/>
+ <account type="13" name="Munkavállalói"/>
+ <account type="13" name="SzJA"/>
+ <account type="13" name="Más adó"/>
+ </account>
+ <account type="13" name="Számítógép"/>
+ <account type="13" name="Mosás/tisztítás"/>
+ <account type="13" name="Különféle"/>
+ <account type="13" name="Háztartási"/>
+ <account type="13" name="Kábel TV"/>
+ <account type="13" name="Kedvtelés"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Hitelkártya"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/eduloan.kmt b/kmymoney2/templates/hu_HU/eduloan.kmt
new file mode 100644
index 0000000..600e7ce
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Diákhitel</title>
+ <shortdesc>Diákhitelszámla és kamat</shortdesc>
+ <longdesc>Annak érdemes kiválasztani ezt, aki vett fel diákhitelt (DH, DH-kamat)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kamat">
+ <account type="13" name="Diákhitel kamata"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Hitelek">
+ <account type="10" name="Diákhitel"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/fixedassets.kmt b/kmymoney2/templates/hu_HU/fixedassets.kmt
new file mode 100644
index 0000000..ca40e98
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Befektetett eszközök</title>
+ <shortdesc>Számlák nagy befektetett eszközök nyomonkövetésére</shortdesc>
+ <longdesc>Akkor érdemes kiválasztani ezt, ha ön nagyobb befektetett eszközökkel rendelkezik (ház, jármű, nyaraló, más eszköz).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Befektetett eszközök">
+ <account type="9" name="Jármű"/>
+ <account type="9" name="Más eszköz"/>
+ <account type="9" name="Ház"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/homeloan.kmt b/kmymoney2/templates/hu_HU/homeloan.kmt
new file mode 100644
index 0000000..4d19aea
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Lakáshitel</title>
+ <shortdesc>Számlák a lakáshitelhez és kamathoz</shortdesc>
+ <longdesc>Önnek akkor célszerű ezt választani, ha rendelkezik lakáshitellel (jelzáloghitel, kamat).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kamat">
+ <account type="13" name="Jelzálogkamat"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Hitelek">
+ <account type="10" name="Jelzáloghitelek"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/homeown.kmt b/kmymoney2/templates/hu_HU/homeown.kmt
new file mode 100644
index 0000000..e487ec5
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Lakásköltségek</title>
+ <shortdesc>Lakástulajdonosi költségek</shortdesc>
+ <longdesc>Akkor érdemes ezt választani, ha önnek van saját lakása. Ez a készlet a saját lakás költségeinek nyomonkövetésére való számlákat tartalmaz (biztosítás, adók, javítások).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Biztosítás">
+ <account type="13" name="Lakásbiztosítás"/>
+ </account>
+ <account type="13" name="Adók">
+ <account type="13" name="Ingatlanadó"/>
+ </account>
+ <account type="13" name="Lakásjavítás"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/otherloan.kmt b/kmymoney2/templates/hu_HU/otherloan.kmt
new file mode 100644
index 0000000..1f7077b
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Más hitelek</title>
+ <shortdesc>Számlák más hitelek nyomonkövetésére</shortdesc>
+ <longdesc>Akkor érdemes ezt választani, ha ön vesz fel más, kisebb hiteleket.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Kamat">
+ <account type="13" name="Más kamat"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Hitelek">
+ <account type="10" name="Más hitel"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/renter.kmt b/kmymoney2/templates/hu_HU/renter.kmt
new file mode 100644
index 0000000..e9b2700
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Bérköltségek</title>
+ <shortdesc>Bérlakás költségei</shortdesc>
+ <longdesc>Akkor érdemes ezt választani, ha ön bérel lakást (lakbér, lakásbiztosítás)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Lakbér"/>
+ <account type="13" name="Biztosítás">
+ <account type="13" name="Bérleti biztosítás"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/retiremt.kmt b/kmymoney2/templates/hu_HU/retiremt.kmt
new file mode 100644
index 0000000..b745644
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Nyugdíjszámlák</title>
+ <shortdesc>Nyugdíjszámla a hozzá kapcsolódó befektetési számlákkal</shortdesc>
+ <longdesc>Akkor érdemes ezt választani, ha önnek vannak nyugdíjszámlái (részvény, kötvény, befektetési alap, nyugdíjalap)</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Befektetések">
+ <account type="7" name="Nyugdíj"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/spouseinc.kmt b/kmymoney2/templates/hu_HU/spouseinc.kmt
new file mode 100644
index 0000000..cbaf2da
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/spouseinc.kmt
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hitvesi jövedelem</title>
+ <shortdesc>Számlák a hitvesi jövedelmek nyomonkövetésére</shortdesc>
+ <longdesc>Akkor érdemes ezt kiválasztani, ha önnek van dolgozó hitvese (fizetés (hitves), adók (hitves)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Fizetés (hitves)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Adók (hitves)">
+ <account type="13" name="TBJ"/>
+ <account type="13" name="Munkavállalói"/>
+ <account type="13" name="SzJA"/>
+ <account type="13" name="Más adó"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/hu_HU/spouseretire.kmt b/kmymoney2/templates/hu_HU/spouseretire.kmt
new file mode 100644
index 0000000..a7feb3c
--- /dev/null
+++ b/kmymoney2/templates/hu_HU/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/hu_HU/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hitvesi nyugdíjszámlák</title>
+ <shortdesc>Nyugdíjszámla a hozzá tartozó hitvesi befektetési számlákkal</shortdesc>
+ <longdesc>Akkor érdemes ezt kiválasztani, ha önnek vannak befektetései a hitvese nevén (részvény, kötvény, befektetési alap, kamat osztalék)</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Befektetések">
+ <account type="7" name="Hitvesi nyugdíj"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/Makefile.am b/kmymoney2/templates/it/Makefile.am
new file mode 100644
index 0000000..7abc6b9
--- /dev/null
+++ b/kmymoney2/templates/it/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/it
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt brokerage.kmt childcare.kmt checkbook.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/it/brokerage.kmt b/kmymoney2/templates/it/brokerage.kmt
new file mode 100644
index 0000000..3ff34a2
--- /dev/null
+++ b/kmymoney2/templates/it/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conti investimenti</title>
+ <shortdesc>Conti per il brokeraggio ed i relativi investimenti</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiedono degli investimenti (azioni, buoni, fondi comuni, fondi indicizzati, interessi, dividendi).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Commissioni"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Entrate dividendi"/>
+ <account type="12" name="Entrate interessi">
+ <account type="12" name="Interessi buoni"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investimenti">
+ <account type="7" name="Conto brokeraggio"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/carloan.kmt b/kmymoney2/templates/it/carloan.kmt
new file mode 100644
index 0000000..6bfefa6
--- /dev/null
+++ b/kmymoney2/templates/it/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Mutuo auto</title>
+ <shortdesc>Conti per il mutuo dell'auto e relativi interessi</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiede un mutuo per l'automobile (mutuo automobile, interessi sul mutuo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interessi">
+ <account type="13" name="Interessi mutuo automobile"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Mutui">
+ <account type="10" name="Mutuo automobile"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/checkbook.kmt b/kmymoney2/templates/it/checkbook.kmt
new file mode 100644
index 0000000..b07c86b
--- /dev/null
+++ b/kmymoney2/templates/it/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Semplice libro conti</title>
+ <shortdesc>L'insieme minimale di conti per usare GnuCash.</shortdesc>
+ <longdesc>Utile per tenere il saldo delle proprie entrate e uscite. Successivamente, se ce ne sarà bisogno, sarà possibile incominciare a tenerne traccia in modo più dettagliato.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Bilanci d'apertura"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Attività correnti">
+ <account type="1" name="Conto corrente"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/childcare.kmt b/kmymoney2/templates/it/childcare.kmt
new file mode 100644
index 0000000..2d62d48
--- /dev/null
+++ b/kmymoney2/templates/it/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Uscite baby sitter</title>
+ <shortdesc>Un conto per tenere traccia dei costi della baby sitter</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si hanno delle uscite per la baby sitter.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Baby sitter"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/common.kmt b/kmymoney2/templates/it/common.kmt
new file mode 100644
index 0000000..e336816
--- /dev/null
+++ b/kmymoney2/templates/it/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conti comuni</title>
+ <shortdesc>Un insieme basilare comprendente i conti più comunemente usati</shortdesc>
+ <longdesc>Questo insieme di conti è selezionato dalla maggior parte degli utenti. L'insieme comprende i conti usati più comunemente (conto corrente, di risparmio, contanti, carta di credito, entrate, uscite comuni).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Entrate extra"/>
+ <account type="12" name="Altre entrate"/>
+ <account type="12" name="Regali ricevuti"/>
+ <account type="12" name="Stipendio"/>
+ <account type="12" name="Entrate interessi">
+ <account type="12" name="Altri interessi"/>
+ <account type="12" name="Interessi conto risparmio"/>
+ <account type="12" name="Interessi conto corrente"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Bilanci d'apertura"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Attività correnti">
+ <account type="1" name="Conto corrente"/>
+ <account type="3" name="Liquidità"/>
+ <account type="1" name="Conto risparmio"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Intrattenimento">
+ <account type="13" name="Musica/Film"/>
+ <account type="13" name="Viaggi"/>
+ <account type="13" name="Divertimento"/>
+ </account>
+ <account type="13" name="Libri"/>
+ <account type="13" name="Ristoranti"/>
+ <account type="13" name="Regali"/>
+ <account type="13" name="Spese mediche"/>
+ <account type="13" name="Donazioni"/>
+ <account type="13" name="Trasporti pubblici"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Benzina"/>
+ <account type="13" name="Parcheggio"/>
+ <account type="13" name="Riparazioni e manutenzione"/>
+ <account type="13" name="Varie"/>
+ </account>
+ <account type="13" name="Servizi bancari"/>
+ <account type="13" name="Educazione"/>
+ <account type="13" name="Servizi">
+ <account type="13" name="Acqua"/>
+ <account type="13" name="Gas"/>
+ <account type="13" name="Rifiuti"/>
+ <account type="13" name="Elettricità"/>
+ </account>
+ <account type="13" name="Prima necessità"/>
+ <account type="13" name="Abbigliamento"/>
+ <account type="13" name="Abbonamenti"/>
+ <account type="13" name="Telefono"/>
+ <account type="13" name="Assicurazione">
+ <account type="13" name="Assicurazione auto"/>
+ <account type="13" name="Assicurazione vita"/>
+ <account type="13" name="Assicurazione medica"/>
+ </account>
+ <account type="13" name="Servizi Internet"/>
+ <account type="13" name="Correzioni"/>
+ <account type="13" name="Imposte">
+ <account type="13" name="Pensione"/>
+ <account type="13" name="Regionali/provinciali"/>
+ <account type="13" name="Statali"/>
+ <account type="13" name="Cure mediche"/>
+ <account type="13" name="Altre imposte"/>
+ </account>
+ <account type="13" name="Computer"/>
+ <account type="13" name="Lavanderia"/>
+ <account type="13" name="Varie"/>
+ <account type="13" name="Alimentari"/>
+ <account type="13" name="TV"/>
+ <account type="13" name="Hobby"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Carta credito"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/fixedassets.kmt b/kmymoney2/templates/it/fixedassets.kmt
new file mode 100644
index 0000000..8b93c9e
--- /dev/null
+++ b/kmymoney2/templates/it/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Attività ingenti</title>
+ <shortdesc>Conti per tenere traccia di attività ingenti</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiedono delle attività di notevole valore e durata (casa, automobile, seconda casa, altre attività).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Attività ingenti">
+ <account type="9" name="Automobile"/>
+ <account type="9" name="Altre attività"/>
+ <account type="9" name="Casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/homeloan.kmt b/kmymoney2/templates/it/homeloan.kmt
new file mode 100644
index 0000000..21328a2
--- /dev/null
+++ b/kmymoney2/templates/it/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Mutuo casa</title>
+ <shortdesc>Conti per il mutuo della casa e relativi interessi</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiede un mutuo per la casa (mutuo, interessi).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interessi">
+ <account type="13" name="Interessi mutuo casa"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Mutui">
+ <account type="10" name="Mutuo casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/homeown.kmt b/kmymoney2/templates/it/homeown.kmt
new file mode 100644
index 0000000..328173d
--- /dev/null
+++ b/kmymoney2/templates/it/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Uscite casa</title>
+ <shortdesc>Uscite associate al possesso di una casa</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiede una casa. L'insieme fornisce un gruppo di conti utili a tenere traccia delle spese di casa (assicurazione, imposte, riparazioni).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Assicurazione">
+ <account type="13" name="Assicurazione casa"/>
+ </account>
+ <account type="13" name="Imposte">
+ <account type="13" name="ICI"/>
+ </account>
+ <account type="13" name="Riparazioni casa"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/otherloan.kmt b/kmymoney2/templates/it/otherloan.kmt
new file mode 100644
index 0000000..abb3000
--- /dev/null
+++ b/kmymoney2/templates/it/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Altri mutui</title>
+ <shortdesc>Conti per tenere traccia di altri mutui e relativi interessi</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiedono altri mutui oltre a quello per la casa (altri mutui, interessi).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Interessi">
+ <account type="13" name="Altri interessi"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Mutui">
+ <account type="10" name="Altri mutui"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/renter.kmt b/kmymoney2/templates/it/renter.kmt
new file mode 100644
index 0000000..801173c
--- /dev/null
+++ b/kmymoney2/templates/it/renter.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Uscite affitto</title>
+ <shortdesc>Uscite associate all'affitto di una casa</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si ha in affitto una casa o un appartamento.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Affitto"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/retiremt.kmt b/kmymoney2/templates/it/retiremt.kmt
new file mode 100644
index 0000000..641262c
--- /dev/null
+++ b/kmymoney2/templates/it/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conti fondo pensione</title>
+ <shortdesc>Conto per il fondo pensione e relativi sottoconti d'investimento</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiedono dei fondi pensione (azioni, buoni, fondi comuni, fondi indicizzati).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimenti">
+ <account type="7" name="Pensione"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/spouseinc.kmt b/kmymoney2/templates/it/spouseinc.kmt
new file mode 100644
index 0000000..6892ebd
--- /dev/null
+++ b/kmymoney2/templates/it/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Entrate coniuge</title>
+ <shortdesc>Conti per tener traccia separatamente delle entrate del coniuge</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se il coniuge lavora (stipendio ed imposte del coniuge).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Stipendio (coniuge)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Imposte (coniuge)">
+ <account type="13" name="Pensione"/>
+ <account type="13" name="Spese mediche"/>
+ <account type="13" name="Regionali/provinciali"/>
+ <account type="13" name="Statale"/>
+ <account type="13" name="Altre imposte"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/it/spouseretire.kmt b/kmymoney2/templates/it/spouseretire.kmt
new file mode 100644
index 0000000..e4fe029
--- /dev/null
+++ b/kmymoney2/templates/it/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/it/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conti fondo pensione coniuge</title>
+ <shortdesc>Conto per il fondo pensione e relativi investimenti del coniuge</shortdesc>
+ <longdesc>Selezionare questo insieme di conti se si possiedono degli investimenti in favore del coniuge (azioni, buoni, fondi comuni, fondi indicizzati, interessi, dividendi).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimenti">
+ <account type="7" name="Fondo pensione coniuge"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/Makefile.am b/kmymoney2/templates/jp/Makefile.am
new file mode 100644
index 0000000..f0a3148
--- /dev/null
+++ b/kmymoney2/templates/jp/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/jp
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt checkbook.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/jp/brokerage.kmt b/kmymoney2/templates/jp/brokerage.kmt
new file mode 100644
index 0000000..27b708e
--- /dev/null
+++ b/kmymoney2/templates/jp/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>投資勘定科目集</title>
+ <shortdesc>委託売買口座と関連する投資勘定科目(株式、債券、投資信託、金利、配当)</shortdesc>
+ <longdesc>投資(株式、債券、投資信託、金利、配当)を行っている場合は、この勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="委託手数料"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="配当収入"/>
+ <account type="12" name="利息収入">
+ <account type="12" name="債券利息"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="投資">
+ <account type="7" name="委託売買口座"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/business.kmt b/kmymoney2/templates/jp/business.kmt
new file mode 100644
index 0000000..291a50b
--- /dev/null
+++ b/kmymoney2/templates/jp/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>ビジネス勘定科目</title>
+ <shortdesc>ビジネス用勘定科目の全般。</shortdesc>
+ <longdesc>ビジネスを行っているユーザは他の選択肢の代わりにこれを選ぶとよいでしょう。これにはたいていのビジネスを行うのに必要な勘定科目、買掛金、売掛金、収益、費用など、がすべて含まれます。</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="クレジットカード"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="内部留保"/>
+ <account type="16" name="開始残高"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="備品レンタル費"/>
+ <account type="13" name="諸費用"/>
+ <account type="13" name="修理費">
+ <account type="13" name="備品修理費"/>
+ <account type="13" name="建物修理費"/>
+ <account type="13" name="コンピュータ修理費"/>
+ <account type="13" name="建物管理費"/>
+ </account>
+ <account type="13" name="送料"/>
+ <account type="13" name="研修費"/>
+ <account type="13" name="減価償却"/>
+ <account type="13" name="オフィス消耗品"/>
+ <account type="13" name="専門家料金">
+ <account type="13" name="法務費"/>
+ <account type="13" name="会計費"/>
+ </account>
+ <account type="13" name="印刷複写費"/>
+ <account type="13" name="食費"/>
+ <account type="13" name="会費講読費"/>
+ <account type="13" name="免許許可"/>
+ <account type="13" name="現金値引き"/>
+ <account type="13" name="賃金"/>
+ <account type="13" name="外部サービス"/>
+ <account type="13" name="調整"/>
+ <account type="13" name="旅費娯楽費">
+ <account type="13" name="食費"/>
+ <account type="13" name="旅費"/>
+ <account type="13" name="娯楽"/>
+ </account>
+ <account type="13" name="義援金"/>
+ <account type="13" name="自動車">
+ <account type="13" name="修理維持"/>
+ <account type="13" name="ガソリン"/>
+ <account type="13" name="駐車場"/>
+ <account type="13" name="通行料"/>
+ </account>
+ <account type="13" name="レンタル費"/>
+ <account type="13" name="公共料金">
+ <account type="13" name="ガス"/>
+ <account type="13" name="ゴミ収集"/>
+ <account type="13" name="インターネット"/>
+ <account type="13" name="携帯電話"/>
+ <account type="13" name="ケーブルテレビ"/>
+ <account type="13" name="電気"/>
+ <account type="13" name="水道"/>
+ <account type="13" name="電話"/>
+ </account>
+ <account type="13" name="保険料">
+ <account type="13" name="所得補償保険"/>
+ <account type="13" name="労働災害保険"/>
+ <account type="13" name="賠償責任保険"/>
+ </account>
+ <account type="13" name="銀行手数料"/>
+ <account type="13" name="税金">
+ <account type="13" name="国税"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="Property"/>
+ <account type="13" name="Local"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="その他の税金"/>
+ <account type="13" name="地方税"/>
+ <account type="13" name="FUTA"/>
+ </account>
+ <account type="13" name="書籍"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="利息収入"/>
+ <account type="12" name="売上"/>
+ <account type="12" name="その他の収入"/>
+ <account type="12" name="賠償費用"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流動資産">
+ <account type="1" name="普通預金口座"/>
+ <account type="3" name="小口現金"/>
+ <account type="1" name="当座預金口座"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/carloan.kmt b/kmymoney2/templates/jp/carloan.kmt
new file mode 100644
index 0000000..a5fcdb5
--- /dev/null
+++ b/kmymoney2/templates/jp/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>自動車ローン</title>
+ <shortdesc>自動車ローンと関連利子用の勘定科目</shortdesc>
+ <longdesc>自動車ローンを持っている場合はこの勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="利子">
+ <account type="13" name="自動車ローン利子"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="ローン">
+ <account type="10" name="自動車ローン"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/cdmoneymkt.kmt b/kmymoney2/templates/jp/cdmoneymkt.kmt
new file mode 100644
index 0000000..54c2563
--- /dev/null
+++ b/kmymoney2/templates/jp/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>譲渡性預金(CD)と短期金融市場</title>
+ <shortdesc>譲渡性預金と短期金融市場用の勘定科目</shortdesc>
+ <longdesc>譲渡性預金か短期金融市場の口座を持っている場合は、この勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="利息収入">
+ <account type="12" name="譲渡性預金利息"/>
+ <account type="12" name="短期金融市場利息"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流動資産">
+ <account type="1" name="短期金融市場"/>
+ <account type="1" name="銀行譲渡性預金"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/checkbook.kmt b/kmymoney2/templates/jp/checkbook.kmt
new file mode 100644
index 0000000..ec3dd49
--- /dev/null
+++ b/kmymoney2/templates/jp/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>単純小切手帳</title>
+ <shortdesc>GnuCashを使う上で最小限の勘定科目セット</shortdesc>
+ <longdesc>小切手帳の収支を合わせるだけであればこれを使ってください。必要になれば、あとから詳細な収益や費用の管理を始めることができます。</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="開始残高"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流動資産">
+ <account type="1" name="当座預金口座"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/childcare.kmt b/kmymoney2/templates/jp/childcare.kmt
new file mode 100644
index 0000000..6cadcc5
--- /dev/null
+++ b/kmymoney2/templates/jp/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>養育費用</title>
+ <shortdesc>養育費用を管理するための勘定科目</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have childcare expenses.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="養育費"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/common.kmt b/kmymoney2/templates/jp/common.kmt
new file mode 100644
index 0000000..07b1944
--- /dev/null
+++ b/kmymoney2/templates/jp/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>共通勘定科目集</title>
+ <shortdesc>最も共通に使われる科目の基本セット</shortdesc>
+ <longdesc>ほとんどのユーザはこの勘定科目セットを選ぶとよいでしょう。最も共通に使われる科目 (預貯金、現金、クレジットカード、所得、一般的な支出) が含まれています。</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="ボーナス"/>
+ <account type="12" name="その他の収入"/>
+ <account type="12" name="贈与収入"/>
+ <account type="12" name="給与"/>
+ <account type="12" name="利息収入">
+ <account type="12" name="その他の利息"/>
+ <account type="12" name="普通預金利息"/>
+ <account type="12" name="当座預金利息"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="開始残高"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流動資産">
+ <account type="1" name="当座預金"/>
+ <account type="3" name="現金"/>
+ <account type="1" name="普通預金"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="娯楽">
+ <account type="13" name="音楽/映画"/>
+ <account type="13" name="旅行"/>
+ <account type="13" name="リクリエーション"/>
+ </account>
+ <account type="13" name="書籍"/>
+ <account type="13" name="食費"/>
+ <account type="13" name="贈答"/>
+ <account type="13" name="医療費"/>
+ <account type="13" name="義援金"/>
+ <account type="13" name="交通機関"/>
+ <account type="13" name="自動車">
+ <account type="13" name="ガソリン"/>
+ <account type="13" name="駐車場"/>
+ <account type="13" name="修理維持"/>
+ <account type="13" name="通行料"/>
+ </account>
+ <account type="13" name="銀行手数料"/>
+ <account type="13" name="教育"/>
+ <account type="13" name="公共料金">
+ <account type="13" name="水道"/>
+ <account type="13" name="ガス"/>
+ <account type="13" name="ゴミ収集"/>
+ <account type="13" name="電気"/>
+ </account>
+ <account type="13" name="消耗品"/>
+ <account type="13" name="衣料品"/>
+ <account type="13" name="購読"/>
+ <account type="13" name="電話料金"/>
+ <account type="13" name="保険料">
+ <account type="13" name="自動車保険"/>
+ <account type="13" name="生命保険"/>
+ <account type="13" name="医療保険"/>
+ </account>
+ <account type="13" name="オンラインサービス"/>
+ <account type="13" name="調整"/>
+ <account type="13" name="税金">
+ <account type="13" name="公的年金"/>
+ <account type="13" name="地方税"/>
+ <account type="13" name="国税"/>
+ <account type="13" name="健康保険"/>
+ <account type="13" name="その他の税"/>
+ </account>
+ <account type="13" name="コンピュータ"/>
+ <account type="13" name="クリーニング"/>
+ <account type="13" name="その他"/>
+ <account type="13" name="日用品"/>
+ <account type="13" name="ケーブルテレビ"/>
+ <account type="13" name="趣味"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="クレジットカード"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/eduloan.kmt b/kmymoney2/templates/jp/eduloan.kmt
new file mode 100644
index 0000000..d685993
--- /dev/null
+++ b/kmymoney2/templates/jp/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>教育ローン</title>
+ <shortdesc>教育ローンと関連する金利の勘定科目</shortdesc>
+ <longdesc>教育住宅ローンを持っている場合はこの勘定科目セットを選びたくなるかもしれません。</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="利子">
+ <account type="13" name="教育ローン利子"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="ローン">
+ <account type="10" name="教育ローン"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/fixedassets.kmt b/kmymoney2/templates/jp/fixedassets.kmt
new file mode 100644
index 0000000..6b36ba8
--- /dev/null
+++ b/kmymoney2/templates/jp/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>固定資産</title>
+ <shortdesc>大規模な固定資産管理用の勘定科目</shortdesc>
+ <longdesc>大規模な固定資産(住宅、自動車、別荘、その他資産)を持っている場合はこの勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="固定資産">
+ <account type="9" name="自動車"/>
+ <account type="9" name="その他の資産"/>
+ <account type="9" name="住宅"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/homeloan.kmt b/kmymoney2/templates/jp/homeloan.kmt
new file mode 100644
index 0000000..5af215e
--- /dev/null
+++ b/kmymoney2/templates/jp/homeloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>住宅ローン</title>
+ <shortdesc>住宅ローンと関連する金利の勘定科目</shortdesc>
+ <longdesc>住宅ローンを持っている場合はこの勘定科目セットを選びたくなるかもしれません。</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="住宅ローン"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="金利">
+ <account type="13" name="住宅ローン金利"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/homeown.kmt b/kmymoney2/templates/jp/homeown.kmt
new file mode 100644
index 0000000..08ab991
--- /dev/null
+++ b/kmymoney2/templates/jp/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>住居費</title>
+ <shortdesc>住居所有にかかる費用</shortdesc>
+ <longdesc>住居を保有している場合はこの勘定科目セットを選ぶとよいでしょう。このセットは住居費用(保険、税金、修理)を管理する勘定科目のグループを用意します。</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="保険">
+ <account type="13" name="住宅保険"/>
+ </account>
+ <account type="13" name="税金">
+ <account type="13" name="固定資産税"/>
+ </account>
+ <account type="13" name="修繕費"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/otherloan.kmt b/kmymoney2/templates/jp/otherloan.kmt
new file mode 100644
index 0000000..3853f43
--- /dev/null
+++ b/kmymoney2/templates/jp/otherloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>その他のローン</title>
+ <shortdesc>その他のローンと利息を管理するための勘定科目</shortdesc>
+ <longdesc>住宅以外の何か他のローンを持っている場合はこの勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="利子">
+ <account type="13" name="その他の利子"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ <account type="10" name="">
+ <account type="10" name="その他のローン"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/renter.kmt b/kmymoney2/templates/jp/renter.kmt
new file mode 100644
index 0000000..4d4c3ae
--- /dev/null
+++ b/kmymoney2/templates/jp/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>賃貸費用</title>
+ <shortdesc>賃貸住宅にかかる費用</shortdesc>
+ <longdesc>住居やアパートを賃貸している場合は(家賃、賃貸保険)この勘定科目集合を選ぶといいでしょう。</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="家賃"/>
+ <account type="13" name="保険">
+ <account type="13" name="賃貸住宅保険"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/retiremt.kmt b/kmymoney2/templates/jp/retiremt.kmt
new file mode 100644
index 0000000..fc81b7c
--- /dev/null
+++ b/kmymoney2/templates/jp/retiremt.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>個人年金口座</title>
+ <shortdesc>個人年金口座と関連する投資勘定科目</shortdesc>
+ <longdesc>個人年金口座(株式、債券、投資信託)を持っている場合はこの勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="個人年金"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/spouseinc.kmt b/kmymoney2/templates/jp/spouseinc.kmt
new file mode 100644
index 0000000..0b1fcd6
--- /dev/null
+++ b/kmymoney2/templates/jp/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>配偶者収益</title>
+ <shortdesc>配偶者の収益を分離して管理するための勘定科目集</shortdesc>
+ <longdesc>配偶者が働いている場合はこの勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="給与(配偶者)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="税金(配偶者)">
+ <account type="13" name="公的年金"/>
+ <account type="13" name="健康保険"/>
+ <account type="13" name="地方税"/>
+ <account type="13" name="国税"/>
+ <account type="13" name="その他の税"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/jp/spouseretire.kmt b/kmymoney2/templates/jp/spouseretire.kmt
new file mode 100644
index 0000000..43b1dac
--- /dev/null
+++ b/kmymoney2/templates/jp/spouseretire.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/ja/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>配偶者個人年金口座</title>
+ <shortdesc>配偶者の個人年金口座と関連する投資勘定科目</shortdesc>
+ <longdesc>配偶者名での投資(株式、債券、投資信託、利息、配当)を持っている場合はこの勘定科目セットを選ぶとよいでしょう。</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="配偶者個人年金"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/nl_NL/Makefile.am b/kmymoney2/templates/nl_NL/Makefile.am
new file mode 100644
index 0000000..54b6db6
--- /dev/null
+++ b/kmymoney2/templates/nl_NL/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/nl_NL
+
+template_DATA = default_accounts.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/nl_NL/default_accounts.kmt b/kmymoney2/templates/nl_NL/default_accounts.kmt
new file mode 100644
index 0000000..ff4481d
--- /dev/null
+++ b/kmymoney2/templates/nl_NL/default_accounts.kmt
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 default</title>
+ <shortdesc/>
+ <longdesc/>
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Allimentatie" />
+ <account type="12" name="Werkgever" >
+ <account type="12" name="Bonus" />
+ <account type="12" name="Buitenlandse inkomsten" />
+ <account type="12" name="Anders" />
+ <account type="12" name="Salaris / Loon" />
+ <account type="12" name="Overwerk" />
+ <account type="12" name="Bijdrage pensioenpremie" />
+ <account type="12" name="Bijdrage ziektekostenverzekering" />
+ <account type="12" name="Commissie" />
+ </account>
+ <account type="12" name="Bank" >
+ <account type="12" name="Rente" />
+ <account type="12" name="Service kosten" />
+ </account>
+ <account type="12" name="Beleggingen / Investeringen" >
+ <account type="12" name="Verkoop opties" />
+ <account type="12" name="Dividend" />
+ <account type="12" name="Stock dividend" />
+ <account type="12" name="Rente" />
+ <account type="12" name="Verkoop aandelen" />
+ </account>
+ <account type="12" name="Andere inkomsten" >
+ <account type="12" name="Bedrijfsopties en -aandelen" />
+ <account type="12" name="Giften" />
+ <account type="12" name="Aflossingen" />
+ <account type="12" name="Loterijen" />
+ <account type="12" name="Belasting teruggaaf" />
+ <account type="12" name="Uitkeringen" >
+ <account type="12" name="Studiebeurs" />
+ <account type="12" name="Kinderbijslag" />
+ <account type="12" name="WW" />
+ <account type="12" name="AOW" />
+ <account type="12" name="WIA" />
+ <account type="12" name="Lijfrente" />
+ <account type="12" name="Pensioen" />
+ <account type="12" name="Levensverzekering" />
+ <account type="12" name="Ziektekostenverzekering" />
+ <account type="12" name="Stakingskas" />
+ <account type="12" name="Huur subsidie" />
+ </account>
+ </account>
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Rekeningen" >
+ <account type="13" name="Telefoon" />
+ <account type="13" name="Huur" />
+ <account type="13" name="Elektriciteit" />
+ <account type="13" name="TV" />
+ <account type="13" name="Lokale belastingen en heffingen" />
+ <account type="13" name="Gas" />
+ <account type="13" name="Hypotheek" >
+ <account type="13" name="Rente" />
+ <account type="13" name="Aflossingsverzekering" />
+ <account type="13" name="Aflossing" />
+ </account>
+ <account type="13" name="Water" />
+ <account type="13" name="Stookolie" />
+ <account type="13" name="Afvalstoffenheffing" />
+ <account type="13" name="Rioolrecht" />
+ <account type="13" name="Abonnementen" />
+ <account type="13" name="Stadsverwarming" />
+ </account>
+ <account type="13" name="Bank kosten" >
+ <account type="13" name="Rente" />
+ <account type="13" name="Service kosten" />
+ </account>
+ <account type="13" name="Zakelijke uitgaven" >
+ <account type="13" name="Auto" >
+ <account type="13" name="Brandstof" />
+ <account type="13" name="Onderhoud" />
+ <account type="13" name="Verzekering" />
+ <account type="13" name="Leasekosten" />
+ <account type="13" name="Lening" />
+ </account>
+ <account type="13" name="Investeringen" />
+ <account type="13" name="Juridische uitgaven" />
+ <account type="13" name="Reis- en verblijfskosten" >
+ <account type="13" name="Accomodatie" />
+ <account type="13" name="Tolgelden" />
+ <account type="13" name="Auto huur" />
+ </account>
+ <account type="13" name="Kantoor huur" />
+ <account type="13" name="Office Supplies" />
+ <account type="13" name="Divers" />
+ <account type="13" name="Loon en salaris" >
+ <account type="13" name="Toelagen" />
+ <account type="13" name="Vakbond" />
+ </account>
+ <account type="13" name="Rente" />
+ </account>
+ <account type="13" name="Auto" >
+ <account type="13" name="Brandstof" />
+ <account type="13" name="Onderhoud" />
+ <account type="13" name="Verzekering" />
+ <account type="13" name="Lease" />
+ <account type="13" name="Lening" />
+ <account type="13" name="Tol gelden en veerdiensten" />
+ <account type="13" name="Parkeer kosten" />
+ <account type="13" name="Rijles" />
+ </account>
+ <account type="13" name="Opname kas" />
+ <account type="13" name="Goede doelen" >
+ <account type="13" name="Giften" />
+ </account>
+ <account type="13" name="Allimentatie (uitgaven)" />
+ <account type="13" name="Onderwijs" >
+ <account type="13" name="Boeken" />
+ <account type="13" name="Lesgeld" />
+ <account type="13" name="Studie lening" />
+ </account>
+ <account type="13" name="Tuin" />
+ <account type="13" name="Gezondheid" >
+ <account type="13" name="Tandarts" />
+ <account type="13" name="Huisarts" />
+ <account type="13" name="Ziekenhuis" />
+ <account type="13" name="Opticien" />
+ <account type="13" name="Medicijnen" />
+ <account type="13" name="Fysiotherapie" />
+ </account>
+ <account type="13" name="Vakantie" >
+ <account type="13" name="Accomodatie" />
+ <account type="13" name="Reiskosten" />
+ </account>
+ <account type="13" name="Huishoudelijk" >
+ <account type="13" name="Boodschappen" />
+ <account type="13" name="Stoffering" />
+ <account type="13" name="Reparatie" />
+ <account type="13" name="Bloemen en planten" />
+ <account type="13" name="Cadeaus" />
+ <account type="13" name="Levensmiddelen" />
+ <account type="13" name="Reiskosten" />
+ <account type="13" name="Divers" />
+ <account type="13" name="Speelgoed" />
+ <account type="13" name="Zakgeld" />
+ <account type="13" name="Kleding" />
+ <account type="13" name="Persoonlijke verzorging" />
+ </account>
+ <account type="13" name="Verzekeringen" >
+ <account type="13" name="Wettelijke aansprakelijkheid" />
+ <account type="13" name="Levensverzekering" />
+ <account type="13" name="Ziektekosten verzekering" />
+ <account type="13" name="Auto verzekering" />
+ <account type="13" name="Arbeidsongeschiktheidsverzekering" />
+ <account type="13" name="Uitvaart verzekering" />
+ <account type="13" name="Rechtsbijstand verzekering" />
+ <account type="13" name="Inboedel verzekering" />
+ <account type="13" name="Pensioen gat verzekering" />
+ </account>
+ <account type="13" name="Werk gerelateerde uitgaven" >
+ <account type="13" name="Vergoedde uitgaven" />
+ <account type="13" name="Niet vergoedde uitgaven" />
+ </account>
+ <account type="13" name="Ontspanning" >
+ <account type="13" name="Boeken en tijdschriften" />
+ <account type="13" name="Uitgaan" />
+ <account type="13" name="Films &amp; videotheek" />
+ <account type="13" name="Hobbies" />
+ <account type="13" name="Sport" />
+ <account type="13" name="Sportkleding" />
+ <account type="13" name="Muziek cassettes, CD's en DVD's" />
+ <account type="13" name="Theater &amp; concerten" />
+ <account type="13" name="Speelgoed" />
+ </account>
+ <account type="13" name="Rechtsbijstand" />
+ <account type="13" name="Lening" >
+ <account type="13" name="Rente" />
+ <account type="13" name="Auto lening" />
+ <account type="13" name="Boot lening" />
+ <account type="13" name="Hypotheek" >
+ <account type="13" name="Aflossing" />
+ <account type="13" name="Rente" />
+ <account type="13" name="Aflossingsverzekering" />
+ </account>
+ <account type="13" name="Studie lening" />
+ <account type="13" name="Motor lening" />
+ <account type="13" name="Doorlopend krediet" />
+ </account>
+ <account type="13" name="Andere uitgaven" >
+ <account type="13" name="Divers" />
+ </account>
+ <account type="13" name="Huisdieren" >
+ <account type="13" name="Voeding" />
+ <account type="13" name="Benodigdheden" />
+ <account type="13" name="Dierenarts" />
+ </account>
+ <account type="13" name="Pensioen voorziening" >
+ <account type="13" name="Lijfrente" />
+ <account type="13" name="Extra pensioen storting" />
+ <account type="13" name="Pensioen premie" />
+ </account>
+ <account type="13" name="Belastingen" >
+ <account type="13" name="Inkomsten belasting" />
+ <account type="13" name="Omzet belasting" />
+ <account type="13" name="Onroerend goed belasting" />
+ <account type="13" name="Anders" />
+ <account type="13" name="Lokale belastingen" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/Makefile.am b/kmymoney2/templates/pt_BR/Makefile.am
new file mode 100644
index 0000000..e3fbe95
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/pt_BR
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt default_accounts.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/pt_BR/brokerage.kmt b/kmymoney2/templates/pt_BR/brokerage.kmt
new file mode 100644
index 0000000..9b46573
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conta de Investimentos</title>
+ <shortdesc>Conta de corretagem com contas de investimentos relacionados (ações, obrigações, fundos de investimento, fundos de índices, juros, dividendos)</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso possua investimentos (ações, obrigações, fundos de investimento, fundos de índices, juros, dividendos).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Comissões"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Receita de Dividendos"/>
+ <account type="12" name="Receita de Juros">
+ <account type="12" name="Juros de Obigações"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investimentos">
+ <account type="7" name="Conta na Corretora"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/carloan.kmt b/kmymoney2/templates/pt_BR/carloan.kmt
new file mode 100644
index 0000000..7612720
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Empréstimo para Automóvel</title>
+ <shortdesc>Contas para empréstimo para automóvel e juros associados</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha um empréstimo para automóvel (empréstimo para automóvel, juro do empréstimo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juro">
+ <account type="13" name="Juro Empréstimo Automóvel"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Empréstimo Automóvel"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/cdmoneymkt.kmt b/kmymoney2/templates/pt_BR/cdmoneymkt.kmt
new file mode 100644
index 0000000..a2ca744
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Depósitos a Prazo e Mercado Monetário</title>
+ <shortdesc>Contas para Depósitos a Prazo e investimentos no mercado monetário</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha depósitos a prazo ou contas no mercado financeiro (DP, Juros DP, mercado monetário, juro mercado monetário).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Juros da Receita">
+ <account type="12" name="Juros do DP"/>
+ <account type="12" name="Juros do Mercado Monetário"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Ativos Atuais">
+ <account type="1" name="Mercado Monetário"/>
+ <account type="1" name="DP Banco"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/childcare.kmt b/kmymoney2/templates/pt_BR/childcare.kmt
new file mode 100644
index 0000000..070eab1
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Despesas de Cuidados Infantís</title>
+ <shortdesc>Uma conta para acompanhar despesas com cuidados infantís</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha despesas com crianças.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Cuidados Infantís"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/common.kmt b/kmymoney2/templates/pt_BR/common.kmt
new file mode 100644
index 0000000..50f255a
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas Comuns</title>
+ <shortdesc>Um conjunto simples com as contas mais utilizadas</shortdesc>
+ <longdesc>A maioria dos usuários deverão selecionar este conjunto de contas. Inclui as contas mais utilizadas (dep. ordem, prazo, dinheiro, cartão crédito, receitas, despesas comuns).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Bônus"/>
+ <account type="12" name="Outras Receitas"/>
+ <account type="12" name="Presentes Recebidos"/>
+ <account type="12" name="Salário"/>
+ <account type="12" name="Juros Recebidos">
+ <account type="12" name="Outros Juros"/>
+ <account type="12" name="Juros Conta Poupança"/>
+ <account type="12" name="Juros Conta Corrente"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Saldos Iniciais"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Ativos Atuais">
+ <account type="1" name="Conta Corrente"/>
+ <account type="3" name="Dinheiro na Carteira"/>
+ <account type="1" name="Conta Poupança"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Diversão">
+ <account type="13" name="Música/Cinema"/>
+ <account type="13" name="Viagens"/>
+ <account type="13" name="Passeios"/>
+ </account>
+ <account type="13" name="Livros"/>
+ <account type="13" name="Refeições Fora"/>
+ <account type="13" name="Presentes"/>
+ <account type="13" name="Despesas com Saúde"/>
+ <account type="13" name="Doações"/>
+ <account type="13" name="Transportes Públicos"/>
+ <account type="13" name="Automóvel">
+ <account type="13" name="Combustível"/>
+ <account type="13" name="Estacionamento"/>
+ <account type="13" name="Reparos e Manutenção"/>
+ <account type="13" name="Impostos"/>
+ </account>
+ <account type="13" name="Taxas Bancárias"/>
+ <account type="13" name="Educação"/>
+ <account type="13" name="Serviços">
+ <account type="13" name="Água"/>
+ <account type="13" name="Gás"/>
+ <account type="13" name="Eletricidade"/>
+ </account>
+ <account type="13" name="Material de Escritório"/>
+ <account type="13" name="Vestuário"/>
+ <account type="13" name="Assinaturas"/>
+ <account type="13" name="Telefone"/>
+ <account type="13" name="Seguro">
+ <account type="13" name="Seguro Automóvel"/>
+ <account type="13" name="Seguro de Vida"/>
+ <account type="13" name="Seguro Saúde"/>
+ </account>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Ajustes"/>
+ <account type="13" name="Impostos">
+ <account type="13" name="CPMF"/>
+ <account type="13" name="IRF"/>
+ <account type="13" name="INSS"/>
+ <account type="13" name="Outros Impostos"/>
+ </account>
+ <account type="13" name="Computador"/>
+ <account type="13" name="Lavandaria"/>
+ <account type="13" name="Outras"/>
+ <account type="13" name="Mercearia"/>
+ <account type="13" name="Tv por assinatura"/>
+ <account type="13" name="Passatempos"/>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Contas a Pagar">
+ <account type="4" name="Cartão de Crédito"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/currency.kmt b/kmymoney2/templates/pt_BR/currency.kmt
new file mode 100644
index 0000000..d27b69d
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conta de Conversão Monetária</title>
+ <shortdesc>Conta para converter e transacionar em moeda estrangeira</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas se converter em moedas estrangeiras. Nota: conta encontra-se em BRL; edite a conta para alterar a moeda.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimentos"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/default_accounts.kmt b/kmymoney2/templates/pt_BR/default_accounts.kmt
new file mode 100644
index 0000000..3cd483c
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/default_accounts.kmt
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 default</title>
+ <shortdesc></shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Contas a Pagar" type="13">
+ <account name="Telefone" type="13"/>
+ <account name="Aluguel" type="13"/>
+ <account name="Eletricidade" type="13"/>
+ <account name="TV" type="13"/>
+ <account name="Taxas Locais" type="13"/>
+ <account name="Óleo Combustível" type="13"/>
+ <account name="Gás Natural" type="13"/>
+ <account name="Hipoteca" type="13"/>
+ <account name="Água e Esgoto" type="13"/>
+ <account name="Condomínio" type="13"/>
+ </account>
+ <account name="Taxas Bancárias" type="13">
+ <account name="Juros Pagos" type="13"/>
+ <account name="Taxa de Serviço" type="13"/>
+ </account>
+ <account name="Empresa" type="13">
+ <account name="Automóvel" type="13">
+ <account name="Combustível" type="13"/>
+ <account name="Manutenção" type="13"/>
+ <account name="Seguro" type="13"/>
+ <account name="Leasing" type="13"/>
+ <account name="Financiamento" type="13"/>
+ <account name="Documentação" type="13"/>
+ </account>
+ <account name="Despesas Legais" type="13"/>
+ <account name="Taxas" type="13">
+ <account name="Taxas Federais" type="13"/>
+ <account name="Taxax Estaduais" type="13"/>
+ <account name="Taxas Locais" type="13"/>
+ <account name="Seguridade Social" type="13"/>
+ <account name="Taxas de Propriedade" type="13"/>
+ </account>
+ <account name="Viagem" type="13">
+ <account name="Acomodações" type="13"/>
+ <account name="Passagens" type="13"/>
+ <account name="Alimentação" type="13"/>
+ <account name="Aluguel de Carro" type="13"/>
+ </account>
+ <account name="Aluguel de Escritório" type="13"/>
+ <account name="Suprimentos de Escritório" type="13"/>
+ <account name="Outros" type="13"/>
+ <account name="Utilidades" type="13">
+ <account name="Eletricidade" type="13"/>
+ <account name="Gás" type="13"/>
+ <account name="Telefone" type="13"/>
+ <account name="Água" type="13"/>
+ <account name="Esgoto" type="13"/>
+ <account name="Lixo e Reciclagem" type="13"/>
+ </account>
+ <account name="Salário e Ordenado" type="13"/>
+ </account>
+ <account name="Automóvel" type="13">
+ <account name="Combustível" type="13"/>
+ <account name="Acessórios" type="13"/>
+ <account name="Serviços" type="13"/>
+ <account name="Seguro" type="13"/>
+ <account name="Leasing" type="13"/>
+ <account name="Financiamento" type="13"/>
+ <account name="Impostos e documentação" type="13"/>
+ </account>
+ <account name="Retirada em Dinheiro" type="13"/>
+ <account name="Caridade" type="13">
+ <account name="Doações" type="13"/>
+ </account>
+ <account name="Despesas com filhos" type="13"/>
+ <account name="Vestuário" type="13"/>
+ <account name="Educação" type="13">
+ <account name="Livros" type="13"/>
+ <account name="Taxas" type="13"/>
+ <account name="Financiamento" type="13"/>
+ <account name="Mensalidade Escolar" type="13"/>
+ <account name="Outros" type="13"/>
+ </account>
+ <account name="Alimentação" type="13">
+ <account name="Restaurante" type="13"/>
+ <account name="Mercado" type="13"/>
+ </account>
+ <account name="Jardinagem" type="13"/>
+ <account name="Presentes" type="13"/>
+ <account name="Saúde" type="13">
+ <account name="Dentista" type="13"/>
+ <account name="Médico" type="13"/>
+ <account name="Hospital" type="13"/>
+ <account name="Oculista" type="13"/>
+ <account name="Remédios" type="13"/>
+ </account>
+ <account name="Viagens" type="13">
+ <account name="Acomodações" type="13"/>
+ <account name="Alimentação" type="13"/>
+ <account name="Passagens" type="13"/>
+ </account>
+ <account name="Casa" type="13">
+ <account name="Mobília" type="13"/>
+ <account name="Reparos" type="13"/>
+ </account>
+ <account name="Seguro" type="13">
+ <account name="Casa" type="13"/>
+ <account name="Vida" type="13"/>
+ <account name="Médico" type="13"/>
+ <account name="Automóvel" type="13"/>
+ <account name="Invalidez" type="13"/>
+ </account>
+ <account name="Despesas de Trabalho" type="13">
+ <account name="Não reembolsadas" type="13"/>
+ <account name="Reembolsadas" type="13"/>
+ </account>
+ <account name="Lazer" type="13">
+ <account name="Livros e Revistas" type="13"/>
+ <account name="Diversão" type="13"/>
+ <account name="Cinemas e Aluguel de Vídeos" type="13"/>
+ <account name="Eventos Esportivos" type="13"/>
+ <account name="Fitas &amp; CDs" type="13"/>
+ <account name="Eventos Culturais" type="13"/>
+ <account name="Brinquedos e Jogos" type="13"/>
+ </account>
+ <account name="Taxas Legais" type="13"/>
+ <account name="Financiamento" type="13">
+ <account name="Juros de Financiamento" type="13"/>
+ </account>
+ <account name="Cuidados Pessoais" type="13"/>
+ <account name="Animal de Estimação" type="13">
+ <account name="Alimentação" type="13"/>
+ <account name="Suprimentos" type="13"/>
+ <account name="Veterinário" type="13"/>
+ </account>
+ <account name="Taxas" type="13">
+ <account name="Taxas Federais" type="13"/>
+ <account name="Taxas Estaduais" type="13"/>
+ <account name="Taxas Locais" type="13"/>
+ <account name="Outras Taxas" type="13"/>
+ <account name="Taxas sobre propriedade" type="13"/>
+ </account>
+ <account name="Utilidades" type="13">
+ <account name="Eletricidade" type="13"/>
+ <account name="Gás" type="13"/>
+ <account name="Telefone" type="13"/>
+ <account name="Água" type="13"/>
+ <account name="Esgoto" type="13"/>
+ <account name="Lixo e Reciclagem" type="13"/>
+ </account>
+ </account>
+ <account name="" type="12">
+ <account name="Outros Rendimentos" type="12">
+ <account name="Financiamento de Estudos" type="12"/>
+ <account name="Ações de Funcionário" type="12"/>
+ <account name="Presentes Recebidos" type="12"/>
+ <account name="Principal do Financiamento Recebido" type="12"/>
+ <account name="Loterias" type="12"/>
+ <account name="Devolução de Impostos" type="12"/>
+ <account name="Seguro Desemprego" type="12"/>
+ <account name="Pensão Recebida para Filhos" type="12"/>
+ </account>
+ <account name="Rendimentos de Aposentadoria" type="12">
+ <account name="Benefícios" type="12"/>
+ <account name="Pensões" type="12"/>
+ </account>
+ <account name="Rendimentos de Investimentos" type="12">
+ <account name="Dividendos" type="12"/>
+ <account name="Ganhos de Capital de curto-prazo" type="12"/>
+ <account name="Ganhos de Capital de longo-prazo" type="12"/>
+ <account name="Juros" type="12"/>
+ <account name="Juros não Tributáveis" type="12"/>
+ </account>
+ <account name="Salário e Ordenado" type="12">
+ <account name="Bônus" type="12"/>
+ <account name="Comissão" type="12"/>
+ <account name="Contribuição do Empregador" type="12"/>
+ <account name="Pagamento Bruto" type="12"/>
+ <account name="Pagamento Líquido" type="12"/>
+ <account name="Horas Extras" type="12"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/eduloan.kmt b/kmymoney2/templates/pt_BR/eduloan.kmt
new file mode 100644
index 0000000..39df84b
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Crédito Educativo</title>
+ <shortdesc>Contas para empréstimos para estudos e juros associados</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas se possuir um crédito educativo (empréstimo para educação, juros do empréstimo para educação).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juros">
+ <account type="13" name="Juros do Crédito Educativo"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Crédito Educativo"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/fixedassets.kmt b/kmymoney2/templates/pt_BR/fixedassets.kmt
new file mode 100644
index 0000000..9ca8408
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Ativo Fixo</title>
+ <shortdesc>Contas para registar ativos fixos</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas se tiver ativos fixos (casa, automóvel, casa de férias, outros ativos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Ativos Fixos">
+ <account type="9" name="Automóvel"/>
+ <account type="9" name="Outro Ativo"/>
+ <account type="9" name="Casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/homeloan.kmt b/kmymoney2/templates/pt_BR/homeloan.kmt
new file mode 100644
index 0000000..b9988b3
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Empréstimo para Habitação</title>
+ <shortdesc>Contas para empréstimo de habitação e juros associados</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha contraido um empréstimo para habitação (emprétimo habitação, juro do empréstimo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juros">
+ <account type="13" name="Juros Empréstimo"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Empréstimo Habitação"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/homeown.kmt b/kmymoney2/templates/pt_BR/homeown.kmt
new file mode 100644
index 0000000..92807bc
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/homeown.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Despesas da Casa</title>
+ <shortdesc>Despesas associadas à posse de uma habitação</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso possua uma habitação própria. Este conjunto disponibiliza um grupo de contas para acompanhar despesas da casa (seguro, impostos, reparos).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Seguro">
+ <account type="13" name="Seguro da Casa"/>
+ </account>
+ <account type="13" name="IPTU"/>
+ <account type="13" name="Reparos na Casa"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/otherloan.kmt b/kmymoney2/templates/pt_BR/otherloan.kmt
new file mode 100644
index 0000000..a37ecf7
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Outros Empréstimos</title>
+ <shortdesc>Contas para controlar outros empréstimos e juros associados</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas se tiver empréstimo em geral (outro empréstimo, juros do outro empréstimo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juro">
+ <account type="13" name="Outro Juro"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Outros Empréstimo"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/renter.kmt b/kmymoney2/templates/pt_BR/renter.kmt
new file mode 100644
index 0000000..d898e72
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/renter.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Despesas de Aluguel</title>
+ <shortdesc>Despesas associadas com uma casa alugada</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha uma casa alugada (renda).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Renda"/>
+ <account type="13" name="Seguro"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/retiremt.kmt b/kmymoney2/templates/pt_BR/retiremt.kmt
new file mode 100644
index 0000000..4b440d2
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas de Aposentadoria</title>
+ <shortdesc>Contas de aposentadoria com subcontas de investimentos relacionados</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha contas de aposentadoria (ações, obrigações, fundos de investimento, fundos de índices).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimentos">
+ <account type="7" name="Aposentadoria"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/spouseinc.kmt b/kmymoney2/templates/pt_BR/spouseinc.kmt
new file mode 100644
index 0000000..0aabacd
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/spouseinc.kmt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Receitas do Cônjuge</title>
+ <shortdesc>Contas para registar separadamente as receitas do cônjuge</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas caso tenha um cônjuge que tenha emprego (salário, impostos).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Salário (Cônjuge)"/>
+ <account type="13" name="Impostos (Cônjuge)">
+ <account type="13" name="Outros Impostos"/>
+ <account type="13" name="IRF"/>
+ <account type="13" name="Seguro Saúde"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_BR/spouseretire.kmt b/kmymoney2/templates/pt_BR/spouseretire.kmt
new file mode 100644
index 0000000..e14c6d2
--- /dev/null
+++ b/kmymoney2/templates/pt_BR/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_BR/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas de Aposentadoria do Cônjuge</title>
+ <shortdesc>Conta de aposentadoria com contas de investimentos relacionadas para o cônjuge</shortdesc>
+ <longdesc>Deverá selecionar este conjunto de contas se tiver investimentos em nome do cônjuge (ações, obrigações, fundos de investimento, fundos de índices, juros, dividendos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimentos">
+ <account type="7" name="Aposentadoria do Cônjuge"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/Makefile.am b/kmymoney2/templates/pt_PT/Makefile.am
new file mode 100644
index 0000000..a3b2694
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/pt_PT
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/pt_PT/brokerage.kmt b/kmymoney2/templates/pt_PT/brokerage.kmt
new file mode 100644
index 0000000..442722b
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conta de Investimentos</title>
+ <shortdesc>Conta de corretagem com contas de investimentos relacionados (acções, obrigações, fundos de investimento, fundos de índices, juros, dividendos)</shortdesc>
+ <longdesc>Você desejará seleccionar este conjunto de acções caso possua investimentos (acções, obrigações, fundos de investimento, fundos de índices, juros, dividendos).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Comissões"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Receita de Dividendos"/>
+ <account type="12" name="Receita de Juros">
+ <account type="12" name="Juros de Obigações"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investimentos">
+ <account type="7" name="Conta na Corretora"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/carloan.kmt b/kmymoney2/templates/pt_PT/carloan.kmt
new file mode 100644
index 0000000..e5bf746
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Empréstimo para Automóvel</title>
+ <shortdesc>Contas para empréstimo para automóvel e juros associados</shortdesc>
+ <longdesc>Você desejará seleccionar este conjunto de contas caso tenha um empréstimo para automóvel (empréstimo para automóvel, juro do empréstimo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juro">
+ <account type="13" name="Juro Empréstimo Automóvel"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Empréstimo Automóvel"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/cdmoneymkt.kmt b/kmymoney2/templates/pt_PT/cdmoneymkt.kmt
new file mode 100644
index 0000000..59dd47c
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Depósitos a Prazo e Mercado Monetário</title>
+ <shortdesc>Contas para Depósitos a Prazo e investimentos no mercado monetário</shortdesc>
+ <longdesc>Desejará utilizar este conjunto de contas caso tenha depósitos a prazo ou contas no mercado financeiro (DP, Juros DP, mercado monetário, juro mercado monetário).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Juros da Receita">
+ <account type="12" name="Juros do DP"/>
+ <account type="12" name="Juros do Mercado Monetário"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activos Actuais">
+ <account type="1" name="Mercado Monetário"/>
+ <account type="1" name="DP Banco"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/childcare.kmt b/kmymoney2/templates/pt_PT/childcare.kmt
new file mode 100644
index 0000000..2ecfc10
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Despesas de Cuidados Infantís</title>
+ <shortdesc>Uma conta para acompanhar despesas com cuidados infantís</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas caso tenha despesas com crianças.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Cuidados Infantís"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/common.kmt b/kmymoney2/templates/pt_PT/common.kmt
new file mode 100644
index 0000000..d5b4b6a
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/common.kmt
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas Comuns</title>
+ <shortdesc>Um conjunto simples com as contas mais utilizadas</shortdesc>
+ <longdesc>A maioria dos utilizadores desejará seleccionar este conjunto de contas. Inclui as contas mais utilizadas (dep. ordem, prazo, dinheiro, cartão crédito, receitas, despesas comuns).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Bónus"/>
+ <account type="12" name="Outras Receitas"/>
+ <account type="12" name="Presentes Recebidos"/>
+ <account type="12" name="Salário"/>
+ <account type="12" name="Juros Recebidos">
+ <account type="12" name="Outros Juros"/>
+ <account type="12" name="Juros Conta Prazo"/>
+ <account type="12" name="Juros Conta Ordem"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Saldos Iniciais"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Activos Actuais">
+ <account type="1" name="Conta à Ordem"/>
+ <account type="3" name="Dinheiro na Carteira"/>
+ <account type="1" name="Conta a Prazo"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Divertimento">
+ <account type="13" name="Música/Cinema"/>
+ <account type="13" name="Viagens"/>
+ <account type="13" name="Passeios"/>
+ </account>
+ <account type="13" name="Livros"/>
+ <account type="13" name="Refeições Fora"/>
+ <account type="13" name="Presentes"/>
+ <account type="13" name="Despesas com Saúde"/>
+ <account type="13" name="Caridade"/>
+ <account type="13" name="Transportes Públicos"/>
+ <account type="13" name="Automóvel">
+ <account type="13" name="Gasolina"/>
+ <account type="13" name="Estacionamento"/>
+ <account type="13" name="Reparações e Manutenção"/>
+ <account type="13" name="Imposto Selo"/>
+ </account>
+ <account type="13" name="Comissões Bancárias"/>
+ <account type="13" name="Educação"/>
+ <account type="13" name="Serviços">
+ <account type="13" name="Água"/>
+ <account type="13" name="Gás"/>
+ <account type="13" name="Electricidade"/>
+ </account>
+ <account type="13" name="Mat. Escritório"/>
+ <account type="13" name="Roupa"/>
+ <account type="13" name="Assinaturas"/>
+ <account type="13" name="Telefone"/>
+ <account type="13" name="Seguro">
+ <account type="13" name="Seguro Automóvel"/>
+ <account type="13" name="Seguro Vida"/>
+ <account type="13" name="Seguro Saúde"/>
+ </account>
+ <account type="13" name="Serviços Internet"/>
+ <account type="13" name="Ajustamentos"/>
+ <account type="13" name="Impostos">
+ <account type="13" name="Segurança Social"/>
+ <account type="13" name="Municipais"/>
+ <account type="13" name="IRS"/>
+ <account type="13" name="Seguro Saúde"/>
+ <account type="13" name="Outros Impostos"/>
+ </account>
+ <account type="13" name="Computador"/>
+ <account type="13" name="Lavandaria"/>
+ <account type="13" name="Outras"/>
+ <account type="13" name="Mercearia"/>
+ <account type="13" name="Televisão por Cabo"/>
+ <account type="13" name="Passatempos"/>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Contas a Pagar">
+ <account type="4" name="Cartão de Crédito"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/eduloan.kmt b/kmymoney2/templates/pt_PT/eduloan.kmt
new file mode 100644
index 0000000..b4ba1df
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Empréstimo para Educação</title>
+ <shortdesc>Contas para empréstimos para estudos e juros associados</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas se possuir um empréstimo para educação (empréstimo para educação, juros do empréstimo para educação).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juros">
+ <account type="13" name="Juros do Empréstimo para Educação"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Empréstimo para Educação"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/fixedassets.kmt b/kmymoney2/templates/pt_PT/fixedassets.kmt
new file mode 100644
index 0000000..110f580
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Imobilizado Corpóreo</title>
+ <shortdesc>Contas para registar activos fixos de grandes dimensões</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas se tiver activos fixos de grandes dimensões (casa, automóvel, casa de férias, outros activos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Activos Fixos">
+ <account type="9" name="Automóvel"/>
+ <account type="9" name="Outro Activo"/>
+ <account type="9" name="Casa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/homeloan.kmt b/kmymoney2/templates/pt_PT/homeloan.kmt
new file mode 100644
index 0000000..6271d0d
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Empréstimo para Habitação</title>
+ <shortdesc>Contas para empréstimo de habitação e juros associados</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas caso tenha contraido um empréstimo para habitação (emprétimo habitação, juro do empréstimo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juros">
+ <account type="13" name="Juros Empréstimo"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Empréstimo Habitação"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/homeown.kmt b/kmymoney2/templates/pt_PT/homeown.kmt
new file mode 100644
index 0000000..28c3c67
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Despesas da Casa</title>
+ <shortdesc>Despesas associadas à posse de uma habitação</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas caso possua uma habitação própria. Este conjunto disponibiliza um grupo de contas para acompanhar despesas da casa (seguro, impostos, reparações).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Seguro">
+ <account type="13" name="Seguro da Casa"/>
+ </account>
+ <account type="13" name="Impostos">
+ <account type="13" name="Contribuição Autárquica"/>
+ </account>
+ <account type="13" name="Reparações na Casa"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/otherloan.kmt b/kmymoney2/templates/pt_PT/otherloan.kmt
new file mode 100644
index 0000000..8a37577
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Outros Empréstimos</title>
+ <shortdesc>Contas para controlar outros empréstimos e juros associados</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas se tiver outro empréstimo para além do crédito à habitação (outro empréstimo, juros do outro empréstimo).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Juro">
+ <account type="13" name="Outro Juro"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Empréstimos">
+ <account type="10" name="Outros Empréstimo"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/renter.kmt b/kmymoney2/templates/pt_PT/renter.kmt
new file mode 100644
index 0000000..a5f0b4f
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Despesas de Aluguer</title>
+ <shortdesc>Despesas associadas com uma casa alugada</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas caso tenha uma casa alugada (renda, seguro de arrendamento).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Renda"/>
+ <account type="13" name="Seguro">
+ <account type="13" name="Seguro de Arrendamento"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/retiremt.kmt b/kmymoney2/templates/pt_PT/retiremt.kmt
new file mode 100644
index 0000000..498ca3a
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas de Reforma</title>
+ <shortdesc>Contas de reforma com subcontas de investimentos relacionados</shortdesc>
+ <longdesc>Você deverá querer seleccionar este conjunto de contas caso tenha contas de reforma (acções, obrigações, fundos de investimento, fundos de índices).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimentos">
+ <account type="7" name="Reforma"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/spouseinc.kmt b/kmymoney2/templates/pt_PT/spouseinc.kmt
new file mode 100644
index 0000000..3a1a092
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Receitas da Esposa</title>
+ <shortdesc>Contas para registar separadamente as receitas da esposa</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas caso tenha uma esposa que tenha emprego (salário (esposa), impostos (esposa)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Salário (Esposa)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Impostos (Esposa)">
+ <account type="13" name="Segurança Social"/>
+ <account type="13" name="Seguro Saúde"/>
+ <account type="13" name="Municipais"/>
+ <account type="13" name="IRS"/>
+ <account type="13" name="Outros Impostos"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/pt_PT/spouseretire.kmt b/kmymoney2/templates/pt_PT/spouseretire.kmt
new file mode 100644
index 0000000..b66a452
--- /dev/null
+++ b/kmymoney2/templates/pt_PT/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/pt_PT/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Contas de Reforma da Esposa</title>
+ <shortdesc>Conta de reforma com contas de investimentos relacionadas para esposa</shortdesc>
+ <longdesc>Desejará seleccionar este conjunto de contas se tiver investimentos em nome da esposa (acções, obrigações, fundos de investimento, fundos de índices, juros, dividendos).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investimentos">
+ <account type="7" name="Reforma da Esposa"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/ro_RO/Makefile.am b/kmymoney2/templates/ro_RO/Makefile.am
new file mode 100644
index 0000000..1ffb6b8
--- /dev/null
+++ b/kmymoney2/templates/ro_RO/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/ro_RO
+
+template_DATA = carloan.kmt common.kmt default_categories-template.kmt homeloan.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/ro_RO/carloan.kmt b/kmymoney2/templates/ro_RO/carloan.kmt
new file mode 100644
index 0000000..407ee81
--- /dev/null
+++ b/kmymoney2/templates/ro_RO/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Credit auto</title>
+ <shortdesc>Conturi pentru un credid auto şi dobânda aferentăs</shortdesc>
+ <longdesc>Aţi avea nevoie de acest set de conturi dacă aveţi un credit auto (creditul auto, dobânda).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Dobândă">
+ <account type="13" name="Dobândă pentru credit auto"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Credite">
+ <account type="10" name="Credit auto"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/ro_RO/common.kmt b/kmymoney2/templates/ro_RO/common.kmt
new file mode 100644
index 0000000..f5c8250
--- /dev/null
+++ b/kmymoney2/templates/ro_RO/common.kmt
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Conturi comune</title>
+ <shortdesc>Un set de bază de conturi folosite de obicei</shortdesc>
+ <longdesc>Majoritatea utilizatorilor vor alege acest set de conturi. El conţine conturi frecvent folosite (cont curent, de economii, numerar, card de credit, venituri, cheltuieli obişnuite).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Sporuri"/>
+ <account type="12" name="Alte venituri"/>
+ <account type="12" name="Cadou primit"/>
+ <account type="12" name="Salar"/>
+ <account type="12" name="Venit din dobândă">
+ <account type="12" name="Alte dobânzi"/>
+ <account type="12" name="Dobânzi pentru depozit"/>
+ <account type="12" name="Dobânzi la vedere"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Solduri la deschidere"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Active curente">
+ <account type="1" name="Cont curent"/>
+ <account type="3" name="Bani în portofel"/>
+ <account type="1" name="Cont de economii"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Divertisment">
+ <account type="13" name="Filme/Muzică"/>
+ <account type="13" name="Calătorii"/>
+ <account type="13" name="Recreere"/>
+ </account>
+ <account type="13" name="Cărţi"/>
+ <account type="13" name="Servirea mesei la restaurant"/>
+ <account type="13" name="Cadouri"/>
+ <account type="13" name="Cheltuieli medicale"/>
+ <account type="13" name="Caritate"/>
+ <account type="13" name="Transport public"/>
+ <account type="13" name="Automobil">
+ <account type="13" name="Combustibil"/>
+ <account type="13" name="Parcare"/>
+ <account type="13" name="Reparaţii şi întreţinere"/>
+ <account type="13" name="Taxe"/>
+ </account>
+ <account type="13" name="Cheltuieli bancare"/>
+ <account type="13" name="Educaţie"/>
+ <account type="13" name="Utilităţi">
+ <account type="13" name="Apa"/>
+ <account type="13" name="Gaz"/>
+ <account type="13" name="Salubrizare"/>
+ <account type="13" name="Energie electrică"/>
+ </account>
+ <account type="13" name="Îmbrăcăminte"/>
+ <account type="13" name="Reţete medicale"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Asigurări">
+ <account type="13" name="Asigurare auto"/>
+ <account type="13" name="Asigurare de viaţă"/>
+ <account type="13" name="Asigurare de sănătate"/>
+ </account>
+ <account type="13" name="Servicii online"/>
+ <account type="13" name="Taxe">
+ <account type="13" name="Impozit"/>
+ <account type="13" name="Amenzi"/>
+ <account type="13" name="Alte taxe"/>
+ </account>
+ <account type="13" name="Electronică"/>
+ <account type="13" name="Alimente"/>
+ <account type="13" name="Cablu TV"/>
+ <account type="13" name="Hobby-uri"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Card de credit"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/ro_RO/default_categories-template.kmt b/kmymoney2/templates/ro_RO/default_categories-template.kmt
new file mode 100644
index 0000000..20a61ed
--- /dev/null
+++ b/kmymoney2/templates/ro_RO/default_categories-template.kmt
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Categorii implicite KMyMoney 0.8</title>
+ <shortdesc>Un set de categorii de uz comun</shortdesc>
+ <longdesc>Folosiţi acest set de categorii pentru a evita creerea manuală unor categorii obişnuite.</longdesc>
+ <accounts>
+ <account type="12" name="" >
+ <account type="12" name="Venituri ca angajat" >
+ <account type="12" name="Compensaţii" />
+ <account type="12" name="Sporuri" />
+ <account type="12" name="Alte venituri ca angajat" />
+ <account type="12" name="Pensie" />
+ <account type="12" name="Salar" />
+ </account>
+ <account type="12" name="Venituri din investiţii" >
+ <account type="12" name="Câştiguri de capital de termen scurt" />
+ <account type="12" name="Câştiguri de capital de termen lung" />
+ <account type="12" name="Dividende" />
+ <account type="12" name="Dobândă" />
+ <account type="12" name="Dobândă neimpozitabilă" />
+ </account>
+ <account type="12" name="Venituri bancare" >
+ <account type="12" name="Dobândă încasată" />
+ <account type="12" name="Împrumut rambursat" />
+ </account>
+ <account type="12" name="Alte venituri" >
+ <account type="12" name="Pensie alimentară" />
+ <account type="12" name="Alocaţii" />
+ <account type="12" name="Ajutor social" />
+ <account type="12" name="Cadouri primite" />
+ <account type="12" name="Câştiguri din jocuri de noroc" />
+ <account type="12" name="Taxe returnate" />
+ <account type="12" name="Ajutor de şomaj" />
+ </account>
+ <account type="12" name="Bonus de pensionare" />
+ </account>
+ <account type="13" name="" >
+ <account type="13" name="Facturi şi plăţi lunare" >
+ <account type="13" name="Utilităţi" >
+ <account type="13" name="Energie electrică" />
+ <account type="13" name="Gaz" />
+ <account type="13" name="Apa şi canalizare" />
+ <account type="13" name="Ssalubrizare şi reciclare" />
+ </account>
+ <account type="13" name="Telefon" >
+ <account type="13" name="Apeluri locale" />
+ <account type="13" name="Apeluri internaţionale" />
+ <account type="13" name="Mobil" />
+ </account>
+ <account type="13" name="Chirie" />
+ <account type="13" name="Ipoteca" >
+ <account type="13" name="Dobândă" />
+ <account type="13" name="Împrumut" />
+ </account>
+ <account type="13" name="TV Cablu / Satelit" />
+ <account type="13" name="Internet" />
+ </account>
+ <account type="13" name="Cheltuieli bancare" >
+ <account type="13" name="Dobândă plătită" />
+ <account type="13" name="Comisioane bancare" />
+ <account type="13" name="Comision pentru fonduri insuficiente" />
+ </account>
+ <account type="13" name="Retragere numerar" />
+ <account type="13" name="Îngrijirea copilului" />
+ <account type="13" name="Îmbrăcăminte" />
+ <account type="13" name="Educaţie" >
+ <account type="13" name="Cărţi" />
+ <account type="13" name="Taxe" />
+ <account type="13" name="Taxe de şcolarizare" />
+ <account type="13" name="Împrumuturi" />
+ </account>
+ <account type="13" name="Mâncare" >
+ <account type="13" name="Masă servită în oraş" />
+ <account type="13" name="Alimente" />
+ </account>
+ <account type="13" name="Întreţinerea locuinţei" >
+ <account type="13" name="Reparaţii" />
+ <account type="13" name="Îmbunătăţiri" />
+ <account type="13" name="Curte şi grădină" />
+ </account>
+ <account type="13" name="Interiorul locuinţei" >
+ <account type="13" name="Mobilă" />
+ <account type="13" name="Decoraţii" />
+ </account>
+ <account type="13" name="Cadouri" />
+ <account type="13" name="Sănătate" >
+ <account type="13" name="Stomatolog" />
+ <account type="13" name="Doctor" />
+ <account type="13" name="Spitalizare" />
+ <account type="13" name="Reţete" />
+ <account type="13" name="Altele" />
+ </account>
+ <account type="13" name="Îngrijire personală" />
+ <account type="13" name="Concedii şi vacanţe" >
+ <account type="13" name="Cazare" />
+ <account type="13" name="Calătoria" />
+ <account type="13" name="Altele" />
+ <account type="13" name="Mâncare" />
+ </account>
+ <account type="13" name="Asigurare" >
+ <account type="13" name="Locuintă" />
+ <account type="13" name="Viată" />
+ <account type="13" name="Medicală" />
+ <account type="13" name="Auto" />
+ </account>
+ <account type="13" name="Cheltuieli la locul de muncă" >
+ <account type="13" name="Rambursate" />
+ <account type="13" name="Nerambursate" />
+ </account>
+ <account type="13" name="Timp liber" >
+ <account type="13" name="Divertisment" />
+ <account type="13" name="Hobby-uri" />
+ <account type="13" name="Sport" />
+ </account>
+ <account type="13" name="Taxe legale" />
+ <account type="13" name="Alte cheltuieli" />
+ <account type="13" name="Îngrijirea animalelor de casă" >
+ <account type="13" name="Mâncare" />
+ <account type="13" name="Consumabile" />
+ <account type="13" name="Cheltuieli veterinare" />
+ </account>
+ <account type="13" name="Retirement Accounts" />
+ <account type="13" name="Taxes" />
+ <account type="13" name="Transport" >
+ <account type="13" name="Automobil" >
+ <account type="13" name="Combustibil" />
+ <account type="13" name="Impozit" />
+ <account type="13" name="Service" />
+ <account type="13" name="Parcare" />
+ <account type="13" name="Asigurare" />
+ <account type="13" name="Leasing" />
+ <account type="13" name="Închiriere" />
+ <account type="13" name="Înmatriculare" />
+ </account>
+ <account type="13" name="Transport public" />
+ </account>
+ <account type="13" name="Uz casnic" />
+ <account type="13" name="Caritate" />
+ <account type="13" name="Taxe contabile" />
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/ro_RO/homeloan.kmt b/kmymoney2/templates/ro_RO/homeloan.kmt
new file mode 100644
index 0000000..ce3ece2
--- /dev/null
+++ b/kmymoney2/templates/ro_RO/homeloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/C/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Credit ipotecar</title>
+ <shortdesc>Conturi pentru un credit ipotecar şi dobânzile aferente</shortdesc>
+ <longdesc>Aţi avea nevoie de acest set de conturi dacă aveţi un credit ipotecar (creditul ipotecar, dobânda).</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="Credit ipotecar"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Dobândă">
+ <account type="13" name="Dobândă ipotecară"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/ru_RU/Makefile.am b/kmymoney2/templates/ru_RU/Makefile.am
new file mode 100644
index 0000000..192797d
--- /dev/null
+++ b/kmymoney2/templates/ru_RU/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/ru_RU
+
+template_DATA = default_accounts.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/ru_RU/default_accounts.kmt b/kmymoney2/templates/ru_RU/default_accounts.kmt
new file mode 100644
index 0000000..0cd1b87
--- /dev/null
+++ b/kmymoney2/templates/ru_RU/default_accounts.kmt
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Персональные финансы</title>
+ <shortdesc>Учёт персональных финансов</shortdesc>
+ <longdesc>Статьи доходов и затрат для учёта персональных финансов</longdesc>
+ <accounts>
+ <account name="" type="13">
+ <account name="Оплата счетов" type="13">
+ <account name="Телефон" type="13"/>
+ <account name="Квартира" type="13"/>
+ <account name="Электричество" type="13"/>
+ <account name="Интернет" type="13"/>
+ <account name="ТВ" type="13"/>
+ <account name="Газ" type="13"/>
+ <account name="Отопление" type="13"/>
+ <account name="Водоснабжение" type="13"/>
+ </account>
+ <account name="Транспорт" type="13">
+ <account name="Содержание автомобиля" type="13"/>
+ <account name="Бензин" type="13"/>
+ <account name="Общественный транспорт" type="13"/>
+ </account>
+ <account name="Питание" type="13">
+ <account name="Продукты" type="13"/>
+ <account name="Общественное питание" type="13"/>
+ </account>
+ <account name="Товары" type="13">
+ <account name="Косметика и парфюмерия" type="13"/>
+ <account name="Одежда и обувь" type="13"/>
+ <account name="Бытовая техника" type="13"/>
+ </account>
+ <account name="Услуги" type="13">
+ <account name="Уход за ребёнком" type="13"/>
+ <account name="Образование" type="13"/>
+ <account name="Медицина" type="13"/>
+ <account name="Прочие услуги" type="13"/>
+ </account>
+ <account name="Домашнее хозяйство" type="13"/>
+ <account name="Досуг" type="13">
+ <account name="Книги и журналы" type="13"/>
+ <account name="Театр и кино" type="13"/>
+ <account name="Спорт" type="13"/>
+ <account name="Музыка" type="13"/>
+ <account name="Развлечения" type="13"/>
+ </account>
+ <account name="Прочее" type="13">
+ <account name="Отпуск" type="13"/>
+ <account name="Подарки" type="13"/>
+ <account name="Страхование" type="13"/>
+ <account name="Выплата процентов" type="13"/>
+ <account name="Налоги" type="13"/>
+ <account name="Другие расходы" type="13"/>
+ </account>
+ </account>
+
+ <account name="" type="12">
+ <account name="Работа" type="12">
+ <account name="Заработная плата" type="12"/>
+ <account name="Премиальные" type="12"/>
+ <account name="Подработка" type="12"/>
+ </account>
+ <account name="Инвестиции" type="12">
+ <account name="Банковские проценты" type="12"/>
+ <account name="Доход по ценным бумагам" type="12"/>
+ <account name="Сдача жилья в аренду" type="12"/>
+ </account>
+ <account name="Прочее" type="12">
+ <account name="Стипендия" type="12"/>
+ <account name="Пенсия" type="12"/>
+ <account name="Помощь родственников" type="12"/>
+ <account name="Налоговые льготы" type="12"/>
+ <account name="Пособия" type="12"/>
+ <account name="Другие доходы" type="12"/>
+ </account>
+ </account>
+
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/Makefile.am b/kmymoney2/templates/sk/Makefile.am
new file mode 100644
index 0000000..f963d21
--- /dev/null
+++ b/kmymoney2/templates/sk/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/sk
+
+template_DATA = homeown.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt renter.kmt common.kmt spouseretire.kmt currency.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt carloan.kmt otherloan.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/sk/brokerage.kmt b/kmymoney2/templates/sk/brokerage.kmt
new file mode 100644
index 0000000..1082800
--- /dev/null
+++ b/kmymoney2/templates/sk/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Investičné účty</title>
+ <shortdesc>Účty, ktoré súvisia s investovaním</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, vlastníte investície (akcie, dlhopisy, podielové listy).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Poplatky"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Dividendový príjem"/>
+ <account type="12" name="Úrokový príjem">
+ <account type="12" name="Úrok dlhopisu"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Investície">
+ <account type="7" name="Brokerov účet"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/carloan.kmt b/kmymoney2/templates/sk/carloan.kmt
new file mode 100644
index 0000000..a85f99a
--- /dev/null
+++ b/kmymoney2/templates/sk/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Úver na auto</title>
+ <shortdesc>Účty pre úver na auto</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak ste si zobrali pôžičku na auto.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Úrok">
+ <account type="13" name="Úrok z úveru na dopravný prostriedok"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Dlhy">
+ <account type="10" name="Úver na dopravný prostriedok"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/cdmoneymkt.kmt b/kmymoney2/templates/sk/cdmoneymkt.kmt
new file mode 100644
index 0000000..0a54c59
--- /dev/null
+++ b/kmymoney2/templates/sk/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Depozitný certifikát a peňažný trh</title>
+ <shortdesc>Účty pre depozitné certifikáty a investície na peňažnom trhu</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak vlastníte depozitné certifikáty alebo investujete na peňažnom trhu.</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Úrokový príjem">
+ <account type="12" name="Úrok depozitného certifikátu"/>
+ <account type="12" name="Úrok peňažného trhu"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Bežné aktíva">
+ <account type="1" name="Peňažný trh"/>
+ <account type="1" name="Depozitný certifikát"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/childcare.kmt b/kmymoney2/templates/sk/childcare.kmt
new file mode 100644
index 0000000..d58d5cb
--- /dev/null
+++ b/kmymoney2/templates/sk/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Výdavky na staroslivosť o dieťa</title>
+ <shortdesc>Účet na zaznamenávanie výdavkov na starostlivosť o dieťa</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak máte výdavky na starostlivosť o dieťa.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Staroslivosť o dieťa"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/common.kmt b/kmymoney2/templates/sk/common.kmt
new file mode 100644
index 0000000..439294a
--- /dev/null
+++ b/kmymoney2/templates/sk/common.kmt
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Bežné účty</title>
+ <shortdesc>Základná sada najčastejšie používaných účtov</shortdesc>
+ <longdesc>Väčšina užívateľov si zvolí túto sadu, lebo obsahuje bežne používané účty (šeky, úspory, hotovosť, platobné karty, príjmy, bežné výdaje).</longdesc>
+ <accounts>
+ <account type="16" name="">
+ <account type="16" name="Počiatočný stav"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Aktuálne aktíva">
+ <account type="1" name="Šekový účet"/>
+ <account type="3" name="Hotovosť v peňaženke"/>
+ <account type="1" name="Úspory"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Jedáleň"/>
+ <account type="13" name="MHD"/>
+ <account type="13" name="Vzdelávanie"/>
+ <account type="13" name="Bežné služby">
+ <account type="13" name="Plyn"/>
+ <account type="13" name="Zbierky bezcenností"/>
+ <account type="13" name="Voda"/>
+ <account type="13" name="Elektrická energia"/>
+ </account>
+ <account type="13" name="Predplatné"/>
+ <account type="13" name="Telefón"/>
+ <account type="13" name="Online služby"/>
+ <account type="13" name="Potraviny"/>
+ <account type="13" name="Zábava">
+ <account type="13" name="Cestovanie"/>
+ <account type="13" name="Rekreácia"/>
+ <account type="13" name="Hudba/Film"/>
+ </account>
+ <account type="13" name="Knihy"/>
+ <account type="13" name="Dary"/>
+ <account type="13" name="Lekárske ošetrenie"/>
+ <account type="13" name="Charita"/>
+ <account type="13" name="Auto">
+ <account type="13" name="Benzín"/>
+ <account type="13" name="Opravy a udržiavanie"/>
+ <account type="13" name="Parkovné"/>
+ <account type="13" name="Poplatky"/>
+ </account>
+ <account type="13" name="Poplatky za bankové služby"/>
+ <account type="13" name="Ošatenie"/>
+ <account type="13" name="Zásobovanie"/>
+ <account type="13" name="Poistenie">
+ <account type="13" name="Poistenie auta"/>
+ <account type="13" name="Životné poistenie"/>
+ <account type="13" name="Zdravotné poistenie"/>
+ </account>
+ <account type="13" name="Úpravy"/>
+ <account type="13" name="Odvody a dane">
+ <account type="13" name="Miestne dane a poplatky"/>
+ <account type="13" name="Sociálne poistenie"/>
+ <account type="13" name="Celoštátne dane"/>
+ <account type="13" name="Zdravotná starostlivosť"/>
+ <account type="13" name="Ostatné dane"/>
+ </account>
+ <account type="13" name="Počítač"/>
+ <account type="13" name="Práčovňa/Čistiareň"/>
+ <account type="13" name="Rôzne"/>
+ <account type="13" name="Káblovka"/>
+ <account type="13" name="Záľuby"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Bonus"/>
+ <account type="12" name="Ostatné príjmy"/>
+ <account type="12" name="Prijaté dary"/>
+ <account type="12" name="Mzda"/>
+ <account type="12" name="Úrokový príjem">
+ <account type="12" name="Šekový úrok"/>
+ <account type="12" name="Ostatné úroky"/>
+ <account type="12" name="Úroky z úspor"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Splatné účty">
+ <account type="4" name="Platobná karta"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/currency.kmt b/kmymoney2/templates/sk/currency.kmt
new file mode 100644
index 0000000..828f264
--- /dev/null
+++ b/kmymoney2/templates/sk/currency.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_currency.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Účet na obchodovanie s menou</title>
+ <shortdesc>Účet na obchodovanie a konvertovanie zahraničných mien</shortdesc>
+ <longdesc>Tento účet budete potrebovať, ak budete konvertovať zahraničné meny. Poznámka: účet je aktuálne v DEM; ak chcete, možete to zmeniť.</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investície"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/eduloan.kmt b/kmymoney2/templates/sk/eduloan.kmt
new file mode 100644
index 0000000..64d2004
--- /dev/null
+++ b/kmymoney2/templates/sk/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Študijná pôžička</title>
+ <shortdesc>Účty pre študijnú pôžičku</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak ste si zobrali pôžičku na štúdium.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Úrok">
+ <account type="13" name="Úrok zo študijnej pôžičky"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Dlhy">
+ <account type="10" name="Študijná pôžička"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/fixedassets.kmt b/kmymoney2/templates/sk/fixedassets.kmt
new file mode 100644
index 0000000..43d4b31
--- /dev/null
+++ b/kmymoney2/templates/sk/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Fixné aktíva</title>
+ <shortdesc>Účty pre zaznamenávanie rozsiahlych fixných aktív</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak vlastníte veľké fixné aktíva (dom, dopravné prostriedky, ostatné aktíva).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Fixné aktíva">
+ <account type="9" name="Dopravný prostriedok"/>
+ <account type="9" name="Ostatné aktíva"/>
+ <account type="9" name="Dom"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/homeloan.kmt b/kmymoney2/templates/sk/homeloan.kmt
new file mode 100644
index 0000000..ca1fc90
--- /dev/null
+++ b/kmymoney2/templates/sk/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Hypotekárny úver</title>
+ <shortdesc>Účty pre hypotekárny úver a s tým súvisiaci úrok</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak ste si zobrali úver na dom (hypoteku).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Úrok">
+ <account type="13" name="Hypotekárny úrok"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Dlhy">
+ <account type="10" name="Hypotekárny úver"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/homeown.kmt b/kmymoney2/templates/sk/homeown.kmt
new file mode 100644
index 0000000..d7d8963
--- /dev/null
+++ b/kmymoney2/templates/sk/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Výdaje z vlastníctva domu</title>
+ <shortdesc>Výdaje, ktoré sú spojené s vlastnením domu</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak vlastníte dom. Táto sada poskytuje skupinu účtov na sledovanie výdajov na dom (poistenie, dane, opravy domu).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Poistenie">
+ <account type="13" name="Poistenie"/>
+ </account>
+ <account type="13" name="Dane">
+ <account type="13" name="Majetková daň"/>
+ </account>
+ <account type="13" name="Opravy domu"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/otherloan.kmt b/kmymoney2/templates/sk/otherloan.kmt
new file mode 100644
index 0000000..67b8ca7
--- /dev/null
+++ b/kmymoney2/templates/sk/otherloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Ostatné pôžičky</title>
+ <shortdesc>Účty pre zaznamenávanie ostatných pôžičiek</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak máte aj inú než hypotekárnu pôžičku.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Úrok">
+ <account type="13" name="Ostatné úroky"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Dlhy">
+ <account type="10" name="Iné pôžičky"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/renter.kmt b/kmymoney2/templates/sk/renter.kmt
new file mode 100644
index 0000000..04ca9ab
--- /dev/null
+++ b/kmymoney2/templates/sk/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Výdavky na nájomné</title>
+ <shortdesc>Výdavky spojené s nájmom domu</shortdesc>
+ <longdesc>Túto sadu účtov si zvoľte, ak si prenajímate dom alebo byt (nájomné, poistenie)</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Nájomné"/>
+ <account type="13" name="Poistenie">
+ <account type="13" name="Poistenie nájomného"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/retiremt.kmt b/kmymoney2/templates/sk/retiremt.kmt
new file mode 100644
index 0000000..4502136
--- /dev/null
+++ b/kmymoney2/templates/sk/retiremt.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Dôchodkové účty</title>
+ <shortdesc>Dôchodkový účet so vzťahom na investičné podúčty</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak máte účty, ktoré vám prinášajú dôchodok (akcie, dlhopisy, podielové listy, index fondov).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investície">
+ <account type="7" name="Dôchodok"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/spouseinc.kmt b/kmymoney2/templates/sk/spouseinc.kmt
new file mode 100644
index 0000000..0477a01
--- /dev/null
+++ b/kmymoney2/templates/sk/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Manželov/Manželkin príjem</title>
+ <shortdesc>Účty na osobitné zaznamenávanie príjmu životného partnera</shortdesc>
+ <longdesc>Túto sadu účtov si zvoľte, ak váš životný partner pracuje.</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Mzda (Partnerova)"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Dane a poplatky (Partnerove)">
+ <account type="13" name="Sociálne poistenie"/>
+ <account type="13" name="Zdravotná starostlivosť"/>
+ <account type="13" name="Miestne dane"/>
+ <account type="13" name="Celoštátne dane"/>
+ <account type="13" name="Ostatné dane"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/sk/spouseretire.kmt b/kmymoney2/templates/sk/spouseretire.kmt
new file mode 100644
index 0000000..04c1c89
--- /dev/null
+++ b/kmymoney2/templates/sk/spouseretire.kmt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/sk/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Manželov/Manželkin dôchodok</title>
+ <shortdesc>Dôchodkový účet so vzťahom na investičný účet životného partnera</shortdesc>
+ <longdesc>Zvoľte si túto sadu účtov, ak ste investovali v partnerovom mene (akcie, dlhopisy, podielové listy).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Investície">
+ <account type="7" name="Partnerov dôchodok"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/Makefile.am b/kmymoney2/templates/tr_TR/Makefile.am
new file mode 100644
index 0000000..f477278
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/tr_TR
+
+template_DATA = fixedassets.kmt homeloan.kmt common.kmt brokerage.kmt TEKDUZ.kmt cdmoneymkt.kmt checkbook.kmt carloan.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/tr_TR/TEKDUZ.kmt b/kmymoney2/templates/tr_TR/TEKDUZ.kmt
new file mode 100644
index 0000000..e35d09f
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/TEKDUZ.kmt
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_TEKDUZ.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>TEK DÜZEN</title>
+ <shortdesc>Tek Düzen Hesap Planı</shortdesc>
+ <longdesc>Tek Düzen Hesap Planı</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="3" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="10" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="16" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="A&#231;&#253;l&#253;&#254; Bakiyeleri"/>
+ </account>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="16" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="16" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="12" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="1" name=""/>
+ <account type="12" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="16" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="16" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="16" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="10" name=""/>
+ <account type="16" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="10" name=""/>
+ <account type="10" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="9" name=""/>
+ <account type="9" name=""/>
+ <account type="13" name=""/>
+ <account type="10" name=""/>
+ <account type="13" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/brokerage.kmt b/kmymoney2/templates/tr_TR/brokerage.kmt
new file mode 100644
index 0000000..ab0f7a1
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Menkul Kıymet Yatırımları</title>
+ <shortdesc>Aracı kurumlar nezdinde işlem gören menkul kıymet yatırımları</shortdesc>
+ <longdesc>Aracı kurumlar nezdinde işlem gören yatırımlarınızı (hisse senedi, tahvil/bono, A/B tipi yatırım fonları, katılma belgeleri, faiz, temettü) takip etmenizi sağlayan hesaplar</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Komisyonlar"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="Temettü Geliri"/>
+ <account type="12" name="Faiz Geliri">
+ <account type="12" name="Tahvil/Bono Faizi"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Yatırımlar">
+ <account type="7" name="Aracı Kurum Hesabı"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/carloan.kmt b/kmymoney2/templates/tr_TR/carloan.kmt
new file mode 100644
index 0000000..6857fd2
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Taşıt Kredisi</title>
+ <shortdesc>Taşıt Kredisi ve faizleri</shortdesc>
+ <longdesc>Taşıt kredisi ve faizlerini takip etmenizi sağlayan hesaplar (taşıt kredisi, kredi faizleri).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Faiz">
+ <account type="13" name="Taşıt Kredi Faizi"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Krediler">
+ <account type="10" name="Taşıt Kredisi"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/cdmoneymkt.kmt b/kmymoney2/templates/tr_TR/cdmoneymkt.kmt
new file mode 100644
index 0000000..87eff05
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Repo, Mevduat Sertifikası</title>
+ <shortdesc>Repo, Mevduat Sertifikası ve diğer para piyasası araçları</shortdesc>
+ <longdesc>Repo, Mevduat Sertifikası gibi para piyasası araçlarınızı takip etmenizi sağlayan hesaplar</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="Faiz Geliri">
+ <account type="12" name="MS Faizi"/>
+ <account type="12" name="Repo Faizi"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Cari Varlıklar">
+ <account type="1" name="Repo"/>
+ <account type="1" name="Mevduat Sertifikası"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/checkbook.kmt b/kmymoney2/templates/tr_TR/checkbook.kmt
new file mode 100644
index 0000000..1f7fc2b
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Çek Defteri/Maaş</title>
+ <shortdesc>GnuCash kullanmanız için gereken asgari hesaplar</shortdesc>
+ <longdesc>Çek/maaş hesabınızı takip etmek için bu planı kullanın. Daha sonra ihtiyaç duyarsanız, gelir ve giderlerinizi daha detaylı takip etmenizi sağlayacak bir plana geçersiniz.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="Açılış Bakiyeleri"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Cari Varlıklar">
+ <account type="1" name="Çek/Maaş Hesabı"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/common.kmt b/kmymoney2/templates/tr_TR/common.kmt
new file mode 100644
index 0000000..9b5b625
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Genel</title>
+ <shortdesc>Kişisel kullanıma uygun, günlük hayatta sık rastlanan kalemler</shortdesc>
+ <longdesc>Pek çok kişinin tercih edeceği, yaygın kullanılan kalemleri takip etmenizi sağlayan hesaplar</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="İkramiye"/>
+ <account type="12" name="Diğer Gelirler"/>
+ <account type="12" name="Hediye Çekleri"/>
+ <account type="12" name="Maaş"/>
+ <account type="12" name="Faiz Geliri">
+ <account type="12" name="Diğer Faizler"/>
+ <account type="12" name="Vadeli Faizi"/>
+ <account type="12" name="Vadesiz Faizi"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="Açılış Bakiyeleri"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="Cari Varlıklar">
+ <account type="1" name="Vadesiz/Maaş Hesabı"/>
+ <account type="3" name="Nakit"/>
+ <account type="1" name="Vadeli Hesap"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="Eğlence">
+ <account type="13" name="Müzik/Sinema"/>
+ <account type="13" name="Seyahat"/>
+ <account type="13" name="Sosyal Faaliyetler"/>
+ </account>
+ <account type="13" name="Kitap"/>
+ <account type="13" name="Lokanta"/>
+ <account type="13" name="Hediyeler"/>
+ <account type="13" name="Sağlık Harcamaları"/>
+ <account type="13" name="Bağışlar"/>
+ <account type="13" name="Toplu Taşıma"/>
+ <account type="13" name="Taşıt">
+ <account type="13" name="Akaryakıt"/>
+ <account type="13" name="Park"/>
+ <account type="13" name="Bakım ve Onarım"/>
+ <account type="13" name="M.T.V. Taksitleri"/>
+ </account>
+ <account type="13" name="Banka İşlem Masrafları"/>
+ <account type="13" name="Eğitim"/>
+ <account type="13" name="Gayrımenkul Giderleri">
+ <account type="13" name="Su"/>
+ <account type="13" name="D.Gaz"/>
+ <account type="13" name="Kapıcı"/>
+ <account type="13" name="Elektrik"/>
+ </account>
+ <account type="13" name="Kırtasiye"/>
+ <account type="13" name="Giyecek"/>
+ <account type="13" name="Abonelik/Üyelik"/>
+ <account type="13" name="Telefon"/>
+ <account type="13" name="Sigorta">
+ <account type="13" name="Taşıt Sigortası"/>
+ <account type="13" name="Hayat Sigortası"/>
+ <account type="13" name="Sağlık Sigortası"/>
+ </account>
+ <account type="13" name="Internet"/>
+ <account type="13" name="Diğer"/>
+ <account type="13" name="Vergiler">
+ <account type="13" name="Emlak"/>
+ <account type="13" name="Çevre Temizlik"/>
+ <account type="13" name="KDV"/>
+ <account type="13" name="ÖTV/ÖİV"/>
+ <account type="13" name="Diğer Vergiler"/>
+ </account>
+ <account type="13" name="Bilgisayar"/>
+ <account type="13" name="Temizlikçi/Kuru Temizleme"/>
+ <account type="13" name="Çeşitli"/>
+ <account type="13" name="Market/Pazar"/>
+ <account type="13" name="KabloTV/Uydu"/>
+ <account type="13" name="Hobi"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="Kredi Kartı"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/fixedassets.kmt b/kmymoney2/templates/tr_TR/fixedassets.kmt
new file mode 100644
index 0000000..8de2e09
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Maddi Duran Varlıklar</title>
+ <shortdesc>Büyük sabit varlıklar</shortdesc>
+ <longdesc>Maddi duran varlıklarınzı (ev, taşıt, yazlık, arsa, vs) takip etmenizi sağlayan hesaplar</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="Maddi Duran Varlıklar">
+ <account type="9" name="Taşıt"/>
+ <account type="9" name="Diğer Varlıklar"/>
+ <account type="9" name="Ev"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/tr_TR/homeloan.kmt b/kmymoney2/templates/tr_TR/homeloan.kmt
new file mode 100644
index 0000000..bfd4a7e
--- /dev/null
+++ b/kmymoney2/templates/tr_TR/homeloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/tr_TR/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Ev Kredisi</title>
+ <shortdesc>Ev Kredisi ve faizleri</shortdesc>
+ <longdesc>Ev kredisi ve faizlerini takip etmenizi sağlayan hesaplar (ev kredisi, kredi faizleri).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="Faiz">
+ <account type="13" name="Kredi Faizi"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="Krediler">
+ <account type="10" name="Ev Kredisi"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/Makefile.am b/kmymoney2/templates/zh_CN/Makefile.am
new file mode 100644
index 0000000..d5f71c7
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/zh_CN
+
+template_DATA = homeown.kmt full.kmt fixedassets.kmt retiremt.kmt eduloan.kmt homeloan.kmt default_accounts.kmt renter.kmt common.kmt spouseretire.kmt brokerage.kmt childcare.kmt cdmoneymkt.kmt checkbook.kmt carloan.kmt otherloan.kmt business.kmt spouseinc.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/zh_CN/brokerage.kmt b/kmymoney2/templates/zh_CN/brokerage.kmt
new file mode 100644
index 0000000..b76c89a
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/brokerage.kmt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_brokerage.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>投资帐户</title>
+ <shortdesc>Brokerage account with related investment accounts (stock, bond, mutual fund, index fund, interest, dividend)</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have investments (stock, bond, mutual fund, index fund, interest, dividend).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="佣金"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="股利收入"/>
+ <account type="12" name="利息收入">
+ <account type="12" name="债券利率"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="投资">
+ <account type="7" name="经纪帐户"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/business.kmt b/kmymoney2/templates/zh_CN/business.kmt
new file mode 100644
index 0000000..5544d4c
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>商业帐户</title>
+ <shortdesc>Full chart of accounts for a business.</shortdesc>
+ <longdesc>Users running a business want to select this instead of other choices. This includes all the accounts you need to run a most businesses, including Payables, Receivables, Income, and Expenses.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="信用卡"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="留存收益"/>
+ <account type="16" name="期初余额"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="设备租赁"/>
+ <account type="13" name="杂项"/>
+ <account type="13" name="修理">
+ <account type="13" name="设备维修"/>
+ <account type="13" name="建筑修复"/>
+ <account type="13" name="电脑维修"/>
+ <account type="13" name="清洁卫生费"/>
+ </account>
+ <account type="13" name="邮资及运送"/>
+ <account type="13" name="教育"/>
+ <account type="13" name="折旧"/>
+ <account type="13" name="办公用品"/>
+ <account type="13" name="专业费用">
+ <account type="13" name="律师费"/>
+ <account type="13" name="会计"/>
+ </account>
+ <account type="13" name="印刷和复印"/>
+ <account type="13" name="用餐"/>
+ <account type="13" name="应得物和捐款"/>
+ <account type="13" name="执照和许可证"/>
+ <account type="13" name="现金折扣"/>
+ <account type="13" name="薪金支出"/>
+ <account type="13" name="境外服务"/>
+ <account type="13" name="调整"/>
+ <account type="13" name="旅行和娱乐">
+ <account type="13" name="用餐"/>
+ <account type="13" name="旅行"/>
+ <account type="13" name="娱乐"/>
+ </account>
+ <account type="13" name="慈善"/>
+ <account type="13" name="汽车">
+ <account type="13" name="维修和保养"/>
+ <account type="13" name="燃气"/>
+ <account type="13" name="停车"/>
+ <account type="13" name="收费"/>
+ </account>
+ <account type="13" name="租金"/>
+ <account type="13" name="水电费">
+ <account type="13" name="燃气"/>
+ <account type="13" name="垃圾收集"/>
+ <account type="13" name="因特网"/>
+ <account type="13" name="手机"/>
+ <account type="13" name="电报"/>
+ <account type="13" name="电"/>
+ <account type="13" name="水"/>
+ <account type="13" name="电话"/>
+ </account>
+ <account type="13" name="保险">
+ <account type="13" name="残疾保险金"/>
+ <account type="13" name="工作者Comp"/>
+ <account type="13" name="责任保险"/>
+ </account>
+ <account type="13" name="银行服务收费"/>
+ <account type="13" name="税收">
+ <account type="13" name="联邦"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="财产"/>
+ <account type="13" name="本地"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="其它税"/>
+ <account type="13" name="州/省"/>
+ <account type="13" name="FUTA"/>
+ </account>
+ <account type="13" name="书籍"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="利息收入"/>
+ <account type="12" name="销售"/>
+ <account type="12" name="其他收入"/>
+ <account type="12" name="报销的费用"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流动资产">
+ <account type="1" name="储蓄帐户"/>
+ <account type="3" name="零用金"/>
+ <account type="1" name="支票帐户"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/carloan.kmt b/kmymoney2/templates/zh_CN/carloan.kmt
new file mode 100644
index 0000000..0a9934a
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/carloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_carloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Car Loan</title>
+ <shortdesc>Accounts for car loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a car loan (car loan, car loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="兴趣">
+ <account type="13" name="汽车贷款利息"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="贷款">
+ <account type="10" name="汽车贷款"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/cdmoneymkt.kmt b/kmymoney2/templates/zh_CN/cdmoneymkt.kmt
new file mode 100644
index 0000000..71e9387
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/cdmoneymkt.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_cdmoneymkt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>CD and Money Market</title>
+ <shortdesc>Accounts for CD and money market investments</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have CDs or money market accounts (CD, CD interest, money market, money market interest).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="利息收入">
+ <account type="12" name="光盘兴趣"/>
+ <account type="12" name="货币市场利率"/>
+ </account>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流动资产">
+ <account type="1" name="货币市场"/>
+ <account type="1" name="银行CD"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/checkbook.kmt b/kmymoney2/templates/zh_CN/checkbook.kmt
new file mode 100644
index 0000000..146497e
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/checkbook.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_checkbook.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>A Simple Checkbook</title>
+ <shortdesc>The minimal set of accounts to use GnuCash.</shortdesc>
+ <longdesc>Use this if you just want to balance your checkbook. Later on, you can start tracking income and expenses in more detail if you feel the need.</longdesc>
+ <accounts>
+ <account type="13" name=""/>
+ <account type="12" name=""/>
+ <account type="16" name="">
+ <account type="16" name="期初余额"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流动资产">
+ <account type="1" name="支票帐户"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/childcare.kmt b/kmymoney2/templates/zh_CN/childcare.kmt
new file mode 100644
index 0000000..0de00e4
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/childcare.kmt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_childcare.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Childcare Expenses</title>
+ <shortdesc>An account for tracking childcare costs</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have childcare expenses.</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="育儿"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/common.kmt b/kmymoney2/templates/zh_CN/common.kmt
new file mode 100644
index 0000000..8a68932
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/common.kmt
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_common.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>通用帐户</title>
+ <shortdesc>A basic set of accounts most commonly used</shortdesc>
+ <longdesc>Most users will want to select this set of accounts. It includes most commonly used accounts (checking, savings, cash, credit card, income, common expenses).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="奖金"/>
+ <account type="12" name="其他收入"/>
+ <account type="12" name="收到的礼物"/>
+ <account type="12" name="薪金"/>
+ <account type="12" name="利息收入">
+ <account type="12" name="其他利息"/>
+ <account type="12" name="储蓄存款利息所得"/>
+ <account type="12" name="支票利息"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="期初余额"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流动资产">
+ <account type="1" name="支票帐户"/>
+ <account type="3" name="现金的钱包"/>
+ <account type="1" name="储蓄帐户"/>
+ </account>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="娱乐">
+ <account type="13" name="Music/Movies"/>
+ <account type="13" name="旅行"/>
+ <account type="13" name="娱乐"/>
+ </account>
+ <account type="13" name="书籍"/>
+ <account type="13" name="用餐"/>
+ <account type="13" name="礼品"/>
+ <account type="13" name="医疗费用"/>
+ <account type="13" name="慈善"/>
+ <account type="13" name="公共交通"/>
+ <account type="13" name="汽车">
+ <account type="13" name="燃气"/>
+ <account type="13" name="停车"/>
+ <account type="13" name="维修和保养"/>
+ <account type="13" name="收费"/>
+ </account>
+ <account type="13" name="银行服务收费"/>
+ <account type="13" name="教育"/>
+ <account type="13" name="水电费">
+ <account type="13" name="水"/>
+ <account type="13" name="燃气"/>
+ <account type="13" name="垃圾收集"/>
+ <account type="13" name="电"/>
+ </account>
+ <account type="13" name="供应品"/>
+ <account type="13" name="衣服"/>
+ <account type="13" name="订阅杂志"/>
+ <account type="13" name="电话"/>
+ <account type="13" name="保险">
+ <account type="13" name="汽车保险"/>
+ <account type="13" name="人寿保险"/>
+ <account type="13" name="健康保险"/>
+ </account>
+ <account type="13" name="在线服务"/>
+ <account type="13" name="调整"/>
+ <account type="13" name="税收">
+ <account type="13" name="社会保险"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="联邦"/>
+ <account type="13" name="医保"/>
+ <account type="13" name="其它税"/>
+ </account>
+ <account type="13" name="电脑"/>
+ <account type="13" name="Laundry/Dry Cleaning"/>
+ <account type="13" name="杂项"/>
+ <account type="13" name="杂货"/>
+ <account type="13" name="电报"/>
+ <account type="13" name="爱好"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="信用卡"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/default_accounts.kmt b/kmymoney2/templates/zh_CN/default_accounts.kmt
new file mode 100644
index 0000000..a6efd90
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/default_accounts.kmt
@@ -0,0 +1,162 @@
+<?xml version = '1.0' encoding = 'utf-8'?>
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>KMyMoney 0.8 default</title>
+ <shortdesc/>
+ <longdesc/>
+ <accounts>
+ <account type="13" name="" >
+ <account type="13" name="账单" >
+ <account type="13" name="电话费" />
+ <account type="13" name="Rent" />
+ <account type="13" name="电费" />
+ <account type="13" name="有线电视费" />
+ <account type="13" name="燃气费" />
+ <account type="13" name="抵押贷款" >
+ <account type="13" name="利息" >
+ </account>
+ <account type="13" name="本金" >
+ </account>
+ </account>
+ <account type="13" name="水费与污水处理费" />
+ <account type="13" name="物业费" />
+ </account>
+ <account type="13" name="银行费用" >
+ <account type="13" name="支付利息" />
+ <account type="13" name="手续费" />
+ </account>
+ <account type="13" name="汽车" >
+ <account type="13" name="汽油" />
+ <account type="13" name="维护" />
+ <account type="13" name="保险" />
+ <account type="13" name="租金" />
+ <account type="13" name="车贷" />
+ <account type="13" name="上路费用" />
+ </account>
+ <account type="13" name="现金提款" />
+ <account type="13" name="慈善事业" >
+ <account type="13" name="捐款" />
+ </account>
+ <account type="13" name="儿童看护" />
+ <account type="13" name="服装" />
+ <account type="13" name="教育" >
+ <account type="13" name="书籍" />
+ <account type="13" name="其他费用" />
+ <account type="13" name="学费" />
+ <account type="13" name="助学贷款" />
+ </account>
+ <account type="13" name="吃喝" >
+ <account type="13" name="下馆子" />
+ <account type="13" name="食品饮料" />
+ </account>
+ <account type="13" name="礼物" />
+ <account type="13" name="健康支出" >
+ <account type="13" name="牙科" />
+ <account type="13" name="看病" />
+ <account type="13" name="住院" />
+ <account type="13" name="眼镜" />
+ <account type="13" name="买药" />
+ </account>
+ <account type="13" name="渡假" >
+ <account type="13" name="食宿" />
+ <account type="13" name="旅行" />
+ </account>
+ <account type="13" name="日常家务" >
+ <account type="13" name="家具" />
+ <account type="13" name="日常维修" />
+ <account type="13" name="日用品" />
+ </account>
+ <account type="13" name="保险" >
+ <account type="13" name="家庭财产保险" />
+ <account type="13" name="寿险" />
+ <account type="13" name="健康险" />
+ <account type="13" name="车辆保险" />
+ <account type="13" name="伤残险" />
+ </account>
+ <account type="13" name="工作开销" >
+ <account type="13" name="工作失误赔偿" />
+ <account type="13" name="其他" />
+ </account>
+ <account type="13" name="休闲娱乐" >
+ <account type="13" name="书籍报纸杂志" />
+ <account type="13" name="娱乐" />
+ <account type="13" name="租碟、看电影" />
+ <account type="13" name="嗜好" />
+ <account type="13" name="体育活动" />
+ <account type="13" name="体育用品" />
+ <account type="13" name="CD磁带" />
+ <account type="13" name="剧院、音乐厅等" />
+ <account type="13" name="玩具、游戏等" />
+ </account>
+ <account type="13" name="法务支出" />
+ <account type="13" name="贷款" >
+ <account type="13" name="贷款利息" />
+ </account>
+ <account type="13" name="自行车" >
+ <account type="13" name="购置费用" />
+ <account type="13" name="维护费用" />
+ </account>
+ <account type="13" name="交通费用" >
+ <account type="13" name="计程车" />
+ <account type="13" name="公共交通" />
+ </account>
+ <account type="13" name="其他支出" >
+ <account type="13" name="未知" />
+ </account>
+ <account type="13" name="个人看护" />
+ <account type="13" name="饲养宠物" >
+ <account type="13" name="食物" />
+ <account type="13" name="各种用品" />
+ <account type="13" name="兽医账单" />
+ <account type="13" name="合法饲养手续" />
+ </account>
+ <account type="13" name="疗养" />
+ <account type="13" name="退休账户" >
+ <account type="13" name="养老保险" />
+ </account>
+ <account type="13" name="税" >
+ <account type="13" name="个人所得税" />
+ </account>
+ </account>
+ <account type="12" name="" >
+ <account type="12" name="赡养费" />
+ <account type="12" name="奖金" />
+ <account type="12" name="红利" />
+ <account type="12" name="独生子女费" />
+ <account type="12" name="投资收入" >
+ <account type="12" name="股票分红" />
+ </account>
+ <account type="12" name="工资" >
+ <account type="12" name="工资" />
+ <account type="12" name="奖金" />
+ <account type="12" name="加班费" />
+ </account>
+ <account type="12" name="礼金" />
+ <account type="12" name="银行" >
+ <account type="12" name="银行利息" />
+ </account>
+ <account type="12" name="投资收入" >
+ <account type="12" name="期权" />
+ <account type="12" name="红利" />
+ <account type="12" name="外汇" />
+ <account type="12" name="利息" />
+ </account>
+ <account type="12" name="退休金" />
+ <account type="12" name="其他收入" >
+ <account type="12" name="助学贷款" />
+ <account type="12" name="收到的贷款本金" />
+ <account type="12" name="彩票、抽奖" />
+ <account type="12" name="退税" />
+ <account type="12" name="离职补偿金" />
+ </account>
+ <account type="12" name="退休计划收入" >
+ <account type="12" name="养老保险" />
+ </account>
+ <account type="12" name="社保收入" >
+ <account type="12" name="养老保险" />
+ <account type="12" name="公积金" />
+ <account type="12" name="医疗保险" />
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/eduloan.kmt b/kmymoney2/templates/zh_CN/eduloan.kmt
new file mode 100644
index 0000000..9990ca8
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/eduloan.kmt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_eduloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Education Loan</title>
+ <shortdesc>Accounts for school loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have an educational loan (education loan, education loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="兴趣">
+ <account type="13" name="教育贷款利息"/>
+ </account>
+ </account>
+ <account type="10" name="">
+ <account type="10" name="贷款">
+ <account type="10" name="教育贷款"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/fixedassets.kmt b/kmymoney2/templates/zh_CN/fixedassets.kmt
new file mode 100644
index 0000000..1e9a593
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/fixedassets.kmt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_fixedassets.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Fixed Assets</title>
+ <shortdesc>Accounts for tracking large fixed assets</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have large fixed assets (house, vehicle, vacation home, other assets).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="9" name="固定资产">
+ <account type="9" name="汽车"/>
+ <account type="9" name="其他资产"/>
+ <account type="9" name="房子"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/full.kmt b/kmymoney2/templates/zh_CN/full.kmt
new file mode 100644
index 0000000..f8e5da5
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/full.kmt
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_full.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Full Chart</title>
+ <shortdesc>Full chart of accounts contains all default accounts.</shortdesc>
+ <longdesc></longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="利息收入">
+ <account type="12" name="储蓄存款利息所得"/>
+ <account type="12" name="货币市场利率"/>
+ <account type="12" name="支票利息"/>
+ <account type="12" name="光盘兴趣"/>
+ <account type="12" name="其他利息"/>
+ <account type="12" name="债券利率"/>
+ </account>
+ <account type="12" name="其他收入"/>
+ <account type="12" name="收到的礼物"/>
+ <account type="12" name="股利收入"/>
+ <account type="12" name="薪金(配偶) "/>
+ <account type="12" name="薪金"/>
+ <account type="12" name="奖金"/>
+ </account>
+ <account type="10" name="">
+ <account type="4" name="信用额度"/>
+ <account type="10" name="贷款">
+ <account type="10" name="汽车贷款"/>
+ <account type="10" name="按揭贷款"/>
+ <account type="10" name="其他贷款"/>
+ <account type="10" name="教育贷款"/>
+ </account>
+ <account type="4" name="信用卡"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="佣金"/>
+ <account type="13" name="衣服"/>
+ <account type="13" name="调整"/>
+ <account type="13" name="教育"/>
+ <account type="13" name="用餐"/>
+ <account type="13" name="供应品"/>
+ <account type="13" name="汽车">
+ <account type="13" name="维修和保养"/>
+ <account type="13" name="停车"/>
+ <account type="13" name="燃气"/>
+ <account type="13" name="收费"/>
+ </account>
+ <account type="13" name="娱乐">
+ <account type="13" name="Music/Movies"/>
+ <account type="13" name="娱乐"/>
+ <account type="13" name="旅行"/>
+ </account>
+ <account type="13" name="电报"/>
+ <account type="13" name="电脑"/>
+ <account type="13" name="育儿"/>
+ <account type="13" name="Laundry/Dry Cleaning"/>
+ <account type="13" name="银行服务收费"/>
+ <account type="13" name="税收">
+ <account type="13" name="State/Province"/>
+ <account type="13" name="房地产税"/>
+ <account type="13" name="其它税"/>
+ <account type="13" name="社会保险"/>
+ <account type="13" name="联邦"/>
+ <account type="13" name="医保"/>
+ </account>
+ <account type="13" name="保险">
+ <account type="13" name="家庭保险"/>
+ <account type="13" name="人寿保险"/>
+ <account type="13" name="汽车保险"/>
+ <account type="13" name="健康保险"/>
+ <account type="13" name="出租保险"/>
+ </account>
+ <account type="13" name="慈善"/>
+ <account type="13" name="家庭修理"/>
+ <account type="13" name="杂货"/>
+ <account type="13" name="在线服务"/>
+ <account type="13" name="租金"/>
+ <account type="13" name="税收(配偶) ">
+ <account type="13" name="社会保险"/>
+ <account type="13" name="其它税"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="医保"/>
+ <account type="13" name="联邦"/>
+ </account>
+ <account type="13" name="兴趣">
+ <account type="13" name="贷款利息"/>
+ <account type="13" name="其他利息"/>
+ <account type="13" name="教育贷款利息"/>
+ <account type="13" name="汽车贷款利息"/>
+ </account>
+ <account type="13" name="杂项"/>
+ <account type="13" name="订阅杂志"/>
+ <account type="13" name="公共交通"/>
+ <account type="13" name="医疗费用"/>
+ <account type="13" name="爱好"/>
+ <account type="13" name="礼品"/>
+ <account type="13" name="书籍"/>
+ <account type="13" name="水电费">
+ <account type="13" name="水"/>
+ <account type="13" name="燃气"/>
+ <account type="13" name="垃圾收集"/>
+ <account type="13" name="电"/>
+ </account>
+ <account type="13" name="电话"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="固定资产">
+ <account type="9" name="房子"/>
+ <account type="9" name="其他资产"/>
+ <account type="9" name="汽车"/>
+ </account>
+ <account type="9" name="流动资产">
+ <account type="1" name="银行CD"/>
+ <account type="1" name="货币市场"/>
+ <account type="3" name="现金的钱包"/>
+ <account type="1" name="储蓄帐户"/>
+ <account type="1" name="支票帐户"/>
+ </account>
+ <account type="9" name="投资">
+ <account type="7" name="退休"/>
+ <account type="7" name="经纪帐户"/>
+ <account type="7" name="配偶退休"/>
+ </account>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="期初余额"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/homeloan.kmt b/kmymoney2/templates/zh_CN/homeloan.kmt
new file mode 100644
index 0000000..1e0374a
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/homeloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_homeloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Home Mortgage Loan</title>
+ <shortdesc>Accounts for home loan and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a home loan (mortgage loan, mortgage interest).</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="10" name="按揭贷款"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="兴趣">
+ <account type="13" name="贷款利息"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/homeown.kmt b/kmymoney2/templates/zh_CN/homeown.kmt
new file mode 100644
index 0000000..966cceb
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/homeown.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_homeown.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Homeowner Expenses</title>
+ <shortdesc>Expenses associated with owning a home</shortdesc>
+ <longdesc>You would want to select this set of accounts if you own a home. This set provides a group of accounts to track home expenses (insurance, taxes, home repair).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="保险">
+ <account type="13" name="家庭保险"/>
+ </account>
+ <account type="13" name="税收">
+ <account type="13" name="房地产税"/>
+ </account>
+ <account type="13" name="家庭修理"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/otherloan.kmt b/kmymoney2/templates/zh_CN/otherloan.kmt
new file mode 100644
index 0000000..4514ac8
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/otherloan.kmt
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_otherloan.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Other Loans</title>
+ <shortdesc>Accounts for tracking other loans and associated interest</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have something other than a home loan (other loan, other loan interest).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="兴趣">
+ <account type="13" name="其他利息"/>
+ </account>
+ </account>
+ <account type="10" name=""/>
+ <account type="10" name="">
+ <account type="10" name="其他贷款"/>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/renter.kmt b/kmymoney2/templates/zh_CN/renter.kmt
new file mode 100644
index 0000000..9d079dd
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/renter.kmt
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_renter.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Renter Expenses</title>
+ <shortdesc>Expenses associated with renting a home</shortdesc>
+ <longdesc>You would want to select this set of accounts if you rent a home or apartment (rent, renter's insurance).</longdesc>
+ <accounts>
+ <account type="13" name="">
+ <account type="13" name="租金"/>
+ <account type="13" name="保险">
+ <account type="13" name="出租保险"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/retiremt.kmt b/kmymoney2/templates/zh_CN/retiremt.kmt
new file mode 100644
index 0000000..f3e3251
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/retiremt.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_retiremt.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Retirement Accounts</title>
+ <shortdesc>Retirement account with related investment subaccounts</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have retirement accounts (stock, bond, mutual fund, index fund).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="退休"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/spouseinc.kmt b/kmymoney2/templates/zh_CN/spouseinc.kmt
new file mode 100644
index 0000000..155eabd
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/spouseinc.kmt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_spouseinc.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Spouse Income</title>
+ <shortdesc>Accounts for tracking spouse's income separately</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have a working spouse (salary (spouse), taxes (spouse)).</longdesc>
+ <accounts>
+ <account type="12" name="">
+ <account type="12" name="薪金(配偶) "/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="税收(配偶) ">
+ <account type="13" name="社会保险"/>
+ <account type="13" name="医保"/>
+ <account type="13" name="State/Province"/>
+ <account type="13" name="联邦"/>
+ <account type="13" name="其它税"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_CN/spouseretire.kmt b/kmymoney2/templates/zh_CN/spouseretire.kmt
new file mode 100644
index 0000000..fbaa2a6
--- /dev/null
+++ b/kmymoney2/templates/zh_CN/spouseretire.kmt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_CN/acctchrt_spouseretire.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>Spouse Retirement Accounts</title>
+ <shortdesc>Retirement account with related investment accounts for spouse</shortdesc>
+ <longdesc>You would want to select this set of accounts if you have investments in a spouse's name (stock, bond, mutual fund, index fund, interest, dividend).</longdesc>
+ <accounts>
+ <account type="9" name="">
+ <account type="7" name="配偶退休"/>
+ </account>
+ <account type="9" name=""/>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_HK/Makefile.am b/kmymoney2/templates/zh_HK/Makefile.am
new file mode 100644
index 0000000..9af54fa
--- /dev/null
+++ b/kmymoney2/templates/zh_HK/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/zh_HK
+
+template_DATA = business.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/zh_HK/business.kmt b/kmymoney2/templates/zh_HK/business.kmt
new file mode 100644
index 0000000..fe02f1b
--- /dev/null
+++ b/kmymoney2/templates/zh_HK/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_HK/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>商業帳户</title>
+ <shortdesc>Full chart of accounts for a business.</shortdesc>
+ <longdesc>Users running a business want to select this instead of other choices. This includes all the accounts you need to run a most businesses, including Payables, Receivables, Income, and Expenses.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="信用卡"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="留存收益"/>
+ <account type="16" name="期初餘額"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="設備租賃"/>
+ <account type="13" name="雜項"/>
+ <account type="13" name="修理">
+ <account type="13" name="設備維修"/>
+ <account type="13" name="建築修復"/>
+ <account type="13" name="電腦維修"/>
+ <account type="13" name="清潔衛生費"/>
+ </account>
+ <account type="13" name="郵資及運送"/>
+ <account type="13" name="教育"/>
+ <account type="13" name="折舊"/>
+ <account type="13" name="辦公用品"/>
+ <account type="13" name="專業費用">
+ <account type="13" name="律師費"/>
+ <account type="13" name="會計"/>
+ </account>
+ <account type="13" name="印刷和復印"/>
+ <account type="13" name="用餐"/>
+ <account type="13" name="應得物和捐款"/>
+ <account type="13" name="執照和許可證"/>
+ <account type="13" name="現金折扣"/>
+ <account type="13" name="薪金支出"/>
+ <account type="13" name="境外服務"/>
+ <account type="13" name="調整"/>
+ <account type="13" name="旅行和娱樂">
+ <account type="13" name="用餐"/>
+ <account type="13" name="旅行"/>
+ <account type="13" name="娱樂"/>
+ </account>
+ <account type="13" name="慈善"/>
+ <account type="13" name="汽車">
+ <account type="13" name="維修和保養"/>
+ <account type="13" name="燃氣"/>
+ <account type="13" name="停車"/>
+ <account type="13" name="收費"/>
+ </account>
+ <account type="13" name="租金"/>
+ <account type="13" name="水電費">
+ <account type="13" name="燃氣"/>
+ <account type="13" name="垃圾收集"/>
+ <account type="13" name="因特網"/>
+ <account type="13" name="手機"/>
+ <account type="13" name="電報"/>
+ <account type="13" name="電"/>
+ <account type="13" name="水"/>
+ <account type="13" name="電話"/>
+ </account>
+ <account type="13" name="保險">
+ <account type="13" name="殘疾保險金"/>
+ <account type="13" name="工作者Comp"/>
+ <account type="13" name="責任保險"/>
+ </account>
+ <account type="13" name="銀行服務收費"/>
+ <account type="13" name="税收">
+ <account type="13" name="聯邦"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="財産"/>
+ <account type="13" name="本地"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="其它税"/>
+ <account type="13" name="州/省"/>
+ <account type="13" name="FUTA"/>
+ </account>
+ <account type="13" name="書籍"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="利息收入"/>
+ <account type="12" name="銷售"/>
+ <account type="12" name="其他收入"/>
+ <account type="12" name="報銷的費用"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流動資産">
+ <account type="1" name="儲蓄帳戶"/>
+ <account type="3" name="零用金"/>
+ <account type="1" name="支票帳戶"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/templates/zh_TW/Makefile.am b/kmymoney2/templates/zh_TW/Makefile.am
new file mode 100644
index 0000000..a03c3b1
--- /dev/null
+++ b/kmymoney2/templates/zh_TW/Makefile.am
@@ -0,0 +1,5 @@
+templatedir=$(kde_datadir)/kmymoney2/templates/zh_TW
+
+template_DATA = business.kmt
+
+EXTRA_DIST = $(template_DATA)
diff --git a/kmymoney2/templates/zh_TW/business.kmt b/kmymoney2/templates/zh_TW/business.kmt
new file mode 100644
index 0000000..3bdadb6
--- /dev/null
+++ b/kmymoney2/templates/zh_TW/business.kmt
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Converted using xea2kmt by Thomas Baumgart from GnuCash sources
+
+ accounts/zh_TW/acctchrt_business.gnucash-xea
+
+ Please check the source file for possible copyright
+ and licence information.
+-->
+<!DOCTYPE KMYMONEY-TEMPLATE>
+<kmymoney-account-template>
+ <title>商業帳户</title>
+ <shortdesc>Full chart of accounts for a business.</shortdesc>
+ <longdesc>Users running a business want to select this instead of other choices. This includes all the accounts you need to run a most businesses, including Payables, Receivables, Income, and Expenses.</longdesc>
+ <accounts>
+ <account type="10" name="">
+ <account type="4" name="信用卡"/>
+ </account>
+ <account type="16" name="">
+ <account type="16" name="留存收益"/>
+ <account type="16" name="期初餘額"/>
+ </account>
+ <account type="13" name="">
+ <account type="13" name="設備租賃"/>
+ <account type="13" name="雜項"/>
+ <account type="13" name="修理">
+ <account type="13" name="設備維修"/>
+ <account type="13" name="建築修復"/>
+ <account type="13" name="電腦維修"/>
+ <account type="13" name="清潔衛生費"/>
+ </account>
+ <account type="13" name="郵資及運送"/>
+ <account type="13" name="教育"/>
+ <account type="13" name="折舊"/>
+ <account type="13" name="辦公用品"/>
+ <account type="13" name="專業費用">
+ <account type="13" name="律師費"/>
+ <account type="13" name="會計"/>
+ </account>
+ <account type="13" name="印刷和復印"/>
+ <account type="13" name="用餐"/>
+ <account type="13" name="應得物和捐款"/>
+ <account type="13" name="執照和許可證"/>
+ <account type="13" name="現金折扣"/>
+ <account type="13" name="薪金支出"/>
+ <account type="13" name="境外服務"/>
+ <account type="13" name="調整"/>
+ <account type="13" name="旅行和娱樂">
+ <account type="13" name="用餐"/>
+ <account type="13" name="旅行"/>
+ <account type="13" name="娱樂"/>
+ </account>
+ <account type="13" name="慈善"/>
+ <account type="13" name="汽車">
+ <account type="13" name="維修和保養"/>
+ <account type="13" name="燃氣"/>
+ <account type="13" name="停車"/>
+ <account type="13" name="收費"/>
+ </account>
+ <account type="13" name="租金"/>
+ <account type="13" name="水電費">
+ <account type="13" name="燃氣"/>
+ <account type="13" name="垃圾收集"/>
+ <account type="13" name="因特網"/>
+ <account type="13" name="手機"/>
+ <account type="13" name="電報"/>
+ <account type="13" name="電"/>
+ <account type="13" name="水"/>
+ <account type="13" name="電話"/>
+ </account>
+ <account type="13" name="保險">
+ <account type="13" name="殘疾保險金"/>
+ <account type="13" name="工作者Comp"/>
+ <account type="13" name="責任保險"/>
+ </account>
+ <account type="13" name="銀行服務收費"/>
+ <account type="13" name="税收">
+ <account type="13" name="聯邦"/>
+ <account type="13" name="FICA"/>
+ <account type="13" name="財産"/>
+ <account type="13" name="本地"/>
+ <account type="13" name="Emp-FICA"/>
+ <account type="13" name="其它税"/>
+ <account type="13" name="州/省"/>
+ <account type="13" name="FUTA"/>
+ </account>
+ <account type="13" name="書籍"/>
+ </account>
+ <account type="12" name="">
+ <account type="12" name="利息收入"/>
+ <account type="12" name="銷售"/>
+ <account type="12" name="其他收入"/>
+ <account type="12" name="報銷的費用"/>
+ </account>
+ <account type="9" name="">
+ <account type="9" name="流動資産">
+ <account type="1" name="儲蓄帳戶"/>
+ <account type="3" name="零用金"/>
+ <account type="1" name="支票帳戶"/>
+ </account>
+ </account>
+ </accounts>
+</kmymoney-account-template>
diff --git a/kmymoney2/tips b/kmymoney2/tips
new file mode 100644
index 0000000..52fc428
--- /dev/null
+++ b/kmymoney2/tips
@@ -0,0 +1,131 @@
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can change the sort order of ledger entries by
+right-clicking the header of the ledger view?
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can easily move to the other side of a transfer transaction
+by opening the context menu with the right mouse button and selecting one of the
+'Goto' functions?
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can start editing a transaction by double-clicking on the
+transaction in the register?
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can show more details of the selected transaction in the
+register by selecting the 'ledger lens' feature in the settings dialog?
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that transactions with no category assigned or split
+transactions with unassigned values are marked with an exclamation mark
+on a yellow triangle in the register?
+</html>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can show all details of the transactions in the register
+by typing &lt;Ctrl-T&gt; or selecting the 'Settings/Show Transaction Detail'
+menu entry? You can turn this feature off the same way.
+</html>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...that you can switch between a listing of all accounts or
+an icon view of all asset and liability accounts with the tabs
+in the accounts view?
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...that the KMyMoney development team wishes you a nice day?
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...you can use your own external filter program to convert any
+import format to QIF on the fly? See the QIF profile editor for
+more details.
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can create a scheduled transaction from an existing
+one by selecting the context menu on a transaction in the ledger
+or the "More..."-menu in the transaction form?
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can switch to the payee of a transaction
+by selecting the context menu on a transaction in the ledger
+or in the transaction menu?
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...that you can modify the colors and fonts used for the ledgers
+via <i>Configure/Register/...</i>?
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...that you can hide transactions prior to a specific date?
+The date can be modified via <i>Configure/Register/Filter</i>.
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...that you can customize the "Home-Page"
+via <i>Configure/Home</i>?
+</html>
+</tip>
+
+<tip category="KMyMoney|Ledger">
+<html>
+<p>...that you can enter new transactions even while reconciling
+an account? You can also make the transaction form visible.
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>...that you can actively support the KMyMoney development team in
+cases that heavily depend on your data? You can save your data in an
+anonymized way for this support.<p>
+Just open your data file and immediately
+select <b>File/Save as...</b>. In the <b>Save As...</b> dialog
+select the filter <b>Anonymous Files</b> and make sure your file gets
+the extensions <b>.anon.xml</b>. <p>
+To verify, how the data looks like you are about to send away, you can open
+this file in KMyMoney and see how the developers see your data.
+</html>
+</tip>
+
+<tip category="KMyMoney|General">
+<html>
+<p>... that you can import your bank statements even without a network
+connection? Just select the file (OFX or QIF) from the File->Import menu.</p>
+<p>Provided by Jose Jorge</p>
+</html>
+</tip>
+
diff --git a/kmymoney2/views/Makefile.am b/kmymoney2/views/Makefile.am
new file mode 100644
index 0000000..693d075
--- /dev/null
+++ b/kmymoney2/views/Makefile.am
@@ -0,0 +1,25 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = -I$(top_srcdir) $(all_includes) -I$(top_srcdir)/libkdchart
+
+noinst_LIBRARIES = libviews.a
+libviews_a_METASOURCES = AUTO
+
+libviews_a_SOURCES = kreportsview.cpp kmymoneytransaction.cpp kgloballedgerview.cpp kmymoneyfile.cpp kinvestmentlistitem.cpp kinvestmentviewdecl.ui kinvestmentview.cpp kscheduledlistitem.cpp kscheduledviewdecl.ui kscheduledview.cpp kpayeesview.cpp kpayeesviewdecl.ui khomeview.cpp kcategoriesviewdecl.ui kcategoriesview.cpp kmymoneyview.cpp kaccountsviewdecl.ui kaccountsview.cpp kinstitutionsviewdecl.ui kinstitutionsview.cpp kbudgetview.cpp kbudgetviewdecl.ui kforecastview.cpp kforecastviewdecl.ui
+
+# oldviews
+# kledgerview.cpp kledgerviewinvestments.cpp kledgerviewliability.cpp kledgerviewloan.cpp kledgerviewcash.cpp kledgerviewasset.cpp kledgerviewcreditcard.cpp kledgerviewsavings.cpp kledgerviewcheckings.cpp
+
+DISTCLEANFILES= kaccountsviewdecl.cpp kcategoriesviewdecl.cpp kinvestmentviewdecl.cpp kpayeesviewdecl.cpp kscheduledviewdecl.cpp kaccountsviewdecl.h kcategoriesviewdecl.h kinvestmentviewdecl.h kpayeesviewdecl.h kscheduledviewdecl.h kinstitutionsviewdecl.cpp kinstitutionsviewdecl.h kbudgetviewdecl.cpp kbudgetviewdecl.h kforecastviewdecl.cpp kforecastviewdecl.h
+
+EXTRA_DIST = kaccountsviewdecl.ui kcategoriesviewdecl.ui kinvestmentviewdecl.ui kpayeesviewdecl.ui kscheduledviewdecl.ui kinstitutionsviewdecl.ui kbudgetviewdecl.ui kforecastviewdecl.ui
+
+instdir=$(includedir)/kmymoney
+inst_HEADERS = kmymoneyview.h
+
+noinst_HEADERS = kaccountsview.h kcategoriesview.h kgloballedgerview.h khomeview.h kinvestmentlistitem.h kinvestmentview.h kmymoneyfile.h kmymoneytransaction.h kpayeesview.h kreportsview.h kscheduledlistitem.h kscheduledview.h kinstitutionsview.h kbudgetview.h kforecastview.h
+
+# old noinst_HEADERS
+# kledgerviewasset.h kledgerviewcash.h kledgerviewcheckings.h kledgerviewcreditcard.h kledgerviewliability.h kledgerviewloan.h kledgerviewsavings.h kledgerview.h kledgerviewinvestments.h
+
+messages: rc.cpp
diff --git a/kmymoney2/views/kaccountsview.cpp b/kmymoney2/views/kaccountsview.cpp
new file mode 100644
index 0000000..b0800cd
--- /dev/null
+++ b/kmymoney2/views/kaccountsview.cpp
@@ -0,0 +1,625 @@
+/***************************************************************************
+ kaccountsview.cpp
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qtabwidget.h>
+#include <qpixmap.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kiconview.h>
+#include <kguiitem.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include "kaccountsview.h"
+#include "kmymoneyview.h"
+#include "../widgets/klistviewsearchline.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../kmymoney2.h"
+
+
+KMyMoneyAccountIconItem::KMyMoneyAccountIconItem(QIconView *parent, const MyMoneyAccount& account) :
+ KIconViewItem(parent, account.name()),
+ m_account(account),
+ m_reconcileFlag(false)
+{
+ updateAccount(account);
+}
+
+KMyMoneyAccountIconItem::~KMyMoneyAccountIconItem()
+{
+}
+
+void KMyMoneyAccountIconItem::setReconciliation(bool on)
+{
+ if(m_reconcileFlag == on)
+ return;
+ m_reconcileFlag = on;
+ updateAccount(m_account);
+}
+
+void KMyMoneyAccountIconItem::updateAccount(const MyMoneyAccount& account)
+{
+ setPixmap(account.accountPixmap(m_reconcileFlag));
+}
+
+KAccountsView::KAccountsView(QWidget *parent, const char *name) :
+ KAccountsViewDecl(parent,name),
+ m_assetItem(0),
+ m_liabilityItem(0)
+{
+ // create the searchline widget
+ // and insert it into the existing layout
+ m_searchWidget = new KListViewSearchLineWidget(m_accountTree, m_accountTree->parentWidget());
+ QVBoxLayout* layout = dynamic_cast<QVBoxLayout*>(m_accountTree->parentWidget()->layout());
+ if(layout) {
+ layout->insertWidget(0, m_searchWidget);
+ }
+
+ // setup icons for collapse and expand button
+ KIconLoader *ic = KGlobal::iconLoader();
+ KGuiItem collapseGuiItem("",
+ QIconSet(ic->loadIcon("viewmag-", KIcon::Small, KIcon::SizeSmall)),
+ QString(),
+ QString());
+ KGuiItem expandGuiItem("",
+ QIconSet(ic->loadIcon("viewmag+", KIcon::Small, KIcon::SizeSmall)),
+ QString(),
+ QString());
+ m_collapseButton->setGuiItem(collapseGuiItem);
+ m_expandButton->setGuiItem(expandGuiItem);
+
+ for(int i=0; i < MaxViewTabs; ++i)
+ m_needReload[i] = false;
+
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ m_tab->setCurrentPage(config->readNumEntry("KAccountsView_LastType", 0));
+
+ connect(m_tab, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotTabChanged(QWidget*)));
+
+ connect(m_accountTree, SIGNAL(selectObject(const MyMoneyObject&)), this, SIGNAL(selectObject(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(openContextMenu(const MyMoneyObject&)), this, SIGNAL(openContextMenu(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(valueChanged(void)), this, SLOT(slotUpdateNetWorth(void)));
+ connect(m_accountTree, SIGNAL(openObject(const MyMoneyObject&)), this, SIGNAL(openObject(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), this, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)));
+
+ connect(m_accountIcons, SIGNAL(selectionChanged(QIconViewItem*)), this, SLOT(slotSelectIcon(QIconViewItem*)));
+ connect(m_accountIcons, SIGNAL(rightButtonClicked(QIconViewItem*, const QPoint&)), this, SLOT(slotOpenContext(QIconViewItem*)));
+ connect(m_accountIcons, SIGNAL(executed(QIconViewItem*)), this, SLOT(slotOpenObject(QIconViewItem*)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadAccounts()));
+ connect(m_collapseButton, SIGNAL(clicked()), this, SLOT(slotExpandCollapse()));
+ connect(m_expandButton, SIGNAL(clicked()), this, SLOT(slotExpandCollapse()));
+}
+
+KAccountsView::~KAccountsView()
+{
+}
+
+void KAccountsView::slotExpandCollapse(void)
+{
+ if(sender()) {
+ KMyMoneyGlobalSettings::setShowAccountsExpanded(sender() == m_expandButton);
+ }
+}
+
+void KAccountsView::slotLoadAccounts(void)
+{
+ m_needReload[ListView] = true;
+ m_needReload[IconView] = true;
+ if(isVisible())
+ slotTabChanged(m_tab->currentPage());
+}
+
+void KAccountsView::slotTabChanged(QWidget* _tab)
+{
+ AccountsViewTab tab = static_cast<AccountsViewTab>(m_tab->indexOf(_tab));
+
+ // remember this setting for startup
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("KAccountsView_LastType", tab);
+
+ loadAccounts(tab);
+
+ switch(tab) {
+ case ListView:
+ // update the hint if categories are hidden
+ m_hiddenCategories->setShown(m_haveUnusedCategories);
+ break;
+
+ case IconView:
+ m_hiddenCategories->hide();
+ break;
+
+ default:
+ break;
+ }
+
+ KMyMoneyAccountTreeBaseItem* treeItem = m_accountTree->selectedItem();
+ KMyMoneyAccountIconItem* iconItem = selectedIcon();
+
+ emit selectObject(MyMoneyAccount());
+ switch(static_cast<AccountsViewTab>(m_tab->indexOf(m_tab->currentPage()))) {
+ case ListView:
+ // if we have a selected account, let the application know about it
+ if(treeItem) {
+ emit selectObject(treeItem->itemObject());
+ }
+ break;
+
+ case IconView:
+ if(iconItem) {
+ emit selectObject(iconItem->itemObject());
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void KAccountsView::show(void)
+{
+ // don't forget base class implementation
+ KAccountsViewDecl::show();
+ slotTabChanged(m_tab->currentPage());
+}
+
+void KAccountsView::polish(void)
+{
+ // don't forget base class implementation
+ KAccountsViewDecl::polish();
+ m_accountTree->setResizeMode(QListView::LastColumn);
+ m_accountTree->restoreLayout("Account View Settings");
+}
+
+void KAccountsView::loadAccounts(AccountsViewTab tab)
+{
+ if(m_needReload[tab]) {
+ switch(tab) {
+ case ListView:
+ loadListView();
+ break;
+ case IconView:
+ loadIconView();
+ break;
+ default:
+ break;
+ }
+ m_needReload[tab] = false;
+ }
+}
+
+void KAccountsView::loadIconView(void)
+{
+ ::timetrace("start load accounts icon view");
+
+ // remember the positions of the icons
+ QMap<QString, QPoint> posMap;
+ KMyMoneyAccountIconItem* p = dynamic_cast<KMyMoneyAccountIconItem*>(m_accountIcons->firstItem());
+ for(;p; p = dynamic_cast<KMyMoneyAccountIconItem*>(p->nextItem()))
+ posMap[p->itemObject().id()] = p->pos();
+
+ // turn off updates to avoid flickering during reload
+ m_accountIcons->setAutoArrange(true);
+
+ // clear the current contents and recreate it
+ m_accountIcons->clear();
+ QMap<QString, MyMoneyAccount> accountMap;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // get account list and sort by name
+ QValueList<MyMoneyAccount> alist;
+ file->accountList(alist);
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ for(it_a = alist.begin(); it_a != alist.end(); ++it_a) {
+ accountMap[QString("%1-%2").arg((*it_a).name()).arg((*it_a).id())] = *it_a;
+ }
+
+ bool showClosedAccounts = kmymoney2->toggleAction("view_show_all_accounts")->isChecked()
+ || !KMyMoneyGlobalSettings::hideClosedAccounts();
+ bool existNewIcons = false;
+
+ // parse list and add all asset and liability accounts
+ QMap<QString, MyMoneyAccount>::const_iterator it;
+ for(it = accountMap.begin(); it != accountMap.end(); ++it) {
+ QPoint loc;
+ if((*it).isClosed() && !showClosedAccounts)
+ continue;
+ const QString& pos = (*it).value("kmm-iconpos");
+ KMyMoneyAccountIconItem* item;
+ switch((*it).accountGroup()) {
+ case MyMoneyAccount::Equity:
+ if(!KMyMoneyGlobalSettings::expertMode())
+ continue;
+ // tricky fall through here
+
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ // don't show stock accounts
+ if((*it).isInvest())
+ continue;
+
+ // if we have a position stored with the object and no other
+ // idea of it's current position, then take the one
+ // stored inside the object. Also, turn off auto arrangement
+ if(!pos.isEmpty() && posMap[(*it).id()] == QPoint()) {
+ posMap[(*it).id()] = point(pos);
+ }
+
+ loc = posMap[(*it).id()];
+ if(loc == QPoint()) {
+ existNewIcons = true;
+ } else {
+ m_accountIcons->setAutoArrange(false);
+ }
+
+ item = new KMyMoneyAccountIconItem(m_accountIcons, *it);
+ if((*it).id() == m_reconciliationAccount.id())
+ item->setReconciliation(true);
+
+ if(loc != QPoint()) {
+ item->move(loc);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // clear the current contents
+ m_securityMap.clear();
+ m_transactionCountMap.clear();
+
+ if(existNewIcons) {
+ m_accountIcons->arrangeItemsInGrid(true);
+ }
+
+ m_accountIcons->setAutoArrange(false);
+
+ ::timetrace("done load accounts icon view");
+}
+
+void KAccountsView::loadListView(void)
+{
+ QMap<QString, bool> isOpen;
+
+ ::timetrace("start load accounts list view");
+ // remember the id of the current selected item
+ KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
+ QString selectedItemId = (item) ? item->id() : QString();
+
+ // keep a map of all 'expanded' accounts
+ QListViewItemIterator it_lvi(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item && item->isOpen()) {
+ isOpen[item->id()] = true;
+ }
+ ++it_lvi;
+ }
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_accountTree->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_accountTree->setUpdatesEnabled(false);
+
+ // clear the current contents and recreate it
+ m_accountTree->clear();
+ m_securityMap.clear();
+ m_transactionCountMap.clear();
+
+ // make sure, the pointers are not pointing to some deleted object
+ m_assetItem = m_liabilityItem = 0;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneySecurity> slist = file->currencyList();
+ slist += file->securityList();
+ QValueList<MyMoneySecurity>::const_iterator it_s;
+ for(it_s = slist.begin(); it_s != slist.end(); ++it_s) {
+ m_securityMap[(*it_s).id()] = *it_s;
+ }
+ m_transactionCountMap = file->transactionCountMap();
+
+ m_haveUnusedCategories = false;
+
+ // create the items
+ try {
+ const MyMoneySecurity security = file->baseCurrency();
+ m_accountTree->setBaseCurrency(security);
+
+ const MyMoneyAccount& asset = file->asset();
+ m_assetItem = new KMyMoneyAccountTreeItem(m_accountTree, asset, security, i18n("Asset"));
+ loadSubAccounts(m_assetItem, asset.accountList());
+
+ const MyMoneyAccount& liability = file->liability();
+ m_liabilityItem = new KMyMoneyAccountTreeItem(m_accountTree, liability, security, i18n("Liability"));
+ loadSubAccounts(m_liabilityItem, liability.accountList());
+
+ const MyMoneyAccount& income = file->income();
+ KMyMoneyAccountTreeItem *incomeItem = new KMyMoneyAccountTreeItem(m_accountTree, income, security, i18n("Income"));
+ m_haveUnusedCategories |= loadSubAccounts(incomeItem, income.accountList());
+
+ const MyMoneyAccount& expense = file->expense();
+ KMyMoneyAccountTreeItem *expenseItem = new KMyMoneyAccountTreeItem(m_accountTree, expense, security, i18n("Expense"));
+ m_haveUnusedCategories |= loadSubAccounts(expenseItem, expense.accountList());
+
+ if(KMyMoneyGlobalSettings::expertMode()) {
+ const MyMoneyAccount equity = file->equity();
+ KMyMoneyAccountTreeItem *equityItem = new KMyMoneyAccountTreeItem(m_accountTree, equity, security, i18n("Equity"));
+ loadSubAccounts(equityItem, equity.accountList());
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << "Problem in accounts list view: " << e->what();
+ delete e;
+ }
+
+ // scan through the list of accounts and re-expand those that were
+ // expanded and re-select the one that was probably selected before
+ it_lvi = QListViewItemIterator(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item) {
+ if(item->id() == selectedItemId)
+ m_accountTree->setSelected(item, true);
+ if(isOpen.find(item->id()) != isOpen.end())
+ item->setOpen(true);
+ }
+ ++it_lvi;
+ }
+
+ // reposition viewport
+ m_accountTree->setContentsPos(startPoint.x(), startPoint.y());
+
+ m_searchWidget->searchLine()->updateSearch(QString::null);
+
+ // turn updates back on
+ m_accountTree->setUpdatesEnabled(true);
+ m_accountTree->repaintContents();
+
+ // and in case we need to show things expanded, we'll do so
+ if(KMyMoneyGlobalSettings::showAccountsExpanded())
+ m_accountTree->slotExpandAll();
+
+ // clear the current contents
+ m_securityMap.clear();
+ m_transactionCountMap.clear();
+ ::timetrace("done load accounts list view");
+}
+
+bool KAccountsView::loadSubAccounts(KMyMoneyAccountTreeItem* parent, const QStringList& accountList)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ bool unused = false;
+ bool showClosedAccounts = kmymoney2->toggleAction("view_show_all_accounts")->isChecked()
+ || !KMyMoneyGlobalSettings::hideClosedAccounts();
+
+ QStringList::const_iterator it_a;
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ const MyMoneyAccount& acc = file->account(*it_a);
+ QValueList<MyMoneyPrice> prices;
+ MyMoneySecurity security = file->baseCurrency();
+ try {
+ if(acc.isInvest()) {
+ security = m_securityMap[acc.currencyId()];
+ prices += file->price(acc.currencyId(), security.tradingCurrency());
+ if(security.tradingCurrency() != file->baseCurrency().id()) {
+ MyMoneySecurity sec = m_securityMap[security.tradingCurrency()];
+ prices += file->price(sec.id(), file->baseCurrency().id());
+ }
+ } else if(acc.currencyId() != file->baseCurrency().id()) {
+ if(acc.currencyId() != file->baseCurrency().id()) {
+ security = m_securityMap[acc.currencyId()];
+ prices += file->price(acc.currencyId(), file->baseCurrency().id());
+ }
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << __PRETTY_FUNCTION__ << " caught exception while adding " << acc.name() << "[" << acc.id() << "]: " << e->what();
+ delete e;
+ }
+
+ KMyMoneyAccountTreeItem* item = new KMyMoneyAccountTreeItem(parent, acc, prices, security);
+ if(acc.id() == m_reconciliationAccount.id())
+ item->setReconciliation(true);
+
+ unused |= loadSubAccounts(item, acc.accountList());
+
+ // no child accounts and no transactions in this account means 'unused'
+ bool thisUnused = (!item->firstChild()) && (m_transactionCountMap[acc.id()] == 0);
+
+ // In case of a category which is unused and we are requested to suppress
+ // the display of those,
+ if(acc.isIncomeExpense()) {
+ if(KMyMoneyGlobalSettings::hideUnusedCategory() && thisUnused) {
+ unused = true;
+ delete item;
+ }
+ }
+
+ // if the account is closed and we should not show it, we delete the item
+ if(acc.isClosed() && !showClosedAccounts) {
+ delete item;
+ }
+ }
+ return unused;
+}
+
+void KAccountsView::slotReconcileAccount(const MyMoneyAccount& acc, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance)
+{
+ Q_UNUSED(reconciliationDate);
+ Q_UNUSED(endingBalance);
+
+ // scan through the list of accounts and mark all non
+ // expanded and re-select the one that was probably selected before
+ QListViewItemIterator it_lvi(m_accountTree);
+ KMyMoneyAccountTreeItem* item;
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item) {
+ item->setReconciliation(false);
+ }
+ ++it_lvi;
+ }
+
+ // scan trough the icon list and do the same thing
+ KMyMoneyAccountIconItem* icon = dynamic_cast<KMyMoneyAccountIconItem*>(m_accountIcons->firstItem());
+ for(;icon; icon = dynamic_cast<KMyMoneyAccountIconItem*>(icon->nextItem())) {
+ icon->setReconciliation(false);
+ }
+
+ m_reconciliationAccount = acc;
+
+ if(!acc.id().isEmpty()) {
+ // scan through the list of accounts and mark
+ // the one that is currently reconciled
+ it_lvi = QListViewItemIterator(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item && item->itemObject().id() == acc.id()) {
+ item->setReconciliation(true);
+ break;
+ }
+ ++it_lvi;
+ }
+
+ // scan trough the icon list and do the same thing
+ icon = dynamic_cast<KMyMoneyAccountIconItem*>(m_accountIcons->firstItem());
+ for(;icon; icon = dynamic_cast<KMyMoneyAccountIconItem*>(icon->nextItem())) {
+ if(icon->itemObject().id() == acc.id()) {
+ icon->setReconciliation(true);
+ break;
+ }
+ }
+ }
+}
+
+void KAccountsView::slotUpdateNetWorth(void)
+{
+ if(!m_assetItem || !m_liabilityItem)
+ return;
+
+ MyMoneyMoney netWorth = m_assetItem->totalValue() - m_liabilityItem->totalValue();
+
+ QString s(i18n("Net Worth: "));
+
+ // FIXME figure out how to deal with the approximate
+ // if(!(file->totalValueValid(assetAccount.id()) & file->totalValueValid(liabilityAccount.id())))
+ // s += "~ ";
+
+ s.replace(QString(" "), QString("&nbsp;"));
+ if(netWorth.isNegative()) {
+ s += "<b><font color=\"red\">";
+ }
+ const MyMoneySecurity& sec = MyMoneyFile::instance()->baseCurrency();
+ QString v(netWorth.formatMoney(sec));
+ s += v.replace(QString(" "), QString("&nbsp;"));
+ if(netWorth.isNegative()) {
+ s += "</font></b>";
+ }
+
+ m_totalProfitsLabel->setFont(KMyMoneyGlobalSettings::listCellFont());
+ m_totalProfitsLabel->setText(s);
+}
+
+KMyMoneyAccountIconItem* KAccountsView::selectedIcon(void) const
+{
+ return dynamic_cast<KMyMoneyAccountIconItem*>(m_accountIcons->currentItem());
+}
+
+void KAccountsView::slotSelectIcon(QIconViewItem* item)
+{
+ KMyMoneyAccountIconItem* p = dynamic_cast<KMyMoneyAccountIconItem*>(item);
+ if(p)
+ emit selectObject(p->itemObject());
+}
+
+void KAccountsView::slotOpenContext(QIconViewItem* item)
+{
+ KMyMoneyAccountIconItem* p = dynamic_cast<KMyMoneyAccountIconItem*>(item);
+ if(p)
+ emit openContextMenu(p->itemObject());
+}
+
+void KAccountsView::slotOpenObject(QIconViewItem* item)
+{
+ KMyMoneyAccountIconItem* p = dynamic_cast<KMyMoneyAccountIconItem*>(item);
+ if(p)
+ emit openObject(p->itemObject());
+}
+
+QString KAccountsView::point(const QPoint& val) const
+{
+ return QString("%1;%2").arg(val.x()).arg(val.y());
+}
+
+QPoint KAccountsView::point(const QString& val) const
+{
+ QRegExp exp("(\\d+);(\\d+)");
+ int x = 0;
+ int y = 0;
+ if(exp.search(val) != -1) {
+ x = exp.cap(1).toInt();
+ y = exp.cap(2).toInt();
+ }
+ return QPoint(x, y);
+}
+
+void KAccountsView::slotUpdateIconPos(unsigned int action)
+{
+ if(action != KMyMoneyView::preSave)
+ return;
+
+ MyMoneyFileTransaction ft;
+ KMyMoneyAccountIconItem* p = dynamic_cast<KMyMoneyAccountIconItem*>(m_accountIcons->firstItem());
+ for(;p; p = dynamic_cast<KMyMoneyAccountIconItem*>(p->nextItem())) {
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(p->itemObject());
+ if(acc.value("kmm-iconpos") != point(p->pos())) {
+ MyMoneyAccount a(acc);
+ a.setValue("kmm-iconpos", point(p->pos()));
+ try {
+ MyMoneyFile::instance()->modifyAccount(a);
+ } catch(MyMoneyException* e) {
+ kdDebug(2) << "Unable to update icon pos: " << e->what();
+ delete e;
+ }
+ }
+ }
+ ft.commit();
+}
+
+
+#include "kaccountsview.moc"
diff --git a/kmymoney2/views/kaccountsview.h b/kmymoney2/views/kaccountsview.h
new file mode 100644
index 0000000..ed30ac5
--- /dev/null
+++ b/kmymoney2/views/kaccountsview.h
@@ -0,0 +1,209 @@
+/***************************************************************************
+ kaccountssview.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KACCOUNTSSVIEW_H
+#define KACCOUNTSSVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kiconview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/mymoneyutils.h>
+class KListViewSearchLineWidget;
+
+#include "../views/kaccountsviewdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class represents an item in the account icon view. It is used
+ * by the KAccountsView to select between the accounts using icons.
+ */
+class KMyMoneyAccountIconItem : public KIconViewItem
+{
+public:
+ /**
+ * Constructor to be used to construct an account icon object.
+ *
+ * @param parent pointer to the KIconView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KIconView entry is constructed
+ */
+ KMyMoneyAccountIconItem(QIconView *parent, const MyMoneyAccount& account);
+ ~KMyMoneyAccountIconItem();
+
+ /**
+ * This method is loads new information into the item and updates the fields
+ *
+ * @param account the account data for the object to be updated
+ *
+ * @note if account.id() is not equal to the current account id
+ * then this method returns immediately
+ */
+ void updateAccount(const MyMoneyAccount& account);
+
+ const MyMoneyObject& itemObject(void) const { return m_account; };
+
+ void setReconciliation(bool);
+
+protected:
+
+private:
+ MyMoneyAccount m_account;
+ bool m_reconcileFlag;
+};
+
+
+
+
+/**
+ * This class implements the accounts hierarchical and iconic 'view'.
+ */
+class KAccountsView : public KAccountsViewDecl
+{
+ Q_OBJECT
+private:
+
+public:
+ KAccountsView(QWidget *parent=0, const char *name=0);
+ virtual ~KAccountsView();
+
+public slots:
+ void slotLoadAccounts(void);
+
+ /**
+ * Override the base class behaviour to include all updates that
+ * happened in the meantime.
+ */
+ void show(void);
+
+ /**
+ * Override the base class behaviour to restore the layout. Do not
+ * do this in show() because show() itself may change the layout
+ * in undesired ways.
+ */
+ void polish(void);
+
+ /**
+ * update the account objects if their icon position has changed since
+ * the last time.
+ *
+ * @param action must be KMyMoneyView::preSave, otherwise this slot is a NOP.
+ */
+ void slotUpdateIconPos(unsigned int action);
+
+ void slotReconcileAccount(const MyMoneyAccount& acc, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance);
+
+protected:
+ typedef enum {
+ ListView = 0,
+ IconView,
+ // insert new values above this line
+ MaxViewTabs
+ } AccountsViewTab;
+
+ /**
+ * This method loads the accounts for the respective tab.
+ *
+ * @param tab which tab should be loaded
+ */
+ void loadAccounts(AccountsViewTab tab);
+ void loadListView(void);
+ void loadIconView(void);
+
+ bool loadSubAccounts(KMyMoneyAccountTreeItem* parent, const QStringList& accountList);
+
+ /**
+ * This method returns a pointer to the currently selected
+ * account icon or 0 if no icon is selected.
+ */
+ KMyMoneyAccountIconItem* selectedIcon(void) const;
+
+ QPoint point(const QString& str) const;
+ QString point(const QPoint& val) const;
+
+protected slots:
+ void slotUpdateNetWorth(void);
+ void slotTabChanged(QWidget*);
+ void slotSelectIcon(QIconViewItem* item);
+ void slotOpenContext(QIconViewItem* item);
+ void slotOpenObject(QIconViewItem* item);
+ void slotExpandCollapse(void);
+
+signals:
+ /**
+ * This signal serves as proxy for KMyMoneyAccountTree::selectObject()
+ *
+ * @param obj const reference to object
+ */
+ void selectObject(const MyMoneyObject& obj);
+
+ /**
+ * This signal serves as proxy for
+ * KMyMoneyAccountTree::openContextMenu(const MyMoneyObject&)
+ *
+ * @param obj const reference to object
+ */
+ void openContextMenu(const MyMoneyObject& obj);
+
+ /**
+ * This signal will be emitted when the left mouse button is double
+ * clicked (actually the KDE executed setting is used) on an object.
+ *
+ * @param obj const reference to object
+ */
+ void openObject(const MyMoneyObject& obj);
+
+ /**
+ * This signal is emitted, when the user selected to reparent the
+ * account @p acc to be a subordinate account of @p parent.
+ *
+ * @param acc const reference to account to be reparented
+ * @param parent const reference to new parent account
+ */
+ void reparent(const MyMoneyAccount& acc, const MyMoneyAccount& parent);
+
+private:
+ MyMoneyAccount m_reconciliationAccount;
+ QMap<QString, MyMoneySecurity> m_securityMap;
+ QMap<QString, unsigned long> m_transactionCountMap;
+
+ KMyMoneyAccountTreeItem* m_assetItem;
+ KMyMoneyAccountTreeItem* m_liabilityItem;
+
+ /**
+ * Search widget for the list
+ */
+ KListViewSearchLineWidget* m_searchWidget;
+
+ /// set if a view needs to be reloaded during show()
+ bool m_needReload[MaxViewTabs];
+ bool m_haveUnusedCategories;
+};
+
+#endif
diff --git a/kmymoney2/views/kaccountsviewdecl.ui b/kmymoney2/views/kaccountsviewdecl.ui
new file mode 100644
index 0000000..c8bb5ac
--- /dev/null
+++ b/kmymoney2/views/kaccountsviewdecl.ui
@@ -0,0 +1,204 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAccountsViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAccountsViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>697</width>
+ <height>426</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_tab</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>List</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <widget class="KMyMoneyAccountTree">
+ <property name="name">
+ <cstring>m_accountTree</cstring>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_collapseButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Collapse all accounts in the list</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_expandButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Expand all accounts in the list</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>515</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Icons</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIconView">
+ <property name="name">
+ <cstring>m_accountIcons</cstring>
+ </property>
+ <property name="arrangement">
+ <enum>LeftToRight</enum>
+ </property>
+ <property name="maxItemTextLength">
+ <number>30</number>
+ </property>
+ <property name="autoArrange">
+ <bool>true</bool>
+ </property>
+ <property name="wordWrapIconText">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_hiddenCategories</cstring>
+ </property>
+ <property name="text">
+ <string>Note: Unused categories are not shown as selected by settings.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>367</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_totalProfitsLabel</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Total Profits:</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_expandButton</sender>
+ <signal>clicked()</signal>
+ <receiver>m_accountTree</receiver>
+ <slot>slotExpandAll()</slot>
+ </connection>
+ <connection>
+ <sender>m_collapseButton</sender>
+ <signal>clicked()</signal>
+ <receiver>m_accountTree</receiver>
+ <slot>slotCollapseAll()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kbudgetview.cpp b/kmymoney2/views/kbudgetview.cpp
new file mode 100644
index 0000000..a8d5bc1
--- /dev/null
+++ b/kmymoney2/views/kbudgetview.cpp
@@ -0,0 +1,767 @@
+/***************************************************************************
+ kbudgetview.cpp
+ ---------------
+ begin : Thu Jan 10 2006
+ copyright : (C) 2006 by Darren Gould
+ email : darren_gould@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qmultilineedit.h>
+#include <qpixmap.h>
+#include <qtabwidget.h>
+#include <qlistbox.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qtooltip.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kcalendarsystem.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/kmymoneytitlelabel.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kbudgetvalues.h>
+#include "../widgets/kmymoneyaccounttreebudget.h"
+#include "kbudgetview.h"
+#include "../dialogs/knewbudgetdlg.h"
+#include "../kmymoney2.h"
+
+// *** KBudgetListItem Implementation ***
+KBudgetListItem::KBudgetListItem(KListView *parent, const MyMoneyBudget& budget) :
+ KListViewItem(parent),
+ m_budget(budget)
+{
+ setText(0, budget.name());
+ setText(1, QString("%1").arg(budget.budgetStart().year()));
+
+ // allow in column rename
+ setRenameEnabled(0, true);
+}
+
+KBudgetListItem::~KBudgetListItem()
+{
+}
+
+void KBudgetListItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align)
+{
+ p->setFont(KMyMoneyGlobalSettings::listCellFont());
+
+ QColorGroup cg2(cg);
+
+ if (isAlternate())
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+
+ QListViewItem::paintCell(p, cg2, column, width, align);
+}
+
+
+// *** KBudgetView Implementation ***
+const int KBudgetView::m_iBudgetYearsAhead = 5;
+const int KBudgetView::m_iBudgetYearsBack = 3;
+
+KBudgetView::KBudgetView(QWidget *parent, const char *name ) :
+ KBudgetViewDecl(parent,name),
+ m_needReload(false),
+ m_inSelection(false)
+{
+ m_accountTree->setSorting(-1);
+ m_budgetList->setSorting(0);
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem newButtenItem( QString(""),
+ QIconSet(il->loadIcon("file_new", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Creates a new budget"),
+ i18n("Use this to create a new empty budget."));
+ m_newButton->setGuiItem(newButtenItem);
+ QToolTip::add(m_newButton, newButtenItem.toolTip());
+
+ KGuiItem renameButtenItem( QString(""),
+ QIconSet(il->loadIcon("editpaste", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Rename the current selected budget"),
+ i18n("Use this to start renaming the selected budget."));
+ m_renameButton->setGuiItem(renameButtenItem);
+ QToolTip::add(m_renameButton, renameButtenItem.toolTip());
+
+ KGuiItem deleteButtenItem( QString(""),
+ QIconSet(il->loadIcon("editdelete", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Delete the current selected budget"),
+ i18n("Use this to delete the selected budget."));
+ m_deleteButton->setGuiItem(deleteButtenItem);
+ QToolTip::add(m_deleteButton, deleteButtenItem.toolTip());
+
+ KGuiItem updateButtenItem( QString(""),
+ QIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Accepts the entered values and stores the budget"),
+ i18n("Use this to store the modified data."));
+ m_updateButton->setGuiItem(updateButtenItem);
+ QToolTip::add(m_updateButton, updateButtenItem.toolTip());
+
+ KGuiItem resetButtenItem( QString(""),
+ QIconSet(il->loadIcon("undo", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Revert budget to last saved state"),
+ i18n("Use this to discard the modified data."));
+ m_resetButton->setGuiItem(resetButtenItem);
+ QToolTip::add(m_resetButton, resetButtenItem.toolTip());
+
+ connect(m_budgetList, SIGNAL(contextMenu(KListView*, QListViewItem* , const QPoint&)),
+ this, SLOT(slotOpenContextMenu(KListView*, QListViewItem*, const QPoint&)));
+ connect(m_budgetList, SIGNAL(itemRenamed(QListViewItem*,int,const QString&)), this, SLOT(slotRenameBudget(QListViewItem*,int,const QString&)));
+ connect(m_budgetList, SIGNAL(selectionChanged()), this, SLOT(slotSelectBudget()));
+
+ connect(m_cbBudgetSubaccounts, SIGNAL(clicked()), this, SLOT(cb_includesSubaccounts_clicked()));
+
+ connect(m_accountTree, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotSelectAccount(QListViewItem*)));
+ connect(m_accountTree, SIGNAL(valueChanged()), this, SLOT(slotRefreshHideUnusedButton()));
+
+ // connect the buttons to the actions. Make sure the enabled state
+ // of the actions is reflected by the buttons
+ connect(kmymoney2->action("budget_new"), SIGNAL(enabled(bool)), m_newButton, SLOT(setEnabled(bool)));
+ connect(m_renameButton, SIGNAL(clicked()), kmymoney2->action("budget_rename"), SLOT(activate()));
+ connect(kmymoney2->action("budget_rename"), SIGNAL(enabled(bool)), m_renameButton, SLOT(setEnabled(bool)));
+ connect(m_deleteButton, SIGNAL(clicked()), kmymoney2->action("budget_delete"), SLOT(activate()));
+ connect(kmymoney2->action("budget_delete"), SIGNAL(enabled(bool)), m_deleteButton, SLOT(setEnabled(bool)));
+
+ connect(m_budgetValue, SIGNAL(valuesChanged()), this, SLOT(slotBudgetedAmountChanged()));
+
+ connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewBudget()));
+ connect(m_updateButton, SIGNAL(pressed()), this, SLOT(slotUpdateBudget()));
+ connect(m_resetButton, SIGNAL(pressed()), this, SLOT(slotResetBudget()));
+
+ connect(m_hideUnusedButton, SIGNAL(toggled(bool)), this, SLOT(slotHideUnused(bool)));
+
+ // setup initial state
+ m_newButton->setEnabled(kmymoney2->action("budget_new")->isEnabled());
+ m_renameButton->setEnabled(kmymoney2->action("budget_rename")->isEnabled());
+ m_deleteButton->setEnabled(kmymoney2->action("budget_delete")->isEnabled());
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotRefreshView()));
+}
+
+KBudgetView::~KBudgetView()
+{
+}
+
+void KBudgetView::show()
+{
+ QTimer::singleShot(50, this, SLOT(slotRearrange()));
+ QWidget::show();
+ if(m_needReload) {
+ slotRefreshView();
+ }
+}
+
+void KBudgetView::polish()
+{
+ KBudgetViewDecl::polish();
+ m_accountTree->restoreLayout("Budget Account View Settings");
+}
+
+void KBudgetView::slotRearrange(void)
+{
+ resizeEvent(0);
+}
+
+void KBudgetView::resizeEvent(QResizeEvent* ev)
+{
+ // resize the register
+ KBudgetViewDecl::resizeEvent(ev);
+}
+
+void KBudgetView::slotReloadView(void)
+{
+ ::timetrace("Start KBudgetView::slotReloadView");
+ slotRearrange();
+ ::timetrace("Done KBudgetView::slotReloadView");
+}
+
+void KBudgetView::loadBudgets(void)
+{
+ QString id;
+
+ ::timetrace("Start KBudgetView::loadBudgets");
+
+ // remember which item is currently selected
+ id = m_budget.id();
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_budgetList->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_budgetList->setUpdatesEnabled(false);
+
+ // clear the budget list
+ m_budgetList->clear();
+ m_budgetValue->clear();
+
+ // add the correct years to the drop down list
+ QDate date = QDate::currentDate(Qt::LocalTime);
+ int iStartYear = date.year() - m_iBudgetYearsBack;
+
+ m_yearList.clear();
+ for (int i=0; i<m_iBudgetYearsAhead + m_iBudgetYearsBack; i++)
+ m_yearList += QString::number(iStartYear+i);
+
+ KBudgetListItem* currentItem = 0;
+
+ QValueList<MyMoneyBudget> list = MyMoneyFile::instance()->budgetList();
+ QValueList<MyMoneyBudget>::ConstIterator it;
+ for (it = list.begin(); it != list.end(); ++it)
+ {
+ KBudgetListItem* item = new KBudgetListItem(m_budgetList, *it);
+
+ // create a list of unique years
+ if (m_yearList.findIndex(QString::number((*it).budgetStart().year())) == -1)
+ m_yearList += QString::number((*it).budgetStart().year());
+
+ if(item->budget().id() == id) {
+ m_budget = (*it);
+ currentItem = item;
+ item->setSelected(true);
+ }
+ }
+ m_yearList.sort();
+
+ if (currentItem) {
+ m_budgetList->setCurrentItem(currentItem);
+ }
+
+ // reposition viewport
+ m_budgetList->setContentsPos(startPoint.x(), startPoint.y());
+
+ // turn updates back on
+ m_budgetList->setUpdatesEnabled(true);
+ m_budgetList->repaintContents();
+
+ // reset the status of the buttons
+ m_updateButton->setEnabled(false);
+ m_resetButton->setEnabled(false);
+
+ // make sure the world around us knows what we have selected
+ slotSelectBudget();
+
+ ::timetrace("End KBudgetView::loadBudgets");
+}
+
+void KBudgetView::ensureBudgetVisible(const QString& id)
+{
+ for (QListViewItem * item = m_budgetList->firstChild(); item; item = item->itemBelow()) {
+ KBudgetListItem* p = dynamic_cast<KBudgetListItem*>(item);
+ if(p && p->budget().id() == id) {
+ if(p->itemAbove())
+ m_budgetList->ensureItemVisible(p->itemAbove());
+ if(p->itemBelow())
+ m_budgetList->ensureItemVisible(p->itemBelow());
+
+ m_budgetList->setCurrentItem(p); // active item and deselect all others
+ m_budgetList->setSelected(p, true); // and select it
+ m_budgetList->ensureItemVisible(p);
+ break;
+ }
+ }
+}
+
+void KBudgetView::slotRefreshView(void)
+{
+ if(isVisible()) {
+ if(m_inSelection)
+ QTimer::singleShot(0, this, SLOT(slotRefreshView()));
+ else {
+ loadBudgets();
+ m_needReload = false;
+ }
+ } else {
+ m_needReload = true;
+ }
+}
+
+void KBudgetView::loadAccounts(void)
+{
+ QMap<QString, bool> isOpen;
+
+ ::timetrace("start load budget account view");
+
+ // if no budgets are selected, don't load the accounts
+ // and clear out the previously shown list
+ if (m_budget.id().isEmpty()) {
+ m_accountTree->clear();
+ m_budgetValue->clear();
+ m_updateButton->setEnabled(false);
+ m_resetButton->setEnabled(false);
+ ::timetrace("done load budgets view");
+ return;
+ }
+
+ // remember the id of the current selected item
+ KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
+ QString selectedItemId = (item) ? item->id() : QString();
+
+ // keep a map of all 'expanded' accounts
+ QListViewItemIterator it_lvi(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(it_lvi.current());
+ if(item && item->isOpen()) {
+ isOpen[item->id()] = true;
+ }
+ ++it_lvi;
+ }
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_accountTree->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_accountTree->setUpdatesEnabled(false);
+
+ // clear the current contents and recreate it
+ m_accountTree->clear();
+ m_transactionCountMap.clear();
+
+ // make sure, the pointers are not pointing to some deleted object
+ m_incomeItem = m_expenseItem = 0;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ m_transactionCountMap = file->transactionCountMap();
+
+ m_accountTree->setBaseCurrency(file->baseCurrency());
+
+ bool haveUnusedBudgets = false;
+
+ // create the items
+ try {
+ const MyMoneySecurity& security = file->baseCurrency();
+ m_accountTree->setBaseCurrency(security);
+
+ const MyMoneyAccount& income = file->income();
+ QStringList incSubAcctList = income.accountList();
+ m_incomeItem = new KMyMoneyAccountTreeBudgetItem(m_accountTree, income, m_budget, security, i18n("Income"));
+ haveUnusedBudgets |= loadSubAccounts(m_incomeItem, incSubAcctList, m_budget);
+ m_incomeItem->setSelectable(false);
+
+ const MyMoneyAccount& expense = file->expense();
+ QStringList expSubAcctList = expense.accountList();
+ m_expenseItem = new KMyMoneyAccountTreeBudgetItem(m_accountTree, expense, m_budget, security, i18n("Expense"));
+ haveUnusedBudgets |= loadSubAccounts(m_expenseItem, expSubAcctList, m_budget);
+ m_expenseItem->setSelectable(false);
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << "Problem in budgetview: " << e->what();
+ delete e;
+ }
+
+ // scan through the list of accounts and re-expand those that were
+ // expanded and re-select the one that was probably selected before
+ it_lvi = QListViewItemIterator(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(it_lvi.current());
+ if(item) {
+ if(item->id() == selectedItemId)
+ m_accountTree->setSelected(item, true);
+ if(isOpen.find(item->id()) != isOpen.end())
+ item->setOpen(true);
+ }
+ ++it_lvi;
+ }
+
+ // reposition viewport
+ m_accountTree->setContentsPos(startPoint.x(), startPoint.y());
+
+ // turn updates back on
+ m_accountTree->setUpdatesEnabled(true);
+ m_accountTree->repaintContents();
+
+ m_updateButton->setEnabled(!(selectedBudget() == m_budget));
+ m_resetButton->setEnabled(!(selectedBudget() == m_budget));
+
+ ::timetrace("done load budgets view");
+}
+
+
+bool KBudgetView::loadSubAccounts(KMyMoneyAccountTreeBudgetItem* parent, QStringList& accountList, const MyMoneyBudget& budget)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ bool unused = false;
+
+ //sort the subaccount list
+ //FIXME this is just a hack to order the accounts
+ if ( !accountList.isEmpty() ) {
+ QMap<QString, MyMoneyAccount> accountMap;
+ QValueList<MyMoneyAccount> alist;
+ file->accountList ( alist, accountList );
+ accountList.clear();
+ QValueList<MyMoneyAccount>::const_iterator it_ac;
+ for ( it_ac = alist.begin(); it_ac != alist.end(); ++it_ac ) {
+ accountMap[(*it_ac).name()] = *it_ac;
+ }
+ QMap<QString, MyMoneyAccount>::const_iterator it_am;
+ for ( it_am = accountMap.begin(); it_am != accountMap.end(); ++it_am ) {
+ accountList.prepend((*it_am).id()); //use prepend instead of append otherwise account show up in ascending order
+ }
+ }
+
+ QStringList::const_iterator it_a;
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ const MyMoneyAccount& acc = file->account(*it_a);
+ QValueList<MyMoneyPrice> prices;
+ MyMoneySecurity security = file->baseCurrency();
+ try {
+ if(acc.isInvest()) {
+ security = file->security(acc.currencyId());
+ prices += file->price(acc.currencyId(), security.tradingCurrency());
+ if(security.tradingCurrency() != file->baseCurrency().id()) {
+ MyMoneySecurity sec = file->security(security.tradingCurrency());
+ prices += file->price(sec.id(), file->baseCurrency().id());
+ }
+ } else if(acc.currencyId() != file->baseCurrency().id()) {
+ if(acc.currencyId() != file->baseCurrency().id()) {
+ security = file->security(acc.currencyId());
+ prices += file->price(acc.currencyId(), file->baseCurrency().id());
+ }
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << __PRETTY_FUNCTION__ << " caught exception while adding " << acc.name() << "[" << acc.id() << "]: " << e->what();
+ delete e;
+ }
+
+ QStringList subAcctList = acc.accountList();
+ KMyMoneyAccountTreeBudgetItem *item = new KMyMoneyAccountTreeBudgetItem(parent, acc, budget, prices, security);
+ unused |= loadSubAccounts(item, subAcctList, budget);
+
+ // no child accounts and no value assigned to this account
+ bool thisUnused = (!item->firstChild()) && (!budget.contains(acc.id()));
+
+ // In case of a budget which is unused and we are requested to suppress
+ // the display of those,
+ if(acc.accountGroup() == MyMoneyAccount::Income
+ || acc.accountGroup() == MyMoneyAccount::Expense) {
+ if(m_hideUnusedButton->isEnabled() && m_hideUnusedButton->isChecked() && thisUnused) {
+ unused = true;
+ delete item;
+ }
+ }
+ }
+ return unused;
+}
+
+void KBudgetView::askSave(void)
+{
+ // check if the content of a currently selected budget was modified
+ // and ask to store the data
+ if (m_updateButton->isEnabled()) {
+ if (KMessageBox::questionYesNo(this, QString("<qt>%1</qt>").arg(
+ i18n("Do you want to save the changes for <b>%1</b>").arg(m_budget.name())),
+ i18n("Save changes")) == KMessageBox::Yes) {
+ m_inSelection = true;
+ slotUpdateBudget();
+ m_inSelection = false;
+ }
+ }
+}
+
+void KBudgetView::slotRefreshHideUnusedButton(void)
+{
+ m_hideUnusedButton->setDisabled(m_budget.getaccounts().isEmpty());
+}
+
+void KBudgetView::slotSelectBudget(void)
+{
+ askSave();
+ KBudgetListItem* item;
+ if (m_budget.id().isEmpty()) {
+ item = dynamic_cast<KBudgetListItem*>(m_budgetList->firstChild());
+ if(item) {
+ m_budgetList->blockSignals(true);
+ m_budgetList->setSelected(item, true); // WRTODO das auch beim NewBudget machen
+ m_budgetList->blockSignals(false);
+ }
+ }
+
+ m_accountTree->setEnabled(false);
+ m_assignmentBox->setEnabled(false);
+ m_budget = MyMoneyBudget();
+
+ QListViewItemIterator it_l(m_budgetList, QListViewItemIterator::Selected);
+ item = dynamic_cast<KBudgetListItem*>(it_l.current());
+ if(item) {
+ m_budget = item->budget();
+ m_accountTree->setEnabled(true);
+ }
+
+ slotRefreshHideUnusedButton();
+ loadAccounts();
+
+ QValueList<MyMoneyBudget> budgetList;
+ if(!m_budget.id().isEmpty())
+ budgetList << m_budget;
+ emit selectObjects(budgetList);
+}
+
+void KBudgetView::slotHideUnused(bool toggled)
+{
+ // make sure we show all items for an empty budget
+ bool prevState=!toggled;
+ slotRefreshHideUnusedButton();
+ if (prevState!=m_hideUnusedButton->isChecked())
+ loadAccounts();
+}
+
+const MyMoneyBudget& KBudgetView::selectedBudget(void) const
+{
+ static MyMoneyBudget nullBudget;
+
+ QListViewItemIterator it_l(m_budgetList, QListViewItemIterator::Selected);
+ KBudgetListItem* item = dynamic_cast<KBudgetListItem*>(it_l.current());
+ if(item) {
+ return item->budget();
+ }
+
+ return nullBudget;
+}
+
+KMyMoneyAccountTreeBudgetItem* KBudgetView::selectedAccount(void) const
+{
+ QListViewItemIterator it_l(m_accountTree, QListViewItemIterator::Selected);
+ KMyMoneyAccountTreeBudgetItem* item = dynamic_cast<KMyMoneyAccountTreeBudgetItem*>(it_l.current());
+ return item;
+}
+
+void KBudgetView::slotOpenContextMenu(KListView* lv, QListViewItem* i, const QPoint& p)
+{
+ Q_UNUSED(lv);
+ Q_UNUSED(p);
+
+ m_accountTree->setUpdatesEnabled(false);
+
+ KBudgetListItem* item = dynamic_cast<KBudgetListItem*>(i);
+ if (item)
+ emit openContextMenu(item->budget());
+ else
+ emit openContextMenu(MyMoneyBudget());
+
+ m_accountTree->setUpdatesEnabled(true);
+}
+
+void KBudgetView::slotStartRename(void)
+{
+ QListViewItemIterator it_l(m_budgetList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ if((it_v = it_l.current()) != 0) {
+ it_v->startRename(0);
+ }
+}
+
+// This variant is only called when a single budget is selected and renamed.
+void KBudgetView::slotRenameBudget(QListViewItem* p , int /*col*/, const QString& txt)
+{
+ KBudgetListItem *pBudget = dynamic_cast<KBudgetListItem*> (p);
+ if (!pBudget)
+ return;
+
+ //kdDebug() << "[KPayeesView::slotRenamePayee]" << endl;
+ // create a copy of the new name without appended whitespaces
+ QString new_name = txt.stripWhiteSpace();
+ if (pBudget->budget().name() != new_name) {
+ MyMoneyFileTransaction ft;
+ try {
+ // check if we already have a budget with the new name
+ try {
+ // this function call will throw an exception, if the budget
+ // hasn't been found.
+ MyMoneyFile::instance()->budgetByName(new_name);
+ // the name already exists, ask the user whether he's sure to keep the name
+ if (KMessageBox::questionYesNo(this,
+ i18n("A budget with the name '%1' already exists. It is not advisable to have "
+ "multiple budgets with the same identification name. Are you sure you would like "
+ "to rename the budget?").arg(new_name)) != KMessageBox::Yes)
+ {
+ p->setText(0,pBudget->budget().name());
+ return;
+ }
+ } catch(MyMoneyException *e) {
+ // all ok, the name is unique
+ delete e;
+ }
+
+ MyMoneyBudget b = pBudget->budget();
+ b.setName(new_name);
+ // don't use pBudget beyond this point as it will change due to call to modifyBudget
+ pBudget = 0;
+
+ MyMoneyFile::instance()->modifyBudget(b);
+
+ // the above call to modifyBudget will reload the view so
+ // all references and pointers to the view have to be
+ // re-established. You cannot use pBudget beyond this point!!!
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to modify budget"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+ }
+ else {
+ pBudget->setText(0, new_name);
+ }
+}
+
+void KBudgetView::slotSelectAccount(QListViewItem* item)
+{
+ if(item->listView() == m_accountTree) {
+ m_assignmentBox->setEnabled(false);
+ KMyMoneyAccountTreeBudgetItem *account = selectedAccount();
+ m_assignmentBox->setEnabled(account != 0);
+
+ if(account) {
+ if (m_budget.id().isEmpty() )
+ return;
+
+ QString id = account->id();
+ m_leAccounts->setText(MyMoneyFile::instance()->accountToCategory(id));
+ m_cbBudgetSubaccounts->setChecked(m_budget.account(id).budgetSubaccounts());
+ m_accountTotal->setValue(m_budget.account(id).totalBalance());
+
+ MyMoneyBudget::AccountGroup budgetAccount = m_budget.account( id );
+ if ( id != budgetAccount.id() ) {
+ budgetAccount.setBudgetLevel(MyMoneyBudget::AccountGroup::eMonthly);
+ }
+ m_budgetValue->setBudgetValues(m_budget, budgetAccount);
+ }
+ }
+}
+
+void KBudgetView::slotBudgetedAmountChanged(void)
+{
+ if (m_budget.id().isEmpty())
+ return;
+
+ KMyMoneyAccountTreeBudgetItem *account;
+ if ((account=selectedAccount()) == NULL)
+ return;
+
+ MyMoneyBudget::AccountGroup accountGroup = m_budget.account(account->id());
+ accountGroup.setId( account->id() );
+ m_budgetValue->budgetValues(m_budget, accountGroup);
+ m_budget.setAccount(accountGroup, account->id());
+
+ account->setBudget(m_budget);
+ m_accountTotal->setValue(accountGroup.totalBalance());
+
+ m_updateButton->setEnabled(!(selectedBudget() == m_budget));
+ m_resetButton->setEnabled(!(selectedBudget() == m_budget));
+}
+
+void KBudgetView::AccountEnter()
+{
+ if (m_budget.id().isEmpty())
+ return;
+
+ //(ace) kCategoryWidget not currently defined
+ KMyMoneyAccountTreeBudgetItem *item = NULL; //dynamic_cast<KMyMoneyAccountTreeBudgetItem*> (m_accountTree->findItem(m_leAccounts->selectedAccountId()));
+ if (item)
+ {
+ m_accountTree->setCurrentItem(item);
+ m_accountTree->setOpen(item, true);
+ }
+}
+
+
+void KBudgetView::cb_includesSubaccounts_clicked()
+{
+ if (m_budget.id().isEmpty())
+ return;
+
+ if(selectedAccount() != 0) {
+ QString accountID = selectedAccount()->id();
+ // now, we get a reference to the accountgroup, to mofify its atribute,
+ // and then put the resulting account group instead of the original
+
+ MyMoneyBudget::AccountGroup auxAccount = m_budget.account(accountID);
+ auxAccount.setBudgetSubaccounts( m_cbBudgetSubaccounts->isChecked());
+ m_budget.setAccount( auxAccount, accountID);
+
+ loadAccounts();
+ }
+}
+
+void KBudgetView::slotNewBudget(void)
+{
+ askSave();
+ kmymoney2->action("budget_new")->activate();
+}
+
+void KBudgetView::slotResetBudget(void)
+{
+ try {
+ m_budget = MyMoneyFile::instance()->budget(m_budget.id());
+ loadAccounts();
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to reset budget"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+}
+
+void KBudgetView::slotUpdateBudget(void)
+{
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifyBudget(m_budget);
+ ft.commit();
+ slotRefreshHideUnusedButton();
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to modify budget"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+}
+
+void KBudgetView::languageChange(void)
+{
+ KBudgetViewDecl::languageChange();
+
+ m_newButton->setText(QString());
+ m_renameButton->setText(QString());
+ m_deleteButton->setText(QString());
+ m_updateButton->setText(QString());
+ m_resetButton->setText(QString());
+}
+
+#include "kbudgetview.moc"
diff --git a/kmymoney2/views/kbudgetview.h b/kmymoney2/views/kbudgetview.h
new file mode 100644
index 0000000..f857a15
--- /dev/null
+++ b/kmymoney2/views/kbudgetview.h
@@ -0,0 +1,221 @@
+/***************************************************************************
+ kbudgetview.h
+ -------------
+ begin : Thu Jan 24 2002
+ copyright : (C) 2006 by Darren Gould
+ email : darren_gould@gmx.de
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBUDGETVIEW_H
+#define KBUDGETVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+#include <kpopupmenu.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kbudgetviewdecl.h"
+#include "../mymoney/mymoneybudget.h"
+#include "../mymoney/mymoneysecurity.h"
+class KMyMoneyAccountTreeBudgetItem;
+
+/**
+ * @author Darren Gould
+ * @author Thomas Baumgart
+ *
+ *
+ * This class represents an item in the budgets list view.
+ */
+class KBudgetListItem : public KListViewItem
+{
+public:
+ /**
+ * Constructor to be used to construct a budget entry object.
+ *
+ * @param parent pointer to the KListView object this entry should be
+ * added to.
+ * @param budget const reference to MyMoneyBudget for which
+ * the KListView entry is constructed
+ */
+ KBudgetListItem(KListView *parent, const MyMoneyBudget& budget);
+ ~KBudgetListItem();
+
+ /**
+ * This method is re-implemented from QListViewItem::paintCell().
+ * Besides the standard implementation, the QPainter is set
+ * according to the applications settings.
+ */
+ void paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align);
+
+ const MyMoneyBudget& budget(void) { return m_budget; };
+ void setBudget(const MyMoneyBudget& budget) { m_budget = budget; }
+
+private:
+ MyMoneyBudget m_budget;
+};
+
+/**
+ * @author Darren Gould
+ * @author Thomas Baumgart
+ */
+class KBudgetView : public KBudgetViewDecl
+{
+ Q_OBJECT
+public:
+ KBudgetView(QWidget *parent=0, const char *name=0);
+ ~KBudgetView();
+ void show();
+
+ /**
+ * Override the base class behaviour to restore the layout. Do not
+ * do this in show() because show() itself may change the layout
+ * in undesired ways.
+ */
+ void polish(void);
+
+ /**
+ * This method is used to suppress updates for specific times
+ * (e.g. during creation of a new MyMoneyFile object when the
+ * default accounts are loaded). The behaviour of update() is
+ * controlled with the parameter.
+ *
+ * @param suspend Suspend updates or not. Possible values are
+ *
+ * @li true updates are suspended
+ * @li false updates will be performed immediately
+ *
+ * When a true/false transition of the parameter between
+ * calls to this method is detected,
+ * refresh() will be invoked once automatically.
+ */
+ void suspendUpdate(const bool suspend);
+
+public slots:
+ void slotReloadView(void);
+ void slotRefreshView(void);
+ void slotSelectBudget(void);
+ void slotHideUnused(bool);
+ void slotRefreshHideUnusedButton();
+ void slotStartRename(void);
+
+ /**
+ *This is to update the information about the checkbox "budget amount integrates subaccounts" into the file, when the user clicks the check box
+ */
+ void cb_includesSubaccounts_clicked();
+
+
+protected:
+ void resizeEvent(QResizeEvent*);
+ void loadAccounts(void);
+ bool loadSubAccounts(KMyMoneyAccountTreeBudgetItem* parent, QStringList& accountList, const MyMoneyBudget& budget);
+
+ /**
+ * This method loads all available budgets into the budget list widget. If a budget is
+ * currently selected it remains selected if it is still present.
+ */
+ void loadBudgets(void);
+ void ensureBudgetVisible(const QString& id);
+ const MyMoneyBudget& selectedBudget(void) const;
+ KMyMoneyAccountTreeBudgetItem* selectedAccount(void) const;
+ void setTimeSpan(KMyMoneyAccountTreeBudgetItem *account, MyMoneyBudget::AccountGroup& accountGroup, int iTimeSpan);
+ void askSave(void);
+
+protected slots:
+
+ /**
+ * This slot is called when the name of a budget is changed inside
+ * the budget list view and only a single budget is selected.
+ *
+ * @param p The listviewitem containing the budget name
+ * @param col The column where the name is located
+ * @param txt The text of the new name
+ */
+ void slotRenameBudget(QListViewItem *p, int col, const QString& txt);
+
+ /**
+ * This slot is called when the amount of a budget is changed. It
+ * updates the budget and stores it in the engine
+ */
+ void slotBudgetedAmountChanged(void);
+
+ /**
+ */
+ void slotSelectAccount(QListViewItem*);
+
+ void AccountEnter();
+
+ void slotUpdateBudget(void);
+
+ void slotResetBudget(void);
+
+ void slotNewBudget(void);
+
+ void languageChange(void);
+
+private slots:
+ void slotRearrange(void);
+
+ /**
+ * This slot receives the signal from the listview control that an item was right-clicked,
+ * If @p item points to a real budget item, emits openContextMenu().
+ *
+ * @param lv pointer to the listview
+ * @param i the item on which the cursor resides
+ * @param p position of the pointing device
+ */
+ void slotOpenContextMenu(KListView* lv, QListViewItem* i, const QPoint& p);
+
+signals:
+ /**
+ * This signal serves as proxy for KMyMoneyBudgetList::selectObject()
+ */
+ void openContextMenu(const MyMoneyObject& obj);
+ void selectObjects(const QValueList<MyMoneyBudget>& budget);
+
+private:
+ typedef enum {
+ eNone=-1,
+ eYearly=0,
+ eMonthly=1,
+ eMonthByMonth=2
+ } eTimePeriodColumn;
+
+ MyMoneyBudget m_budget;
+
+ QMap<QString, unsigned long> m_transactionCountMap;
+ QStringList m_yearList;
+
+ KMyMoneyAccountTreeBudgetItem* m_incomeItem;
+ KMyMoneyAccountTreeBudgetItem* m_expenseItem;
+
+ /// set if a view needs to be reloaded during show()
+ bool m_needReload;
+
+ // set if we are in the selection of a different budget
+ bool m_inSelection;
+
+ void adaptHideUnusedButton(void);
+
+ static const int m_iBudgetYearsAhead;
+ static const int m_iBudgetYearsBack;
+};
+
+#endif
diff --git a/kmymoney2/views/kbudgetviewdecl.ui b/kmymoney2/views/kbudgetviewdecl.ui
new file mode 100644
index 0000000..f3fb5be
--- /dev/null
+++ b/kmymoney2/views/kbudgetviewdecl.ui
@@ -0,0 +1,348 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KBudgetViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KBudgetViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>957</width>
+ <height>610</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Your budgets</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_newButton</cstring>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_renameButton</cstring>
+ </property>
+ <property name="text">
+ <string>Ren</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>Del</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_resetButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Res</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_updateButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Upd</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Year</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_budgetList</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="showSortIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>false</bool>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneyAccountTreeBudget">
+ <property name="name">
+ <cstring>m_accountTree</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>5</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_hideUnusedButton</cstring>
+ </property>
+ <property name="text">
+ <string>Hide unused budget categories</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_assignmentBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>5</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Assignments</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Account</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_leAccounts</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Total</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_accountTotal</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="calculatorButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_cbBudgetSubaccounts</cstring>
+ </property>
+ <property name="text">
+ <string>Include subaccounts</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KBudgetValues">
+ <property name="name">
+ <cstring>m_budgetValue</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KMyMoneyAccountTreeBudget</class>
+ <header location="local">../widgets/kmymoneyaccounttreebudget.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="870">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kcategoriesview.cpp b/kmymoney2/views/kcategoriesview.cpp
new file mode 100644
index 0000000..e01d62b
--- /dev/null
+++ b/kmymoney2/views/kcategoriesview.cpp
@@ -0,0 +1,313 @@
+/***************************************************************************
+ kcategoriesview.cpp - description
+ -------------------
+ begin : Sun Jan 20 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include "kcategoriesview.h"
+#include "../widgets/klistviewsearchline.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../kmymoney2.h"
+
+
+KCategoriesView::KCategoriesView(QWidget *parent, const char *name ) :
+ KCategoriesViewDecl(parent, name),
+ m_incomeItem(0),
+ m_expenseItem(0),
+ m_needReload(false)
+{
+ // create the searchline widget
+ // and insert it into the existing layout
+ m_searchWidget = new KListViewSearchLineWidget(m_accountTree, m_accountTree->parentWidget());
+ QVBoxLayout* layout = dynamic_cast<QVBoxLayout*>(m_accountTree->parentWidget()->layout());
+ if(layout) {
+ layout->insertWidget(0, m_searchWidget);
+ }
+
+ // setup icons for collapse and expand button
+ KIconLoader *ic = KGlobal::iconLoader();
+ KGuiItem collapseGuiItem("",
+ QIconSet(ic->loadIcon("viewmag-", KIcon::Small, KIcon::SizeSmall)),
+ QString(),
+ QString());
+ KGuiItem expandGuiItem("",
+ QIconSet(ic->loadIcon("viewmag+", KIcon::Small, KIcon::SizeSmall)),
+ QString(),
+ QString());
+ m_collapseButton->setGuiItem(collapseGuiItem);
+ m_expandButton->setGuiItem(expandGuiItem);
+
+ m_accountTree->setSectionHeader(i18n("Category"));
+
+ connect(m_accountTree, SIGNAL(selectObject(const MyMoneyObject&)), this, SIGNAL(selectObject(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(openContextMenu(const MyMoneyObject&)), this, SIGNAL(openContextMenu(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(valueChanged(void)), this, SLOT(slotUpdateProfit(void)));
+ connect(m_accountTree, SIGNAL(openObject(const MyMoneyObject&)), this, SIGNAL(openObject(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), this, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadAccounts()));
+ connect(m_collapseButton, SIGNAL(clicked()), this, SLOT(slotExpandCollapse()));
+ connect(m_expandButton, SIGNAL(clicked()), this, SLOT(slotExpandCollapse()));
+}
+
+KCategoriesView::~KCategoriesView()
+{
+}
+
+void KCategoriesView::slotExpandCollapse(void)
+{
+ if(sender()) {
+ KMyMoneyGlobalSettings::setShowAccountsExpanded(sender() == m_expandButton);
+ }
+}
+
+
+void KCategoriesView::show(void)
+{
+ if(m_needReload) {
+ loadAccounts();
+ m_needReload = false;
+ }
+
+ // don't forget base class implementation
+ KCategoriesViewDecl::show();
+
+ // if we have a selected account, let the application know about it
+ KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
+ if(item) {
+ emit selectObject(item->itemObject());
+ }
+}
+
+void KCategoriesView::polish(void)
+{
+ KCategoriesViewDecl::polish();
+ m_accountTree->setResizeMode(QListView::LastColumn);
+ m_accountTree->restoreLayout("Category View Settings");
+
+}
+
+void KCategoriesView::slotLoadAccounts(void)
+{
+ if(isVisible()) {
+ loadAccounts();
+ } else {
+ m_needReload = true;
+ }
+}
+
+void KCategoriesView::loadAccounts(void)
+{
+ QMap<QString, bool> isOpen;
+
+ ::timetrace("start load categories view");
+ // remember the id of the current selected item
+ KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
+ QString selectedItemId = (item) ? item->id() : QString();
+
+ // keep a map of all 'expanded' accounts
+ QListViewItemIterator it_lvi(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item && item->isOpen()) {
+ isOpen[item->id()] = true;
+ }
+ ++it_lvi;
+ }
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_accountTree->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_accountTree->setUpdatesEnabled(false);
+
+ // clear the current contents and recreate it
+ m_accountTree->clear();
+ m_securityMap.clear();
+ m_transactionCountMap.clear();
+
+ // make sure, the pointers are not pointing to some deleted object
+ m_incomeItem = m_expenseItem = 0;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneySecurity> slist = file->currencyList();
+ slist += file->securityList();
+ QValueList<MyMoneySecurity>::const_iterator it_s;
+ for(it_s = slist.begin(); it_s != slist.end(); ++it_s) {
+ m_securityMap[(*it_s).id()] = *it_s;
+ }
+
+ m_transactionCountMap = file->transactionCountMap();
+
+ bool haveUnusedCategories = false;
+
+ // create the items
+ try {
+ const MyMoneySecurity& security = file->baseCurrency();
+ m_accountTree->setBaseCurrency(security);
+
+ const MyMoneyAccount& income = file->income();
+ m_incomeItem = new KMyMoneyAccountTreeItem(m_accountTree, income, security, i18n("Income"));
+ haveUnusedCategories |= loadSubAccounts(m_incomeItem, income.accountList());
+
+ const MyMoneyAccount& expense = file->expense();
+ m_expenseItem = new KMyMoneyAccountTreeItem(m_accountTree, expense, security, i18n("Expense"));
+ haveUnusedCategories |= loadSubAccounts(m_expenseItem, expense.accountList());
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << "Problem in categoriesview: " << e->what() << endl;
+ delete e;
+ }
+
+ // scan through the list of accounts and re-expand those that were
+ // expanded and re-select the one that was probably selected before
+ it_lvi = QListViewItemIterator(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item) {
+ if(item->id() == selectedItemId)
+ m_accountTree->setSelected(item, true);
+ if(isOpen.find(item->id()) != isOpen.end())
+ item->setOpen(true);
+ }
+ ++it_lvi;
+ }
+
+ // reposition viewport
+ m_accountTree->setContentsPos(startPoint.x(), startPoint.y());
+
+ m_searchWidget->searchLine()->updateSearch(QString::null);
+
+ // turn updates back on
+ m_accountTree->setUpdatesEnabled(true);
+ m_accountTree->repaintContents();
+
+ // and in case we need to show things expanded, we'll do so
+ if(KMyMoneyGlobalSettings::showAccountsExpanded())
+ m_accountTree->slotExpandAll();
+
+ // update the hint if categories are hidden
+ m_hiddenCategories->setShown(haveUnusedCategories);
+
+ ::timetrace("done load categories view");
+}
+
+bool KCategoriesView::loadSubAccounts(KMyMoneyAccountTreeItem* parent, const QStringList& accountList)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ bool unused = false;
+
+ QStringList::const_iterator it_a;
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ const MyMoneyAccount& acc = file->account(*it_a);
+ QValueList<MyMoneyPrice> prices;
+ MyMoneySecurity security = file->baseCurrency();
+ try {
+ if(acc.isInvest()) {
+ security = m_securityMap[acc.currencyId()];
+ prices += file->price(acc.currencyId(), security.tradingCurrency());
+ if(security.tradingCurrency() != file->baseCurrency().id()) {
+ MyMoneySecurity sec = m_securityMap[security.tradingCurrency()];
+ prices += file->price(sec.id(), file->baseCurrency().id());
+ }
+ } else if(acc.currencyId() != file->baseCurrency().id()) {
+ if(acc.currencyId() != file->baseCurrency().id()) {
+ security = m_securityMap[acc.currencyId()];
+ prices += file->price(acc.currencyId(), file->baseCurrency().id());
+ }
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << __PRETTY_FUNCTION__ << " caught exception while adding " << acc.name() << "[" << acc.id() << "]: " << e->what();
+ delete e;
+ }
+
+ KMyMoneyAccountTreeItem* item = new KMyMoneyAccountTreeItem(parent, acc, prices, security);
+ unused |= loadSubAccounts(item, acc.accountList());
+
+ // no child accounts and not transactions in this account means 'unused'
+ bool thisUnused = (!item->firstChild()) && (m_transactionCountMap[acc.id()] == 0);
+
+ // In case of a category which is unused and we are requested to suppress
+ // the display of those,
+ if(acc.accountGroup() == MyMoneyAccount::Income
+ || acc.accountGroup() == MyMoneyAccount::Expense) {
+ if(KMyMoneyGlobalSettings::hideUnusedCategory() && thisUnused) {
+ unused = true;
+ delete item;
+ }
+ }
+ }
+ return unused;
+}
+
+void KCategoriesView::slotUpdateProfit(void)
+{
+ if(!m_incomeItem || !m_expenseItem)
+ return;
+
+ MyMoneyMoney profit = m_incomeItem->totalValue() - m_expenseItem->totalValue();
+
+ QString s(i18n("Profit: "));
+ if(profit.isNegative())
+ s = i18n("Loss: ");
+
+ // FIXME figure out how to deal with the approximate
+ // if(!(file->totalValueValid(assetAccount.id()) & file->totalValueValid(liabilityAccount.id())))
+ // s += "~ ";
+
+ s.replace(QString(" "), QString("&nbsp;"));
+ if(profit.isNegative()) {
+ s += "<b><font color=\"red\">";
+ }
+ const MyMoneySecurity& sec = MyMoneyFile::instance()->baseCurrency();
+ QString v(profit.abs().formatMoney(sec));
+ s += v.replace(QString(" "), QString("&nbsp;"));
+ if(profit.isNegative()) {
+ s += "</font></b>";
+ }
+
+ m_totalProfitsLabel->setFont(KMyMoneyGlobalSettings::listCellFont());
+ m_totalProfitsLabel->setText(s);
+}
+
+#include "kcategoriesview.moc"
+
diff --git a/kmymoney2/views/kcategoriesview.h b/kmymoney2/views/kcategoriesview.h
new file mode 100644
index 0000000..4a6ad3c
--- /dev/null
+++ b/kmymoney2/views/kcategoriesview.h
@@ -0,0 +1,147 @@
+/***************************************************************************
+ kcategoriesview.h - description
+ -------------------
+ begin : Sun Jan 20 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ (C) 2005 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCATEGORIESVIEW_H
+#define KCATEGORIESVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/mymoneyutils.h>
+class KListViewSearchLineWidget;
+
+#include "kcategoriesviewdecl.h"
+
+/**
+ * @brief This class contains the implementation of the categories view.
+ * @author Michael Edwardes, Thomas Baumgart
+ *
+ * While named "categories view", this view actually displays all accounts
+ * that are children of the global "Income" and "Expense" accounts. Even though
+ * categories are internally just accounts as well, the distinction between
+ * categories and accounts in the user interface is done for better
+ * usability and clarity.
+ *
+ * The main functionality in the categories view is actually implemented
+ * in the KMyMoneyAccountTree. Signals from user actions are connect to
+ * other signals/slots in KCategoriesView and relayed to KMyMoneyView.
+ * A typical example is the selectObject() signal that eventually results
+ * in enabling/disabling the user actions for the categories view.
+ *
+ * For the categories view three user actions are important (all created in
+ * kmymoney2.cpp): category_new, category_edit and category_delete. They are
+ * accessible from either the main menu or the context menu.
+ */
+class KCategoriesView : public KCategoriesViewDecl
+{
+ Q_OBJECT
+public:
+ KCategoriesView(QWidget *parent=0, const char *name=0);
+ virtual ~KCategoriesView();
+
+
+public slots:
+ void slotLoadAccounts(void);
+
+ /**
+ * Override the base class behaviour to include all updates that
+ * happened in the meantime.
+ */
+ void show(void);
+
+ /**
+ * Override the base class behaviour to restore the layout. Do not
+ * do this in show() because show() itself may change the layout
+ * in undesired ways.
+ */
+ void polish(void);
+
+protected:
+ void loadAccounts(void);
+ bool loadSubAccounts(KMyMoneyAccountTreeItem* parent, const QStringList& accountList);
+
+protected slots:
+ void slotUpdateProfit(void);
+ void slotExpandCollapse(void);
+
+private:
+ /**
+ * This method returns an icon according to the account type
+ * passed in the argument @p type.
+ *
+ * @param type account type as defined in MyMoneyAccount::accountTypeE
+ */
+ const QPixmap accountImage(const MyMoneyAccount::accountTypeE type) const;
+
+signals:
+ /**
+ * This signal serves as proxy for KMyMoneyAccountTree::selectObject()
+ */
+ void selectObject(const MyMoneyObject&);
+
+ /**
+ * This signal serves as proxy for
+ * KMyMoneyAccountTree::openContextMenu(const MyMoneyObject&)
+ */
+ void openContextMenu(const MyMoneyObject& obj);
+
+ /**
+ * This signal will be emitted when the left mouse button is double
+ * clicked (actually the KDE executed setting is used) on an account.
+ */
+ void openObject(const MyMoneyObject& obj);
+
+ /**
+ * This signal is emitted, when the user selected to reparent the
+ * account @p acc to be a subordinate account of @p parent.
+ *
+ * @param acc const reference to account to be reparented
+ * @param parent const reference to new parent account
+ */
+ void reparent(const MyMoneyAccount& acc, const MyMoneyAccount& parent);
+
+private:
+ QMap<QString, MyMoneySecurity> m_securityMap;
+ QMap<QString, unsigned long> m_transactionCountMap;
+
+ KMyMoneyAccountTreeItem* m_incomeItem;
+ KMyMoneyAccountTreeItem* m_expenseItem;
+
+ /**
+ * Search widget for the list
+ */
+ KListViewSearchLineWidget* m_searchWidget;
+
+ /// set if a view needs to be reloaded during show()
+ bool m_needReload;
+};
+
+#endif
diff --git a/kmymoney2/views/kcategoriesviewdecl.ui b/kmymoney2/views/kcategoriesviewdecl.ui
new file mode 100644
index 0000000..858cc54
--- /dev/null
+++ b/kmymoney2/views/kcategoriesviewdecl.ui
@@ -0,0 +1,153 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KCategoriesViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KCategoriesViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>698</width>
+ <height>430</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KMyMoneyAccountTree">
+ <property name="name">
+ <cstring>m_accountTree</cstring>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_collapseButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Collapse all accounts in the list</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_expandButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Expand all accounts in the list</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>515</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_hiddenCategories</cstring>
+ </property>
+ <property name="text">
+ <string>Note: Unused categories are not shown as selected by settings.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>310</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_totalProfitsLabel</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Total Profits:</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_expandButton</sender>
+ <signal>clicked()</signal>
+ <receiver>m_accountTree</receiver>
+ <slot>slotExpandAll()</slot>
+ </connection>
+ <connection>
+ <sender>m_collapseButton</sender>
+ <signal>clicked()</signal>
+ <receiver>m_accountTree</receiver>
+ <slot>slotCollapseAll()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kforecastview.cpp b/kmymoney2/views/kforecastview.cpp
new file mode 100644
index 0000000..c7bcb0a
--- /dev/null
+++ b/kmymoney2/views/kforecastview.cpp
@@ -0,0 +1,673 @@
+/***************************************************************************
+ kforecastview.cpp
+ -------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtabwidget.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qbuttongroup.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include "kforecastview.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../kmymoney2.h"
+#include "../kmymoneyutils.h"
+#include "../mymoney/mymoneyforecast.h"
+#include "../widgets/kmymoneyforecastlistviewitem.h"
+#include "../widgets/kmymoneyaccounttreeforecast.h"
+#include "../reports/pivottable.h"
+#include "../reports/pivotgrid.h"
+
+KForecastView::KForecastView(QWidget *parent, const char *name) :
+ KForecastViewDecl(parent,name)
+{
+ for(int i=0; i < MaxViewTabs; ++i)
+ m_needReload[i] = false;
+
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ m_tab->setCurrentPage(config->readNumEntry("KForecastView_LastType", 0));
+
+ connect(m_tab, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotTabChanged(QWidget*)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadForecast()));
+
+ connect(m_forecastButton, SIGNAL(clicked()), this, SLOT(slotManualForecast()));
+
+ m_forecastList->setAllColumnsShowFocus(true);
+ m_summaryList->setAllColumnsShowFocus(true);
+ //m_adviceList->setAllColumnsShowFocus(true);
+ m_advancedList->setAllColumnsShowFocus(true);
+
+ m_forecastChart = new KReportChartView(m_tabChart, "forecastChart" );
+ m_forecastChart->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
+
+ loadForecastSettings();
+
+}
+
+KForecastView::~KForecastView()
+{
+}
+
+void KForecastView::slotTabChanged(QWidget* _tab)
+{
+ ForecastViewTab tab = static_cast<ForecastViewTab>(m_tab->indexOf(_tab));
+
+ // remember this setting for startup
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("KForecastView_LastType", tab);
+
+ loadForecast(tab);
+
+}
+
+void KForecastView::loadForecast(ForecastViewTab tab)
+{
+ if(m_needReload[tab]) {
+ switch(tab) {
+ case ListView:
+ loadListView();
+ break;
+ case SummaryView:
+ loadSummaryView();
+ break;
+ case AdvancedView:
+ loadAdvancedView();
+ break;
+ case BudgetView:
+ loadBudgetView();
+ break;
+ case ChartView:
+ loadChartView();
+ break;
+ default:
+ break;
+ }
+ m_needReload[tab] = false;
+ }
+}
+
+void KForecastView::show(void)
+{
+ // don't forget base class implementation
+ KForecastViewDecl::show();
+ slotTabChanged(m_tab->currentPage());
+}
+
+void KForecastView::slotLoadForecast(void)
+{
+ m_needReload[SummaryView] = true;
+ m_needReload[ListView] = true;
+ m_needReload[AdvancedView] = true;
+ m_needReload[BudgetView] = true;
+ m_needReload[ChartView] = true;
+
+ //refresh settings
+ loadForecastSettings();
+
+ if(isVisible())
+ slotTabChanged(m_tab->currentPage());
+}
+
+void KForecastView::slotManualForecast(void)
+{
+ m_needReload[SummaryView] = true;
+ m_needReload[ListView] = true;
+ m_needReload[AdvancedView] = true;
+ m_needReload[BudgetView] = true;
+ m_needReload[ChartView] = true;
+
+ if(isVisible())
+ slotTabChanged(m_tab->currentPage());
+}
+
+void KForecastView::loadForecastSettings(void)
+{
+ //fill the settings controls
+ m_forecastDays->setValue(KMyMoneyGlobalSettings::forecastDays());
+ m_accountsCycle->setValue(KMyMoneyGlobalSettings::forecastAccountCycle());
+ m_beginDay->setValue(KMyMoneyGlobalSettings::beginForecastDay());
+ m_forecastCycles->setValue(KMyMoneyGlobalSettings::forecastCycles());
+ m_historyMethod->setButton(KMyMoneyGlobalSettings::historyMethod());
+ switch(KMyMoneyGlobalSettings::forecastMethod()) {
+ case 0:
+ m_forecastMethod->setText(i18n("Scheduled"));
+ m_forecastCycles->setDisabled(true);
+ m_historyMethod->setDisabled(true);
+ break;
+ case 1:
+ m_forecastMethod->setText(i18n("History"));
+ m_forecastCycles->setEnabled(true);
+ m_historyMethod->setEnabled(true);
+ break;
+ default:
+ m_forecastMethod->setText(i18n("Unknown"));
+ break;
+ }
+}
+
+void KForecastView::loadListView(void)
+{
+ MyMoneyForecast forecast;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ m_forecastList->setBaseCurrency(file->baseCurrency());
+
+ //get the settings from current page
+ forecast.setForecastDays(m_forecastDays->value());
+ forecast.setAccountsCycle(m_accountsCycle->value());
+ forecast.setBeginForecastDay(m_beginDay->value());
+ forecast.setForecastCycles(m_forecastCycles->value());
+ forecast.setHistoryMethod(m_historyMethod->selectedId());
+ forecast.doForecast();
+
+ //clear the list, including columns
+ m_forecastList->clearColumns();
+
+ //add columns
+ m_forecastList->showAccount();
+ m_forecastList->showDetailed(forecast);
+
+ //add default rows
+ addTotalRow(m_forecastList, forecast);
+ addAssetLiabilityRows(forecast);
+
+ //load asset and liability forecast accounts
+ loadAccounts(forecast, file->asset(), m_assetItem, KMyMoneyAccountTreeForecastItem::eDetailed);
+ loadAccounts(forecast, file->liability(), m_liabilityItem, KMyMoneyAccountTreeForecastItem::eDetailed);
+
+ m_forecastList->show();
+}
+
+void KForecastView::loadSummaryView(void)
+{
+ MyMoneyForecast forecast;
+ QValueList<MyMoneyAccount> accList;
+ int dropMinimum;
+ int dropZero;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ m_summaryList->setBaseCurrency(file->baseCurrency());
+
+ //get the settings from current page
+ forecast.setForecastDays(m_forecastDays->value());
+ forecast.setAccountsCycle(m_accountsCycle->value());
+ forecast.setBeginForecastDay(m_beginDay->value());
+ forecast.setForecastCycles(m_forecastCycles->value());
+ forecast.setHistoryMethod(m_historyMethod->selectedId());
+ forecast.doForecast();
+
+ //clear the list, including columns
+ m_summaryList->clearColumns();
+
+ //add columns
+ m_summaryList->showAccount();
+ m_summaryList->showSummary(forecast);
+
+ //add default rows
+ addTotalRow(m_summaryList, forecast);
+ addAssetLiabilityRows(forecast);
+
+ loadAccounts(forecast, file->asset(), m_assetItem, KMyMoneyAccountTreeForecastItem::eSummary);
+ loadAccounts(forecast, file->liability(), m_liabilityItem, KMyMoneyAccountTreeForecastItem::eSummary);
+
+ //Add comments to the advice list
+ //Get all accounts of the right type to calculate forecast
+ m_nameIdx.clear();
+ accList = forecast.accountList();
+ QValueList<MyMoneyAccount>::const_iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ++accList_t ) {
+ MyMoneyAccount acc = *accList_t;
+ if(m_nameIdx[acc.id()] != acc.id()) { //Check if the account is there
+ m_nameIdx[acc.id()] = acc.id();
+ }
+ }
+
+ QMap<QString, QString>::ConstIterator it_nc;
+ for(it_nc = m_nameIdx.begin(); it_nc != m_nameIdx.end(); ++it_nc) {
+
+ const MyMoneyAccount& acc = file->account(*it_nc);
+ MyMoneySecurity currency;
+
+ //change currency to deep currency if account is an investment
+ if(acc.isInvest()) {
+ MyMoneySecurity underSecurity = file->security(acc.currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security(acc.currencyId());
+ }
+
+ //Check if the account is going to be below zero or below the minimal balance in the forecast period
+ QString minimumBalance = acc.value("minimumBalance");
+ MyMoneyMoney minBalance = MyMoneyMoney(minimumBalance);
+
+ //Check if the account is going to be below minimal balance
+ dropMinimum = forecast.daysToMinimumBalance(acc);
+
+ //Check if the account is going to be below zero in the future
+ dropZero = forecast.daysToZeroBalance(acc);
+
+ // spit out possible warnings
+ QString msg;
+
+ // if a minimum balance has been specified, an appropriate warning will
+ // only be shown, if the drop below 0 is on a different day or not present
+
+ if(dropMinimum != -1
+ && !minBalance.isZero()
+ && (dropMinimum < dropZero
+ || dropZero == -1)) {
+ switch(dropMinimum) {
+ case -1:
+ break;
+ case 0:
+ msg = QString("<font color=\"%1\">").arg(KMyMoneyGlobalSettings::listNegativeValueColor().name());
+ msg += i18n("The balance of %2 is below the minimum balance %3 today.").arg(acc.name()).arg(minBalance.formatMoney(acc, currency));
+ msg += QString("</font>");
+ break;
+ default:
+ msg = QString("<font color=\"%1\">").arg(KMyMoneyGlobalSettings::listNegativeValueColor().name());
+ msg += i18n("The balance of %1 will drop below the minimum balance %2 in %3 days.").arg(acc.name()).arg(minBalance.formatMoney(acc, currency)).arg(dropMinimum-1);
+ msg += QString("</font>");
+ }
+
+ if(!msg.isEmpty()) {
+ m_adviceText->append(msg);
+ }
+ }
+
+ // a drop below zero is always shown
+ msg = QString();
+ switch(dropZero) {
+ case -1:
+ break;
+ case 0:
+ if(acc.accountGroup() == MyMoneyAccount::Asset) {
+ msg = QString("<font color=\"%1\">").arg(KMyMoneyGlobalSettings::listNegativeValueColor().name());
+ msg += i18n("The balance of %1 is below %2 today.").arg(acc.name()).arg(MyMoneyMoney().formatMoney(acc, currency));
+ msg += QString("</font>");
+ break;
+ }
+ if(acc.accountGroup() == MyMoneyAccount::Liability) {
+ msg = i18n("The balance of %1 is above %2 today.").arg(acc.name()).arg(MyMoneyMoney().formatMoney(acc, currency));
+ break;
+ }
+ break;
+ default:
+ if(acc.accountGroup() == MyMoneyAccount::Asset) {
+ msg = QString("<font color=\"%1\">").arg(KMyMoneyGlobalSettings::listNegativeValueColor().name());
+ msg += i18n("The balance of %1 will drop below %2 in %3 days.").arg(acc.name()).arg(MyMoneyMoney().formatMoney(acc, currency)).arg(dropZero);
+ msg += QString("</font>");
+ break;
+ }
+ if(acc.accountGroup() == MyMoneyAccount::Liability) {
+ msg = i18n("The balance of %1 will raise above %2 in %3 days.").arg(acc.name()).arg(MyMoneyMoney().formatMoney(acc, currency)).arg(dropZero);
+ break;
+ }
+ }
+ if(!msg.isEmpty()) {
+ m_adviceText->append(msg);
+ }
+
+ //advice about trends
+ msg = QString();
+ MyMoneyMoney accCycleVariation = forecast.accountCycleVariation(acc);
+ if (accCycleVariation < MyMoneyMoney(0, 1)) {
+ msg = QString("<font color=\"%1\">").arg(KMyMoneyGlobalSettings::listNegativeValueColor().name());
+ msg += i18n("The account %1 is decreasing %2 per cycle.").arg(acc.name()).arg(accCycleVariation.formatMoney(acc, currency));
+ msg += QString("</font>");
+ }
+
+ if(!msg.isEmpty()) {
+ m_adviceText->append(msg);
+ }
+ }
+ m_summaryList->show();
+ m_adviceText->show();
+}
+
+void KForecastView::loadAdvancedView(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyAccount> accList;
+ MyMoneySecurity baseCurrency = file->baseCurrency();
+ MyMoneyForecast forecast;
+ int daysToBeginDay;
+
+ //get the settings from current page
+ forecast.setForecastDays(m_forecastDays->value());
+ forecast.setAccountsCycle(m_accountsCycle->value());
+ forecast.setBeginForecastDay(m_beginDay->value());
+ forecast.setForecastCycles(m_forecastCycles->value());
+ forecast.setHistoryMethod(m_historyMethod->selectedId());
+ forecast.doForecast();
+
+ //Get all accounts of the right type to calculate forecast
+ m_nameIdx.clear();
+ accList = forecast.accountList();
+ QValueList<MyMoneyAccount>::const_iterator accList_t = accList.begin();
+ for(; accList_t != accList.end(); ++accList_t ) {
+ MyMoneyAccount acc = *accList_t;
+ if(m_nameIdx[acc.id()] != acc.id()) { //Check if the account is there
+ m_nameIdx[acc.id()] = acc.id();
+ }
+ }
+ //clear the list, including columns
+ m_advancedList->clear();
+ for(;m_advancedList->columns() > 0;) {
+ m_advancedList->removeColumn(0);
+ }
+
+ //add first column of both lists
+ int accountColumn = m_advancedList->addColumn(i18n("Account"), -1);
+
+ //if beginning of forecast is today, set the begin day to next cycle to avoid repeating the first cycle
+ if(QDate::currentDate() < forecast.beginForecastDate()) {
+ daysToBeginDay = QDate::currentDate().daysTo(forecast.beginForecastDate());
+ } else {
+ daysToBeginDay = forecast.accountsCycle();
+ }
+
+ //add columns
+ for(int i = 1; ((i * forecast.accountsCycle()) + daysToBeginDay) <= forecast.forecastDays(); ++i) {
+ int col = m_advancedList->addColumn(i18n("Min Bal %1").arg(i), -1);
+ m_advancedList->setColumnAlignment(col, Qt::AlignRight);
+ m_advancedList->addColumn(i18n("Min Date %1").arg(i), -1);
+ }
+ for(int i = 1; ((i * forecast.accountsCycle()) + daysToBeginDay) <= forecast.forecastDays(); ++i) {
+ int col = m_advancedList->addColumn(i18n("Max Bal %1").arg(i), -1);
+ m_advancedList->setColumnAlignment(col, Qt::AlignRight);
+ m_advancedList->addColumn(i18n("Max Date %1").arg(i), -1);
+ }
+ int col = m_advancedList->addColumn(i18n("Average"), -1);
+ m_advancedList->setColumnAlignment(col, Qt::AlignRight);
+ m_advancedList->setSorting(-1);
+ KMyMoneyForecastListViewItem *advancedItem = 0;
+
+ QMap<QString, QString>::ConstIterator it_nc;
+ for(it_nc = m_nameIdx.begin(); it_nc != m_nameIdx.end(); ++it_nc) {
+ const MyMoneyAccount& acc = file->account(*it_nc);
+ QString amount;
+ MyMoneyMoney amountMM;
+ MyMoneySecurity currency;
+
+ //change currency to deep currency if account is an investment
+ if(acc.isInvest()) {
+ MyMoneySecurity underSecurity = file->security(acc.currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security(acc.currencyId());
+ }
+
+
+ advancedItem = new KMyMoneyForecastListViewItem(m_advancedList, advancedItem, false);
+ advancedItem->setText(accountColumn, acc.name());
+ int it_c = 1; // iterator for the columns of the listview
+
+ //get minimum balance list
+ QValueList<QDate> minBalanceList = forecast.accountMinimumBalanceDateList(acc);
+ QValueList<QDate>::Iterator t_min;
+ for(t_min = minBalanceList.begin(); t_min != minBalanceList.end() ; ++t_min)
+ {
+ QDate minDate = *t_min;
+ amountMM = forecast.forecastBalance(acc, minDate);
+
+ amount = amountMM.formatMoney(acc, currency);
+ advancedItem->setText(it_c, amount, amountMM.isNegative());
+ it_c++;
+
+ QString dateString = KGlobal::locale()->formatDate(minDate, true);
+ advancedItem->setText(it_c, dateString, amountMM.isNegative());
+ it_c++;
+ }
+
+ //get maximum balance list
+ QValueList<QDate> maxBalanceList = forecast.accountMaximumBalanceDateList(acc);
+ QValueList<QDate>::Iterator t_max;
+ for(t_max = maxBalanceList.begin(); t_max != maxBalanceList.end() ; ++t_max)
+ {
+ QDate maxDate = *t_max;
+ amountMM = forecast.forecastBalance(acc, maxDate);
+
+ amount = amountMM.formatMoney(acc, currency);
+ advancedItem->setText(it_c, amount, amountMM.isNegative());
+ it_c++;
+
+ QString dateString = KGlobal::locale()->formatDate(maxDate, true);
+ advancedItem->setText(it_c, dateString, amountMM.isNegative());
+ it_c++;
+ }
+ //get average balance
+ amountMM = forecast.accountAverageBalance(acc);
+ amount = amountMM.formatMoney(acc, currency);
+ advancedItem->setText(it_c, amount, amountMM.isNegative());
+ it_c++;
+ }
+ m_advancedList->show();
+}
+
+void KForecastView::loadBudgetView(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyForecast forecast;
+// QValueList<MyMoneyAccount> accList;
+
+ m_budgetList->setBaseCurrency(file->baseCurrency());
+
+ //get the settings from current page and calculate this year based on last year
+ QDate historyEndDate = QDate(QDate::currentDate().year()-1, 12, 31);
+ QDate historyStartDate = historyEndDate.addDays(-m_accountsCycle->value() * m_forecastCycles->value());
+ QDate forecastStartDate = QDate(QDate::currentDate().year(), 1, 1);
+ QDate forecastEndDate = QDate::currentDate().addDays(m_forecastDays->value());
+ forecast.setHistoryMethod(m_historyMethod->selectedId());
+
+ MyMoneyBudget budget;
+ forecast.createBudget(budget, historyStartDate, historyEndDate, forecastStartDate, forecastEndDate, false);
+
+ //clear the list, including columns
+ m_budgetList->clearColumns();
+
+ //add columns
+ m_budgetList->showAccount();
+ m_budgetList->showBudget(forecast);
+
+ //add default rows
+ addTotalRow(m_budgetList, forecast);
+ addIncomeExpenseRows(forecast);
+
+ //load income and expense budget accounts
+ loadAccounts(forecast, file->income(), m_incomeItem, KMyMoneyAccountTreeForecastItem::eBudget);
+ loadAccounts(forecast, file->expense(), m_expenseItem, KMyMoneyAccountTreeForecastItem::eBudget);
+
+ m_budgetList->show();
+}
+
+QValueList<MyMoneyPrice> KForecastView::getAccountPrices(const MyMoneyAccount& acc)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyPrice> prices;
+ MyMoneySecurity security = file->baseCurrency();
+ try {
+ if(acc.isInvest()) {
+ security = file->security(acc.currencyId());
+ if(security.tradingCurrency() != file->baseCurrency().id()) {
+ MyMoneySecurity sec = file->security(security.tradingCurrency());
+ prices += file->price(sec.id(), file->baseCurrency().id());
+ }
+ } else if(acc.currencyId() != file->baseCurrency().id()) {
+ if(acc.currencyId() != file->baseCurrency().id()) {
+ security = file->security(acc.currencyId());
+ prices += file->price(acc.currencyId(), file->baseCurrency().id());
+ }
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << __PRETTY_FUNCTION__ << " caught exception while adding " << acc.name() << "[" << acc.id() << "]: " << e->what();
+ delete e;
+ }
+ return prices;
+}
+
+void KForecastView::addAssetLiabilityRows(const MyMoneyForecast& forecast)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyPrice> basePrices;
+ m_assetItem = new KMyMoneyAccountTreeForecastItem( m_totalItem, file->asset(), forecast, basePrices, file->baseCurrency() );
+ m_assetItem->setOpen(true);
+ m_liabilityItem = new KMyMoneyAccountTreeForecastItem( m_totalItem, file->liability(), forecast, basePrices, file->baseCurrency());
+ m_liabilityItem->setOpen(true);
+}
+
+void KForecastView::addIncomeExpenseRows(const MyMoneyForecast& forecast)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyPrice> basePrices;
+ m_incomeItem = new KMyMoneyAccountTreeForecastItem( m_totalItem, file->income(), forecast, basePrices, file->baseCurrency() );
+ m_incomeItem->setOpen(true);
+ m_expenseItem = new KMyMoneyAccountTreeForecastItem( m_totalItem, file->expense(), forecast, basePrices, file->baseCurrency());
+ m_expenseItem->setOpen(true);
+}
+
+void KForecastView::addTotalRow(KMyMoneyAccountTreeForecast* forecastList, const MyMoneyForecast& forecast)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ m_totalItem = new KMyMoneyAccountTreeForecastItem( forecastList, file->asset(), forecast, file->baseCurrency(), i18n("Total") );
+ m_totalItem->setOpen(true);
+}
+
+bool KForecastView::includeAccount(MyMoneyForecast& forecast, const MyMoneyAccount& acc)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if( forecast.isForecastAccount(acc) )
+ return true;
+
+ QStringList accounts = acc.accountList();
+
+ if(accounts.size() > 0) {
+ QStringList::ConstIterator it_acc;
+ for(it_acc = accounts.begin(); it_acc != accounts.end(); ++it_acc) {
+ MyMoneyAccount account = file->account(*it_acc);
+ if( includeAccount(forecast, account) )
+ return true;
+ }
+ }
+ return false;
+}
+
+void KForecastView::loadAccounts(MyMoneyForecast& forecast, const MyMoneyAccount& account, KMyMoneyAccountTreeForecastItem* parentItem, int forecastType )
+{
+ QMap<QString, QString> nameIdx;
+ QStringList accList;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ KMyMoneyAccountTreeForecastItem *forecastItem = 0;
+
+ //Get all accounts of the right type to calculate forecast
+ accList = account.accountList();
+
+ if(accList.size() == 0)
+ return;
+
+ QStringList::ConstIterator accList_t;
+ for(accList_t = accList.begin(); accList_t != accList.end(); ++accList_t ) {
+ MyMoneyAccount subAccount = file->account(*accList_t);
+ //only add the account if it is a forecast account or the parent of a forecast account
+ if(includeAccount(forecast, subAccount)) {
+ nameIdx[subAccount.id()] = subAccount.id();
+ }
+ }
+
+ QMap<QString, QString>::ConstIterator it_nc;
+ for(it_nc = nameIdx.begin(); it_nc != nameIdx.end(); ++it_nc) {
+
+ const MyMoneyAccount subAccount = file->account(*it_nc);
+ MyMoneySecurity currency;
+ if(subAccount.isInvest()) {
+ MyMoneySecurity underSecurity = file->security(subAccount.currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security(subAccount.currencyId());
+ }
+
+ QString amount;
+ QString vAmount;
+ MyMoneyMoney vAmountMM;
+
+ //get prices
+ QValueList<MyMoneyPrice> prices = getAccountPrices(subAccount);
+
+ forecastItem = new KMyMoneyAccountTreeForecastItem( parentItem, subAccount, forecast, prices, currency, static_cast<KMyMoneyAccountTreeForecastItem::EForecastViewType>(forecastType) );
+ forecastItem->setOpen(true);
+
+ loadAccounts(forecast, subAccount, forecastItem, forecastType);
+ }
+}
+
+void KForecastView::loadChartView(void)
+{
+ MyMoneyReport::EDetailLevel detailLevel[4] = { MyMoneyReport::eDetailAll, MyMoneyReport::eDetailTop, MyMoneyReport::eDetailGroup, MyMoneyReport::eDetailTotal };
+
+ MyMoneyReport reportCfg = MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::userDefined, // overridden by the setDateFilter() call below
+ detailLevel[m_comboDetail->currentItem()],
+ i18n("Networth Forecast"),
+ i18n("Generated Report"));
+
+ reportCfg.setChartByDefault(true);
+ reportCfg.setChartGridLines(false);
+ reportCfg.setChartType(MyMoneyReport::eChartLine);
+ reportCfg.setIncludingSchedules( false );
+ reportCfg.addAccountGroup(MyMoneyAccount::Asset);
+ reportCfg.addAccountGroup(MyMoneyAccount::Liability);
+ reportCfg.setColumnsAreDays( true );
+ reportCfg.setConvertCurrency( true );
+ reportCfg.setIncludingForecast( true );
+ reportCfg.setDateFilter(QDate::currentDate(),QDate::currentDate().addDays(m_forecastDays->value()));
+
+ reports::PivotTable table(reportCfg);
+
+ table.drawChart(*m_forecastChart);
+
+ // Adjust the size
+ m_forecastChart->resize(m_tab->width()-30, m_tab->height()-60);
+
+ m_forecastChart->update();
+}
+
+#include "kforecastview.moc"
diff --git a/kmymoney2/views/kforecastview.h b/kmymoney2/views/kforecastview.h
new file mode 100644
index 0000000..8beb24a
--- /dev/null
+++ b/kmymoney2/views/kforecastview.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+ kforecastview.h
+ -------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KFORECASTVIEW_H
+#define KFORECASTVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyutils.h>
+
+#include "../views/kforecastviewdecl.h"
+#include "../widgets/kmymoneyaccounttreeforecast.h"
+#include "../reports/kreportchartview.h"
+
+using namespace reports;
+
+/**
+ * @author Alvaro Soliverez
+ */
+
+/**
+ * This class implements the forecast 'view'.
+ */
+class KForecastView : public KForecastViewDecl
+{
+ Q_OBJECT
+private:
+
+public:
+ KForecastView(QWidget *parent=0, const char *name=0);
+ virtual ~KForecastView();
+
+ void show(void);
+
+public slots:
+ void slotLoadForecast(void);
+ void slotManualForecast(void);
+
+protected:
+ typedef enum {
+ SummaryView = 0,
+ ListView,
+ AdvancedView,
+ BudgetView,
+ ChartView,
+ // insert new values above this line
+ MaxViewTabs
+ } ForecastViewTab;
+
+ QMap<QString, QString> m_nameIdx;
+
+
+ /**
+ * This method loads the forecast view.
+ */
+ void loadForecast(ForecastViewTab tab);
+
+ /**
+ * This method loads the detailed view
+ */
+ void loadListView(void);
+
+ /**
+ * This method loads the summary view
+ */
+ void loadSummaryView(void);
+
+ /**
+ * This method loads the advanced view
+ */
+ void loadAdvancedView(void);
+
+ /**
+ * This method loads the budget view
+ */
+ void loadBudgetView(void);
+
+ /**
+ * This method loads the budget view
+ */
+ void loadChartView(void);
+
+ /**
+ * This method loads the settings from user configuration
+ */
+ void loadForecastSettings(void);
+
+protected slots:
+ void slotTabChanged(QWidget*);
+
+ /**
+ * Get the list of prices for an account
+ * This is used later to create an instance of KMyMoneyAccountTreeForecastItem
+ *
+ */
+ QValueList<MyMoneyPrice> getAccountPrices(const MyMoneyAccount& acc);
+
+private:
+ void addAssetLiabilityRows(const MyMoneyForecast& forecast);
+ void addIncomeExpenseRows(const MyMoneyForecast& forecast);
+ void addTotalRow(KMyMoneyAccountTreeForecast* forecastList, const MyMoneyForecast& forecast);
+ bool includeAccount(MyMoneyForecast& forecast, const MyMoneyAccount& acc);
+ void loadAccounts(MyMoneyForecast& forecast, const MyMoneyAccount& account, KMyMoneyAccountTreeForecastItem* parentItem, int forecastType);
+
+ bool m_needReload[MaxViewTabs];
+ KMyMoneyAccountTreeForecastItem* m_totalItem;
+ KMyMoneyAccountTreeForecastItem* m_assetItem;
+ KMyMoneyAccountTreeForecastItem* m_liabilityItem;
+ KMyMoneyAccountTreeForecastItem* m_incomeItem;
+ KMyMoneyAccountTreeForecastItem* m_expenseItem;
+
+ KReportChartView* m_forecastChart;
+
+};
+
+#endif
diff --git a/kmymoney2/views/kforecastviewdecl.ui b/kmymoney2/views/kforecastviewdecl.ui
new file mode 100644
index 0000000..6d2bf3b
--- /dev/null
+++ b/kmymoney2/views/kforecastviewdecl.ui
@@ -0,0 +1,614 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KForecastViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KForecastViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>909</width>
+ <height>771</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Forecast Settings</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Days to Forecast:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_forecastDays</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Days of Accounts Cycle:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_accountsCycle</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Day of Month to start Forecast:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>m_beginDay</cstring>
+ </property>
+ <property name="maxValue">
+ <number>31</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Historic Cycles:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>m_forecastCycles</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Chart Detail:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="4" column="1">
+ <item>
+ <property name="text">
+ <string>All</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Top-Level</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Groups</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Totals</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboDetail</cstring>
+ </property>
+ <property name="currentItem">
+ <number>2</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose what level of detail to show on the chart.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout76</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Current Forecast Method:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_forecastMethod</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>method</string>
+ </property>
+ </widget>
+ </hbox>
+ <widget class="QButtonGroup" row="2" column="0">
+ <property name="name">
+ <cstring>m_historyMethod</cstring>
+ </property>
+ <property name="title">
+ <string>History Forecast Method</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton11</cstring>
+ </property>
+ <property name="text">
+ <string>Simple Moving Average</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton12</cstring>
+ </property>
+ <property name="text">
+ <string>Weighted Moving Average</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton12</cstring>
+ </property>
+ <property name="text">
+ <string>Linear Regression</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>6</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout75</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_forecastButton</cstring>
+ </property>
+ <property name="text">
+ <string>Forecast</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer22</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_saveButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_tab</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>summary</cstring>
+ </property>
+ <attribute name="title">
+ <string>Summary</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneyAccountTreeForecast">
+ <column>
+ <property name="text">
+ <string>Account</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>0 days</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>30 days</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>60 days</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>90 days</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_summaryList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>2</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="midLineWidth">
+ <number>1</number>
+ </property>
+ <property name="resizePolicy">
+ <enum>AutoOneFit</enum>
+ </property>
+ </widget>
+ <widget class="QTextEdit">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_adviceText</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="resizePolicy">
+ <enum>AutoOneFit</enum>
+ </property>
+ </widget>
+ </hbox>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ </hbox>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>detail</cstring>
+ </property>
+ <attribute name="title">
+ <string>Detail</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KMyMoneyAccountTreeForecast">
+ <property name="name">
+ <cstring>m_forecastList</cstring>
+ </property>
+ <property name="resizePolicy">
+ <enum>AutoOneFit</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>advanced</cstring>
+ </property>
+ <attribute name="title">
+ <string>Advanced</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>m_advancedList</cstring>
+ </property>
+ <property name="resizePolicy">
+ <enum>AutoOneFit</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>budget</cstring>
+ </property>
+ <attribute name="title">
+ <string>Budget Forecast</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KMyMoneyAccountTreeForecast">
+ <property name="name">
+ <cstring>m_budgetList</cstring>
+ </property>
+ <property name="resizePolicy">
+ <enum>AutoOneFit</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_tabChart</cstring>
+ </property>
+ <attribute name="title">
+ <string>Chart</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>m_layoutChart</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KMyMoneyAccountTreeforecast</class>
+ <header location="local">../widgets/kmymoneyaccounttreeforecast.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </customwidget>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kgloballedgerview.cpp b/kmymoney2/views/kgloballedgerview.cpp
new file mode 100644
index 0000000..bf95e50
--- /dev/null
+++ b/kmymoney2/views/kgloballedgerview.cpp
@@ -0,0 +1,1461 @@
+/***************************************************************************
+ kgloballedgerview.cpp - description
+ -------------------
+ begin : Wed Jul 26 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <typeinfo>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qframe.h>
+#include <qlayout.h>
+#include <qtimer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kpassivepopup.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kgloballedgerview.h"
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccountcombo.h>
+#include <kmymoney/kmymoneytitlelabel.h>
+#include <kmymoney/register.h>
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/selectedtransaction.h>
+
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "../widgets/registersearchline.h"
+#include "../dialogs/ksortoptiondlg.h"
+#include "../kmymoney2.h"
+
+#include "../widgets/scheduledtransaction.h"
+
+class KGlobalLedgerView::Private
+{
+public:
+ Private();
+
+ MousePressFilter* m_mousePressFilter;
+ KMyMoneyRegister::RegisterSearchLineWidget* m_registerSearchLine;
+ QPoint m_startPoint;
+ QString m_reconciliationAccount;
+ QDate m_reconciliationDate;
+ MyMoneyMoney m_endingBalance;
+ int m_precision;
+ bool m_inLoading;
+ bool m_recursion;
+ bool m_showDetails;
+ KMyMoneyRegister::Action m_action;
+ QTimer m_viewPosTimer;
+};
+
+MousePressFilter::MousePressFilter(QWidget* parent, const char* name) :
+ QObject(parent, name),
+ m_lastMousePressEvent(0),
+ m_filterActive(true)
+{
+}
+
+void MousePressFilter::addWidget(QWidget* w)
+{
+ m_parents.append(w);
+}
+
+void MousePressFilter::setFilterActive(bool state)
+{
+ m_filterActive = state;
+}
+
+bool MousePressFilter::isChildOf( QWidget* child, QWidget *parent )
+{
+ while(child) {
+ if(child == parent)
+ return true;
+ // If one of the ancestors is a KPassivePopup then it's as
+ // if it is a child of our own
+ if(dynamic_cast<KPassivePopup*>(child))
+ return true;
+ child = child->parentWidget();
+ }
+ return false;
+}
+
+bool MousePressFilter::eventFilter(QObject* o, QEvent* e)
+{
+ if(m_filterActive) {
+ if(e->type() == QEvent::MouseButtonPress && !m_lastMousePressEvent) {
+ QValueList<QWidget*>::const_iterator it_w;
+ for(it_w = m_parents.begin(); it_w != m_parents.end(); ++it_w) {
+ if(isChildOf((QWidget*)o, (*it_w))) {
+ m_lastMousePressEvent = e;
+ break;
+ }
+ }
+ if(it_w == m_parents.end()) {
+ m_lastMousePressEvent = e;
+ bool rc = false;
+ emit mousePressedOnExternalWidget(rc);
+ }
+ }
+
+ if(e->type() != QEvent::MouseButtonPress) {
+ m_lastMousePressEvent = 0;
+ }
+ }
+ return false;
+}
+
+
+KGlobalLedgerView::Private::Private() :
+ m_mousePressFilter(0),
+ m_registerSearchLine(0),
+ m_inLoading(false),
+ m_recursion(false),
+ m_showDetails(false)
+{
+}
+
+QDate KGlobalLedgerView::m_lastPostDate;
+
+KGlobalLedgerView::KGlobalLedgerView(QWidget *parent, const char *name )
+ : KMyMoneyViewBase(parent, name, i18n("Ledgers")),
+ d(new Private),
+ m_needReload(false),
+ m_newAccountLoaded(true),
+ m_inEditMode(false)
+{
+ d->m_mousePressFilter = new MousePressFilter((QWidget*)this);
+ d->m_action = KMyMoneyRegister::ActionNone;;
+
+ // create the toolbar frame at the top of the view
+ m_toolbarFrame = new QFrame(this);
+ QVBoxLayout* toolbarLayout = new QVBoxLayout(m_toolbarFrame, 0, 0);
+
+ m_toolbar = new KToolBar(m_toolbarFrame, 0, true);
+ toolbarLayout->addWidget(m_toolbar);
+ m_toolbar->setIconText(KToolBar::IconTextRight);
+
+ m_accountComboBox = new KMyMoneyAccountCombo(m_toolbar, "AccountCombo");
+ m_toolbar->insertWidget(1, 100, m_accountComboBox);
+
+#if 0
+ // the account button at the right of the toolbar
+ // I leave the code commented here for a while, so that I see
+ // how I can add other widgets at this point
+ KIconLoader *il = KGlobal::iconLoader();
+ m_toolbar->insertButton(il->loadIcon("document", KIcon::Small, KIcon::SizeSmall),
+ 1,true,i18n("Account"));
+ //m_toolbar->setMaximumSize(50,20);
+ m_toolbar->alignItemRight(1);
+#endif
+ m_toolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ layout()->addWidget(m_toolbarFrame);
+
+ // create the register frame
+ m_registerFrame = new QFrame(this);
+ QVBoxLayout* registerFrameLayout = new QVBoxLayout(m_registerFrame, 0, 0);
+ layout()->addWidget(m_registerFrame);
+ layout()->setStretchFactor(m_registerFrame, 2);
+ m_register = new KMyMoneyRegister::Register(m_registerFrame);
+ registerFrameLayout->addWidget(m_register);
+ m_register->installEventFilter(this);
+ connect(m_register, SIGNAL(openContextMenu()), this, SIGNAL(openContextMenu()));
+ connect(m_register, SIGNAL(headerClicked()), this, SLOT(slotSortOptions()));
+ connect(m_register, SIGNAL(reconcileStateColumnClicked(KMyMoneyRegister::Transaction*)), this, SLOT(slotToggleTransactionMark(KMyMoneyRegister::Transaction*)));
+ connect(&d->m_viewPosTimer, SIGNAL(timeout()), this, SLOT(slotUpdateViewPos()));
+
+ // insert search line widget
+
+ d->m_registerSearchLine = new KMyMoneyRegister::RegisterSearchLineWidget(m_register, m_toolbar);
+ m_toolbar->setStretchableWidget(d->m_registerSearchLine);
+
+ // create the summary frame
+ m_summaryFrame = new QFrame(this);
+ QHBoxLayout* summaryFrameLayout = new QHBoxLayout(m_summaryFrame, 0, 0);
+ m_leftSummaryLabel = new QLabel(m_summaryFrame);
+ m_centerSummaryLabel = new QLabel(m_summaryFrame);
+ m_rightSummaryLabel = new QLabel(m_summaryFrame);
+ summaryFrameLayout->addWidget(m_leftSummaryLabel);
+ QSpacerItem* spacer = new QSpacerItem( 20, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ summaryFrameLayout->addItem(spacer);
+ summaryFrameLayout->addWidget(m_centerSummaryLabel);
+ spacer = new QSpacerItem( 20, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ summaryFrameLayout->addItem(spacer);
+ summaryFrameLayout->addWidget(m_rightSummaryLabel);
+ layout()->addWidget(m_summaryFrame);
+
+ // create the button frame
+ m_buttonFrame = new QFrame(this);
+ QVBoxLayout* buttonLayout = new QVBoxLayout(m_buttonFrame, 0, 0);
+ layout()->addWidget(m_buttonFrame);
+ m_buttonbar = new KToolBar(m_buttonFrame, 0, true);
+ m_buttonbar->setIconText(KToolBar::IconTextRight);
+ buttonLayout->addWidget(m_buttonbar);
+
+ kmymoney2->action("transaction_new")->plug(m_buttonbar);
+ kmymoney2->action("transaction_delete")->plug(m_buttonbar);
+ kmymoney2->action("transaction_edit")->plug(m_buttonbar);
+ kmymoney2->action("transaction_enter")->plug(m_buttonbar);
+ kmymoney2->action("transaction_cancel")->plug(m_buttonbar);
+ kmymoney2->action("transaction_accept")->plug(m_buttonbar);
+ kmymoney2->action("transaction_match")->plug(m_buttonbar);
+
+ // create the transaction form frame
+ m_formFrame = new QFrame(this);
+ QVBoxLayout* frameLayout = new QVBoxLayout(m_formFrame, 5, 0);
+ m_form = new KMyMoneyTransactionForm::TransactionForm(m_formFrame);
+ frameLayout->addWidget(m_form->tabBar(m_formFrame));
+ frameLayout->addWidget(m_form);
+ m_formFrame->setFrameShape( QFrame::Panel );
+ m_formFrame->setFrameShadow( QFrame::Raised );
+ layout()->addWidget(m_formFrame);
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadView()));
+ connect(m_register, SIGNAL(focusChanged(KMyMoneyRegister::Transaction*)), m_form, SLOT(slotSetTransaction(KMyMoneyRegister::Transaction*)));
+ connect(m_register, SIGNAL(focusChanged()), kmymoney2, SLOT(slotUpdateActions()));
+ connect(m_accountComboBox, SIGNAL(accountSelected(const QString&)), this, SLOT(slotSelectAccount(const QString&)));
+ connect(m_register, SIGNAL(selectionChanged(const KMyMoneyRegister::SelectedTransactions&)), this, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(m_register, SIGNAL(editTransaction()), this, SIGNAL(startEdit()));
+ connect(m_register, SIGNAL(emptyItemSelected()), this, SLOT(slotNewTransaction()));
+ connect(m_register, SIGNAL(aboutToSelectItem(KMyMoneyRegister::RegisterItem*, bool&)), this, SLOT(slotAboutToSelectItem(KMyMoneyRegister::RegisterItem*, bool&)));
+ connect(d->m_mousePressFilter, SIGNAL(mousePressedOnExternalWidget(bool&)), this, SIGNAL(cancelOrEndEdit(bool&)));
+
+ connect(m_form, SIGNAL(newTransaction(KMyMoneyRegister::Action)), this, SLOT(slotNewTransaction(KMyMoneyRegister::Action)));
+
+ // setup mouse press filter
+ d->m_mousePressFilter->addWidget(m_formFrame);
+ d->m_mousePressFilter->addWidget(m_buttonFrame);
+ d->m_mousePressFilter->addWidget(m_summaryFrame);
+ d->m_mousePressFilter->addWidget(m_registerFrame);
+}
+
+KGlobalLedgerView::~KGlobalLedgerView()
+{
+ delete d;
+}
+
+void KGlobalLedgerView::slotAboutToSelectItem(KMyMoneyRegister::RegisterItem* item, bool& okToSelect)
+{
+ Q_UNUSED(item);
+ emit cancelOrEndEdit(okToSelect);
+}
+
+void KGlobalLedgerView::slotLoadView(void)
+{
+ m_needReload = true;
+ if(isVisible()) {
+ if(!m_inEditMode) {
+ loadView();
+ m_needReload = false;
+ // force a new account if the current one is empty
+ m_newAccountLoaded = m_account.id().isEmpty();
+ }
+ }
+}
+
+void KGlobalLedgerView::clear(void)
+{
+ // clear current register contents
+ m_register->clear();
+
+ // setup header font
+ QFont font = KMyMoneyGlobalSettings::listHeaderFont();
+ QFontMetrics fm( font );
+ int height = fm.lineSpacing()+6;
+ m_register->horizontalHeader()->setMinimumHeight(height);
+ m_register->horizontalHeader()->setMaximumHeight(height);
+ m_register->horizontalHeader()->setFont(font);
+
+ // setup cell font
+ font = KMyMoneyGlobalSettings::listCellFont();
+ m_register->setFont(font);
+
+ // clear the form
+ m_form->clear();
+
+ // the selected transactions list
+ m_transactionList.clear();
+
+ // and the selected account in the combo box
+ m_accountComboBox->setSelected(QString());
+
+ // fraction defaults to two digits
+ d->m_precision = 2;
+}
+
+void KGlobalLedgerView::loadView(void)
+{
+ MYMONEYTRACER(tracer);
+
+ // setup form visibility
+ m_formFrame->setShown(KMyMoneyGlobalSettings::transactionForm());
+
+ // no account selected
+ emit accountSelected(MyMoneyAccount());
+ // no transaction selected
+ KMyMoneyRegister::SelectedTransactions list;
+ emit transactionsSelected(list);
+
+ QMap<QString, bool> isSelected;
+ QString focusItemId;
+ QString anchorItemId;
+
+ if(!d->m_inLoading)
+ d->m_startPoint = QPoint(-1, -1);
+
+ if(!m_newAccountLoaded) {
+ // remember the current selected transactions
+ KMyMoneyRegister::RegisterItem* item = m_register->firstItem();
+ for(; item; item = item->nextItem()) {
+ if(item->isSelected()) {
+ isSelected[item->id()] = true;
+ }
+ }
+ // remember the item that has the focus
+ if(m_register->focusItem())
+ focusItemId = m_register->focusItem()->id();
+ // and the one that has the selection anchor
+ if(m_register->anchorItem())
+ anchorItemId = m_register->anchorItem()->id();
+
+ // remember the upper left corner of the viewport
+ if(!d->m_inLoading && d->m_showDetails == KMyMoneyGlobalSettings::showRegisterDetailed())
+ d->m_startPoint = QPoint(m_register->contentsX(), m_register->contentsY());
+ } else {
+ if(d->m_viewPosTimer.isActive())
+ d->m_viewPosTimer.stop();
+ d->m_startPoint = QPoint(-1, -1);
+ d->m_inLoading = false;
+ d->m_registerSearchLine->searchLine()->reset();
+ }
+
+ // clear the current contents ...
+ clear();
+
+ // ... load the combobox widget and select current account ...
+ loadAccounts();
+
+ // ... setup the register columns ...
+ m_register->setupRegister(m_account);
+
+ // ... setup the form ...
+ m_form->setupForm(m_account);
+
+ if(m_account.id().isEmpty()) {
+ // if we don't have an account we bail out
+ setEnabled(false);
+ return;
+ }
+ setEnabled(true);
+
+ m_register->setUpdatesEnabled(false);
+
+ // ... and recreate it
+ KMyMoneyRegister::RegisterItem* focusItem = 0;
+ KMyMoneyRegister::RegisterItem* anchorItem = 0;
+ QMap<QString, MyMoneyMoney> actBalance, clearedBalance, futureBalance;
+ QMap<QString, MyMoneyMoney>::iterator it_b;
+ try {
+ // setup the filter to select the transactions we want to display
+ // and update the sort order
+ QString sortOrder;
+ QString key;
+ QDate reconciliationDate = d->m_reconciliationDate;
+
+ MyMoneyTransactionFilter filter(m_account.id());
+ // if it's an investment account, we also take care of
+ // the sub-accounts (stock accounts)
+ if(m_account.accountType() == MyMoneyAccount::Investment)
+ filter.addAccount(m_account.accountList());
+
+ if(isReconciliationAccount()) {
+ key = "kmm-sort-reconcile";
+ sortOrder = KMyMoneyGlobalSettings::sortReconcileView();
+ filter.addState(MyMoneyTransactionFilter::notReconciled);
+ filter.addState(MyMoneyTransactionFilter::cleared);
+ } else {
+ filter.setDateFilter(KMyMoneyGlobalSettings::startDate().date(), QDate());
+ key = "kmm-sort-std";
+ sortOrder = KMyMoneyGlobalSettings::sortNormalView();
+ if (KMyMoneyGlobalSettings::hideReconciledTransactions()
+ && !m_account.isIncomeExpense()) {
+ filter.addState(MyMoneyTransactionFilter::notReconciled);
+ filter.addState(MyMoneyTransactionFilter::cleared);
+ }
+ }
+ filter.setReportAllSplits(true);
+
+ // check if we have an account override of the sort order
+ if(!m_account.value(key).isEmpty())
+ sortOrder = m_account.value(key);
+
+ // setup sort order
+ m_register->setSortOrder(sortOrder);
+
+ // retrieve the list from the engine
+ MyMoneyFile::instance()->transactionList(m_transactionList, filter);
+
+ kmymoney2->slotStatusProgressBar(0, m_transactionList.count());
+
+ // create the elements for the register
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >::const_iterator it;
+ QMap<QString, int>uniqueMap;
+ int i = 0;
+ for(it = m_transactionList.begin(); it != m_transactionList.end(); ++it) {
+ uniqueMap[(*it).first.id()]++;
+ KMyMoneyRegister::Transaction* t = KMyMoneyRegister::Register::transactionFactory(m_register, (*it).first, (*it).second, uniqueMap[(*it).first.id()]);
+ actBalance[t->split().accountId()] = MyMoneyMoney(0,1);
+ kmymoney2->slotStatusProgressBar(++i, 0);
+ // if we're in reconciliation and the state is cleared, we
+ // force the item to show in dimmed intensity to get a visual focus
+ // on those items, that we need to work on
+ if(isReconciliationAccount() && (*it).second.reconcileFlag() == MyMoneySplit::Cleared) {
+ t->setReducedIntensity(true);
+ }
+ }
+
+ // create dummy entries for the scheduled transactions if sorted by postdate
+ int period = KMyMoneyGlobalSettings::schedulePreview();
+ if(m_register->primarySortKey() == KMyMoneyRegister::PostDateSort) {
+ // show scheduled transactions which have a scheduled postdate
+ // within the next 'period' days. In reconciliation mode, the
+ // period starts on the statement date.
+ QDate endDate = QDate::currentDate().addDays(period);
+ if(isReconciliationAccount())
+ endDate = reconciliationDate.addDays(period);
+ QValueList<MyMoneySchedule> scheduleList = MyMoneyFile::instance()->scheduleList(m_account.id());
+ while(scheduleList.count() > 0){
+ MyMoneySchedule& s = scheduleList.first();
+ for(;;) {
+ if(s.isFinished() || s.adjustedNextDueDate() > endDate) {
+ break;
+ }
+
+ MyMoneyTransaction t(s.id(), KMyMoneyUtils::scheduledTransaction(s));
+ // if the transaction is scheduled and overdue, it can't
+ // certainly be posted in the past. So we take todays date
+ // as the alternative
+ if(s.isOverdue())
+ t.setPostDate(QDate::currentDate());
+ else
+ t.setPostDate(s.adjustedNextDueDate());
+ const QValueList<MyMoneySplit>& splits = t.splits();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ if((*it_s).accountId() == m_account.id()) {
+ new KMyMoneyRegister::StdTransactionScheduled(m_register, t, *it_s, uniqueMap[t.id()]);
+ }
+ }
+ // keep track of this payment locally (not in the engine)
+ if(s.isOverdue())
+ s.setLastPayment(QDate::currentDate());
+ else
+ s.setLastPayment(s.nextDueDate());
+
+ // if this is a one time schedule, we can bail out here as we're done
+ if(s.occurence() == MyMoneySchedule::OCCUR_ONCE)
+ break;
+
+ // for all others, we check if the next payment date is still 'in range'
+ s.setNextDueDate(s.nextPayment(s.nextDueDate()));
+ }
+ scheduleList.pop_front();
+ }
+ }
+
+ // add the group markers
+ m_register->addGroupMarkers();
+
+ // sort the transactions according to the sort setting
+ m_register->sortItems();
+
+ // remove trailing and adjacent markers
+ m_register->removeUnwantedGroupMarkers();
+
+ // add special markers for reconciliation now so that they do not get
+ // removed by m_register->removeUnwantedGroupMarkers(). Needs resorting
+ // of items but that's ok.
+
+ KMyMoneyRegister::StatementGroupMarker* statement = 0;
+ KMyMoneyRegister::StatementGroupMarker* dStatement = 0;
+ KMyMoneyRegister::StatementGroupMarker* pStatement = 0;
+
+ if(isReconciliationAccount()) {
+ switch(m_register->primarySortKey()) {
+ case KMyMoneyRegister::PostDateSort:
+ statement = new KMyMoneyRegister::StatementGroupMarker(m_register, KMyMoneyRegister::Deposit, reconciliationDate, i18n("Statement Details"));
+ m_register->sortItems();
+ break;
+ case KMyMoneyRegister::TypeSort:
+ dStatement = new KMyMoneyRegister::StatementGroupMarker(m_register, KMyMoneyRegister::Deposit, reconciliationDate, i18n("Statement Deposit Details"));
+ pStatement = new KMyMoneyRegister::StatementGroupMarker(m_register, KMyMoneyRegister::Payment, reconciliationDate, i18n("Statement Payment Details"));
+ m_register->sortItems();
+ break;
+ default:
+ break;
+ }
+ }
+
+ // we need at least the balance for the account we currently show
+ actBalance[m_account.id()] = MyMoneyMoney();
+
+ if(m_account.accountType() == MyMoneyAccount::Investment) {
+ QValueList<QString>::const_iterator it_a;
+ for(it_a = m_account.accountList().begin(); it_a != m_account.accountList().end(); ++it_a) {
+ actBalance[*it_a] = MyMoneyMoney();
+ }
+ }
+
+ // determine balances (actual, cleared). We do this by getting the actual
+ // balance of all entered transactions from the engine and walk the list
+ // of transactions backward. Also re-select a transaction if it was
+ // selected before and setup the focus item.
+
+ MyMoneyMoney factor(1,1);
+ if(m_account.accountGroup() == MyMoneyAccount::Liability
+ || m_account.accountGroup() == MyMoneyAccount::Equity)
+ factor = -factor;
+
+ QMap<QString, int> deposits;
+ QMap<QString, int> payments;
+ QMap<QString, MyMoneyMoney> depositAmount;
+ QMap<QString, MyMoneyMoney> paymentAmount;
+ for(it_b = actBalance.begin(); it_b != actBalance.end(); ++it_b) {
+ MyMoneyMoney balance = MyMoneyFile::instance()->balance(it_b.key());
+ balance = balance * factor;
+ clearedBalance[it_b.key()] =
+ futureBalance[it_b.key()] =
+ (*it_b) = balance;
+ deposits[it_b.key()] = payments[it_b.key()] = 0;
+ depositAmount[it_b.key()] = MyMoneyMoney();
+ paymentAmount[it_b.key()] = MyMoneyMoney();
+ }
+
+ tracer.printf("total balance of %s = %s", m_account.name().data(), actBalance[m_account.id()].formatMoney("", 2).data());
+ tracer.printf("future balance of %s = %s", m_account.name().data(), futureBalance[m_account.id()].formatMoney("", 2).data());
+ tracer.printf("cleared balance of %s = %s", m_account.name().data(), clearedBalance[m_account.id()].formatMoney("", 2).data());
+
+ KMyMoneyRegister::RegisterItem* p = m_register->lastItem();
+ focusItem = 0;
+
+ // take care of possibly trailing scheduled transactions (bump up the future balance)
+ while(p) {
+ if(p->isSelectable()) {
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t && t->isScheduled()) {
+ MyMoneyMoney balance = futureBalance[t->split().accountId()];
+ const MyMoneySplit& split = t->split();
+ // if this split is a stock split, we can't just add the amount of shares
+ if(t->transaction().isStockSplit()) {
+ balance = balance * split.shares();
+ } else {
+ balance += split.shares() * factor;
+ }
+ futureBalance[split.accountId()] = balance;
+ } else if(t && !focusItem)
+ focusItem = p;
+ }
+ p = p->prevItem();
+ }
+
+ p = m_register->lastItem();
+ while(p) {
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t) {
+ if(isSelected.contains(t->id()))
+ t->setSelected(true);
+
+ if(t->id() == focusItemId)
+ focusItem = t;
+ if(t->id() == anchorItemId)
+ anchorItem = t;
+
+ const MyMoneySplit& split = t->split();
+ MyMoneyMoney balance = futureBalance[split.accountId()];
+ t->setBalance(balance);
+
+ // if this split is a stock split, we can't just add the amount of shares
+ if(t->transaction().isStockSplit()) {
+ balance /= split.shares();
+ } else {
+ balance -= split.shares() * factor;
+ }
+
+ if(!t->isScheduled()) {
+ if(split.reconcileFlag() == MyMoneySplit::NotReconciled) {
+ tracer.printf("Reducing cleared balance by %s because %s/%s(%s) is not reconciled", (split.shares() * factor).formatMoney("", 2).data(), t->transaction().id().data(), split.id().data(), t->transaction().postDate().toString(Qt::ISODate).data());
+ clearedBalance[split.accountId()] -= split.shares() * factor;
+ }
+ if(isReconciliationAccount() && t->transaction().postDate() > reconciliationDate && split.reconcileFlag() == MyMoneySplit::Cleared) {
+ tracer.printf("Reducing cleared balance by %s because we are in reconciliation, %s/%s(%s)'s date is after or on reconciliation date (%s) and is cleared", (split.shares() * factor).formatMoney("", 2).data(), t->transaction().id().data(), split.id().data(), t->transaction().postDate().toString(Qt::ISODate).data(), reconciliationDate.toString(Qt::ISODate).data());
+
+ clearedBalance[split.accountId()] -= split.shares() * factor;
+ }
+ if(isReconciliationAccount() && t->transaction().postDate() <= reconciliationDate && split.reconcileFlag() == MyMoneySplit::Cleared) {
+ if(split.shares().isNegative()) {
+ payments[split.accountId()]++;
+ paymentAmount[split.accountId()] += split.shares();
+ } else {
+ deposits[split.accountId()]++;
+ depositAmount[split.accountId()] += split.shares();
+ }
+ }
+
+ if(t->transaction().postDate() > QDate::currentDate()) {
+ tracer.printf("Reducing actual balance by %s because %s/%s(%s) is in the future", (split.shares() * factor).formatMoney("", 2).data(), t->transaction().id().data(), split.id().data(), t->transaction().postDate().toString(Qt::ISODate).data());
+ actBalance[split.accountId()] -= split.shares() * factor;
+ }
+ }
+ futureBalance[split.accountId()] = balance;
+ }
+ p = p->prevItem();
+ }
+
+ tracer.printf("total balance of %s = %s", m_account.name().data(), actBalance[m_account.id()].formatMoney("", 2).data());
+ tracer.printf("future balance of %s = %s", m_account.name().data(), futureBalance[m_account.id()].formatMoney("", 2).data());
+ tracer.printf("cleared balance of %s = %s", m_account.name().data(), clearedBalance[m_account.id()].formatMoney("", 2).data());
+
+ // update statement information
+ if(statement) {
+ statement->setText(i18n("%1 deposits (%3), %2 payments (%4)").
+ arg(deposits[m_account.id()]).
+ arg(payments[m_account.id()]).
+ arg(depositAmount[m_account.id()].abs().formatMoney(m_account.fraction())).
+ arg(paymentAmount[m_account.id()].abs().formatMoney(m_account.fraction())) );
+ }
+ if(pStatement) {
+ pStatement->setText(i18n("%1 payments (%2)").arg(payments[m_account.id()]).
+ arg(paymentAmount[m_account.id()].abs().formatMoney(m_account.fraction())) );
+ }
+ if(dStatement) {
+ dStatement->setText(i18n("%1 deposits (%2)").arg(deposits[m_account.id()]).
+ arg(depositAmount[m_account.id()].abs().formatMoney(m_account.fraction())) );
+ }
+
+ // add a last empty entry for new transactions
+ // leave some information about the current account
+ MyMoneySplit split;
+ split.setReconcileFlag(MyMoneySplit::NotReconciled);
+ // make sure to use the value specified in the option during reconciliation
+ if(isReconciliationAccount())
+ split.setReconcileFlag(static_cast<MyMoneySplit::reconcileFlagE>(KMyMoneyGlobalSettings::defaultReconciliationState()));
+ KMyMoneyRegister::Register::transactionFactory(m_register, MyMoneyTransaction(), split, 0);
+
+ m_register->updateRegister(true);
+
+ if(focusItem) {
+ // in case we have some selected items we just set the focus item
+ // in other cases, we make the focusitem also the selected item
+ if(isSelected.count() > 1) {
+ m_register->setFocusItem(focusItem);
+ m_register->setAnchorItem(anchorItem);
+ } else
+ m_register->selectItem(focusItem, true);
+ } else {
+ // just use the empty line at the end if nothing else exists in the ledger
+ p = m_register->lastItem();
+ m_register->setFocusItem(p);
+ m_register->selectItem(p);
+ focusItem = p;
+ }
+
+ updateSummaryLine(actBalance, clearedBalance);
+ kmymoney2->slotStatusProgressBar(-1, -1);
+
+ } catch(MyMoneyException *e) {
+ delete e;
+ m_account = MyMoneyAccount();
+ clear();
+ }
+
+ // (re-)position viewport
+ if(m_newAccountLoaded) {
+ if(focusItem) {
+ d->m_startPoint = QPoint(-1, -1);
+ } else {
+ d->m_startPoint = QPoint(0, 0);
+ }
+ }
+ if(!d->m_inLoading) {
+ d->m_viewPosTimer.start(30, true);
+ d->m_inLoading = true;
+ }
+
+ d->m_showDetails = KMyMoneyGlobalSettings::showRegisterDetailed();
+
+ // and tell everyone what's selected
+ emit accountSelected(m_account);
+}
+
+void KGlobalLedgerView::updateSummaryLine(const QMap<QString, MyMoneyMoney>& actBalance, const QMap<QString, MyMoneyMoney>& clearedBalance)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ m_leftSummaryLabel->show();
+ m_centerSummaryLabel->show();
+ m_rightSummaryLabel->show();
+
+ if(isReconciliationAccount()) {
+ if(m_account.accountType() != MyMoneyAccount::Investment) {
+ m_leftSummaryLabel->setText(i18n("Statement: %1").arg(d->m_endingBalance.formatMoney("", d->m_precision)));
+ m_centerSummaryLabel->setText(i18n("Cleared: %1").arg(clearedBalance[m_account.id()].formatMoney("", d->m_precision)));
+ m_rightSummaryLabel->setText(i18n("Difference: %1").arg((clearedBalance[m_account.id()] - d->m_endingBalance).formatMoney("", d->m_precision)));
+ }
+ } else {
+ // update summary line in normal mode
+ QDate reconcileDate = m_account.lastReconciliationDate();
+
+ if(reconcileDate.isValid()) {
+ m_leftSummaryLabel->setText(i18n("Last reconciled: %1").arg(KGlobal::locale()->formatDate(reconcileDate, true)));
+ } else {
+ m_leftSummaryLabel->setText(i18n("Never reconciled"));
+ }
+
+ m_rightSummaryLabel->setPaletteForegroundColor(m_leftSummaryLabel->paletteForegroundColor());
+ if(m_account.accountType() != MyMoneyAccount::Investment) {
+ m_centerSummaryLabel->setText(i18n("Cleared: %1").arg(clearedBalance[m_account.id()].formatMoney("", d->m_precision)));
+ m_rightSummaryLabel->setText(i18n("Balance: %1").arg(actBalance[m_account.id()].formatMoney("", d->m_precision)));
+ bool showNegative = actBalance[m_account.id()].isNegative();
+ if(m_account.accountGroup() == MyMoneyAccount::Liability && !actBalance[m_account.id()].isZero())
+ showNegative = !showNegative;
+ if(showNegative) {
+ m_rightSummaryLabel->setPaletteForegroundColor(KMyMoneyGlobalSettings::listNegativeValueColor());
+ }
+ } else {
+ m_centerSummaryLabel->hide();
+ MyMoneyMoney balance;
+ MyMoneySecurity base = file->baseCurrency();
+ QMap<QString, MyMoneyMoney>::const_iterator it_b;
+ bool approx = false;
+ for(it_b = actBalance.begin(); it_b != actBalance.end(); ++it_b) {
+ MyMoneyAccount stock = file->account(it_b.key());
+ QString currencyId = stock.currencyId();
+ MyMoneySecurity sec = file->security(currencyId);
+ MyMoneyPrice priceInfo;
+ MyMoneyMoney rate(1,1);
+
+ if(stock.isInvest()) {
+ currencyId = sec.tradingCurrency();
+ priceInfo = file->price(sec.id(), currencyId);
+ approx |= !priceInfo.isValid();
+ rate = priceInfo.rate(sec.tradingCurrency());
+ }
+
+ if(currencyId != base.id()) {
+ priceInfo = file->price(sec.tradingCurrency(), base.id());
+ approx |= !priceInfo.isValid();
+ rate = (rate * priceInfo.rate(base.id())).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()));
+ }
+ balance += ((*it_b) * rate).convert(base.smallestAccountFraction());
+ }
+ m_rightSummaryLabel->setText(i18n("Investment value: %1%2").arg(approx ? "~" : "").arg(balance.formatMoney(base.tradingSymbol(), d->m_precision)));
+ }
+ }
+}
+
+void KGlobalLedgerView::slotUpdateViewPos(void)
+{
+ m_register->setUpdatesEnabled(true);
+
+ if(d->m_startPoint == QPoint(-1, -1)) {
+ m_register->ensureItemVisible(m_register->focusItem());
+ m_register->updateContents();
+ } else {
+ m_register->setContentsPos(d->m_startPoint.x(), d->m_startPoint.y());
+ m_register->repaintContents();
+ }
+ d->m_inLoading = false;
+}
+
+
+void KGlobalLedgerView::resizeEvent(QResizeEvent* ev)
+{
+ m_register->resize(KMyMoneyRegister::DetailColumn);
+ m_form->resize(KMyMoneyTransactionForm::ValueColumn1);
+ KMyMoneyViewBase::resizeEvent(ev);
+}
+
+void KGlobalLedgerView::loadAccounts(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // check if the current account still exists and make it the
+ // current account
+ if(!m_account.id().isEmpty()) {
+ try {
+ m_account = file->account(m_account.id());
+ } catch(MyMoneyException *e) {
+ delete e;
+ m_account = MyMoneyAccount();
+ }
+ }
+
+ m_accountComboBox->loadList((KMyMoneyUtils::categoryTypeE)(KMyMoneyUtils::asset | KMyMoneyUtils::liability));
+
+ if(m_account.id().isEmpty()) {
+ QStringList list = m_accountComboBox->accountList();
+ if(list.count()) {
+ QStringList::Iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ MyMoneyAccount a = file->account(*it);
+ if(!a.isInvest()) {
+ if(a.value("PreferredAccount") == "Yes") {
+ m_account = a;
+ break;
+ } else if(m_account.id().isEmpty()) {
+ m_account = a;
+ }
+ }
+ }
+ }
+ }
+
+ if(!m_account.id().isEmpty()) {
+ m_accountComboBox->setSelected(m_account);
+ try {
+ d->m_precision = MyMoneyMoney::denomToPrec(m_account.fraction());
+ } catch(MyMoneyException *e) {
+ qDebug("Security %s for account %s not found", m_account.currencyId().data(), m_account.name().data());
+ delete e;
+ d->m_precision = 2;
+ }
+ }
+}
+
+void KGlobalLedgerView::selectTransaction(const QString& id)
+{
+ if(!id.isEmpty()) {
+ KMyMoneyRegister::RegisterItem* p = m_register->lastItem();
+ while(p) {
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t) {
+ if(t->transaction().id() == id) {
+ m_register->selectItem(t);
+ m_register->ensureItemVisible(t);
+ break;
+ }
+ }
+ p = p->prevItem();
+ }
+ }
+}
+
+void KGlobalLedgerView::slotSelectAllTransactions(void)
+{
+ KMyMoneyRegister::RegisterItem* p = m_register->firstItem();
+ while(p) {
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t) {
+ if(t->isVisible() && t->isSelectable() && !t->isScheduled() && !t->id().isEmpty()) {
+ t->setSelected(true);
+ }
+ }
+ p = p->nextItem();
+ }
+ m_register->repaintItems();
+
+ // inform everyone else about the selected items
+ KMyMoneyRegister::SelectedTransactions list(m_register);
+ emit transactionsSelected(list);
+}
+
+void KGlobalLedgerView::slotSetReconcileAccount(const MyMoneyAccount& acc, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance)
+{
+ if(d->m_reconciliationAccount != acc.id()) {
+ // make sure the account is selected
+ if(!acc.id().isEmpty())
+ slotSelectAccount(acc.id());
+
+ d->m_reconciliationAccount = acc.id();
+ d->m_reconciliationDate = reconciliationDate;
+ d->m_endingBalance = endingBalance;
+ if(acc.accountGroup() == MyMoneyAccount::Liability)
+ d->m_endingBalance = -endingBalance;
+
+ m_newAccountLoaded = true;
+ if(acc.id().isEmpty()) {
+ kmymoney2->action("account_reconcile_postpone")->unplug(m_buttonbar);
+ kmymoney2->action("account_reconcile_finish")->unplug(m_buttonbar);
+ } else {
+ kmymoney2->action("account_reconcile_postpone")->plug(m_buttonbar);
+ kmymoney2->action("account_reconcile_finish")->plug(m_buttonbar);
+ // when we start reconciliation, we need to reload the view
+ // because no data has been changed. When postponing or finishing
+ // reconciliation, the data change in the engine takes care of updateing
+ // the view.
+ slotLoadView();
+ }
+ }
+}
+
+bool KGlobalLedgerView::isReconciliationAccount(void) const
+{
+ return m_account.id() == d->m_reconciliationAccount;
+}
+
+bool KGlobalLedgerView::slotSelectAccount(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyAccount))
+ return false;
+
+ if(d->m_recursion)
+ return false;
+
+ d->m_recursion = true;
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(obj);
+ bool rc = slotSelectAccount(acc.id());
+ d->m_recursion = false;
+ return rc;
+}
+
+bool KGlobalLedgerView::slotSelectAccount(const QString& id, const QString& transactionId)
+{
+ bool rc = true;
+
+ if(!id.isEmpty()) {
+ if(m_account.id() != id) {
+ try {
+ m_account = MyMoneyFile::instance()->account(id);
+ // if a stock account is selected, we show the
+ // the corresponding parent (investment) account
+ if(m_account.isInvest()) {
+ m_account = MyMoneyFile::instance()->account(m_account.parentAccountId());
+ }
+ m_newAccountLoaded = true;
+ slotLoadView();
+ } catch(MyMoneyException* e) {
+ qDebug("Unable to retrieve account %s", id.data());
+ delete e;
+ rc = false;
+ }
+ } else {
+ // we need to refresh m_account.m_accountList, a child could have been deleted
+ m_account = MyMoneyFile::instance()->account(id);
+ emit accountSelected(m_account);
+ }
+ selectTransaction(transactionId);
+ }
+ return rc;
+}
+
+void KGlobalLedgerView::slotNewTransaction(KMyMoneyRegister::Action id)
+{
+ if(!m_inEditMode) {
+ d->m_action = id;
+ emit newTransaction();
+ }
+}
+
+void KGlobalLedgerView::slotNewTransaction(void)
+{
+ slotNewTransaction(KMyMoneyRegister::ActionNone);
+}
+
+void KGlobalLedgerView::setupDefaultAction(void)
+{
+ switch(m_account.accountType()) {
+ // TODO if we want a different action for different account types
+ // we can add cases here
+ default:
+ d->m_action = KMyMoneyRegister::ActionWithdrawal;
+ break;
+ }
+}
+
+bool KGlobalLedgerView::selectEmptyTransaction(void)
+{
+ bool rc = false;
+
+ if(!m_inEditMode) {
+ // in case we don't know the type of transaction to be created,
+ // have at least one selected transaction and the id of
+ // this transaction is not empty, we take it as template for the
+ // transaction to be created
+ KMyMoneyRegister::SelectedTransactions list(m_register);
+ if((d->m_action == KMyMoneyRegister::ActionNone) && (list.count() > 0) && (!list[0].transaction().id().isEmpty())) {
+ // the new transaction to be created will have the same type
+ // as the one that currently has the focus
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(m_register->focusItem());
+ if(t)
+ d->m_action = t->actionType();
+ m_register->clearSelection();
+ }
+
+ // if we still don't have an idea which type of transaction
+ // to create, we use the default.
+ if(d->m_action == KMyMoneyRegister::ActionNone) {
+ setupDefaultAction();
+ }
+
+ m_register->selectItem(m_register->lastItem());
+ m_register->updateRegister();
+ rc = true;
+ }
+ return rc;
+}
+
+TransactionEditor* KGlobalLedgerView::startEdit(const KMyMoneyRegister::SelectedTransactions& list)
+{
+ // we use the warnlevel to keep track, if we have to warn the
+ // user that some or all splits have been reconciled or if the
+ // user cannot modify the transaction if at least one split
+ // has the status frozen. The following value are used:
+ //
+ // 0 - no sweat, user can modify
+ // 1 - user should be warned that at least one split has been reconciled
+ // already
+ // 2 - user will be informed, that this transaction cannot be changed anymore
+
+ int warnLevel = list.warnLevel();
+ Q_ASSERT(warnLevel<2); // otherwise the edit action should not be enabled
+
+ switch(warnLevel) {
+ case 0:
+ break;
+
+ case 1:
+ if(KMessageBox::warningContinueCancel(0,
+ i18n(
+ "At least one split of the selected transactions has been reconciled. "
+ "Do you wish to continue to edit the transactions anyway?"
+ ),
+ i18n("Transaction already reconciled"), KStdGuiItem::cont(),
+ "EditReconciledTransaction") == KMessageBox::Cancel) {
+ warnLevel = 2;
+ }
+ break;
+
+ case 2:
+ KMessageBox::sorry(0,
+ i18n("At least one split of the selected transactions has been frozen. "
+ "Editing the transactions is therefore prohibited."),
+ i18n("Transaction already frozen"));
+ break;
+
+ case 3:
+ KMessageBox::sorry(0,
+ i18n("At least one split of the selected transaction references an account that has been closed. "
+ "Editing the transactions is therefore prohibited."),
+ i18n("Account closed"));
+ break;
+ }
+
+ if(warnLevel > 1)
+ return 0;
+
+
+ TransactionEditor* editor = 0;
+ KMyMoneyRegister::Transaction* item = dynamic_cast<KMyMoneyRegister::Transaction*>(m_register->focusItem());
+
+ if(item) {
+ // in case the current focus item is not selected, we move the focus to the first selected transaction
+ if(!item->isSelected()) {
+ KMyMoneyRegister::RegisterItem* p;
+ for(p = m_register->firstItem(); p; p = p->nextItem()) {
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t && t->isSelected()) {
+ m_register->setFocusItem(t);
+ item = t;
+ break;
+ }
+ }
+ }
+
+ // decide, if we edit in the register or in the form
+ TransactionEditorContainer* parent;
+ if(m_formFrame->isVisible())
+ parent = m_form;
+ else {
+ parent = m_register;
+ }
+
+ editor = item->createEditor(parent, list, m_lastPostDate);
+
+ // check that we use the same transaction commodity in all selected transactions
+ // if not, we need to update this in the editor's list. The user can also bail out
+ // of this operation which means that we have to stop editing here.
+ if(editor) {
+ if(!editor->fixTransactionCommodity(m_account)) {
+ // if the user wants to quit, we need to destroy the editor
+ // and bail out
+ delete editor;
+ editor = 0;
+ }
+ }
+
+ if(editor) {
+ if(parent == m_register) {
+ // make sure, the height of the table is correct
+ m_register->updateRegister(KMyMoneyGlobalSettings::ledgerLens() | !KMyMoneyGlobalSettings::transactionForm());
+ }
+
+ m_inEditMode = true;
+ connect(editor, SIGNAL(transactionDataSufficient(bool)), kmymoney2->action("transaction_enter"), SLOT(setEnabled(bool)));
+ connect(editor, SIGNAL(returnPressed()), kmymoney2->action("transaction_enter"), SLOT(activate()));
+ connect(editor, SIGNAL(escapePressed()), kmymoney2->action("transaction_cancel"), SLOT(activate()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets()));
+ connect(editor, SIGNAL(finishEdit(const KMyMoneyRegister::SelectedTransactions&)), this, SLOT(slotLeaveEditMode(const KMyMoneyRegister::SelectedTransactions&)));
+
+ connect(editor, SIGNAL(objectCreation(bool)), d->m_mousePressFilter, SLOT(setFilterDeactive(bool)));
+ connect(editor, SIGNAL(createPayee(const QString&, QString&)), kmymoney2, SLOT(slotPayeeNew(const QString&, QString&)));
+ connect(editor, SIGNAL(createCategory(MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotCategoryNew(MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(editor, SIGNAL(createSecurity(MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotInvestmentNew(MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(editor, SIGNAL(assignNumber(void)), kmymoney2, SLOT(slotTransactionAssignNumber()));
+ connect(editor, SIGNAL(lastPostDateUsed(const QDate&)), this, SLOT(slotKeepPostDate(const QDate&)));
+
+ // create the widgets, place them in the parent and load them with data
+ // setup tab order
+ m_tabOrderWidgets.clear();
+ editor->setup(m_tabOrderWidgets, m_account, d->m_action);
+
+ Q_ASSERT(!m_tabOrderWidgets.isEmpty());
+
+ // install event filter in all taborder widgets
+ for(QWidget* w = m_tabOrderWidgets.first(); w; w = m_tabOrderWidgets.next()) {
+ w->installEventFilter(this);
+ }
+
+ // Install a filter that checks if a mouse press happened outside
+ // of one of our own widgets.
+ qApp->installEventFilter(d->m_mousePressFilter);
+
+ // Check if the editor has some preference on where to set the focus
+ // If not, set the focus to the first widget in the tab order
+ QWidget* focusWidget = editor->firstWidget();
+ if(!focusWidget)
+ focusWidget = m_tabOrderWidgets.first();
+
+ // for some reason, this only works reliably if delayed a bit
+ QTimer::singleShot(10, focusWidget, SLOT(setFocus()));
+
+ // preset to 'I have no idea which type to create' for the next round.
+ d->m_action = KMyMoneyRegister::ActionNone;
+ }
+ }
+ return editor;
+}
+
+void KGlobalLedgerView::slotLeaveEditMode(const KMyMoneyRegister::SelectedTransactions& list)
+{
+ m_inEditMode = false;
+ qApp->removeEventFilter(d->m_mousePressFilter);
+
+ // a possible focusOut event may have removed the focus, so we
+ // install it back again.
+ m_register->focusItem()->setFocus(true);
+
+ // if we come back from editing a new item, we make sure that
+ // we always select the very last known transaction entry no
+ // matter if the transaction has been created or not.
+
+ if(list.count() && list[0].transaction().id().isEmpty()) {
+ // block signals to prevent some infinite loops that might occur here.
+ m_register->blockSignals(true);
+ m_register->clearSelection();
+ KMyMoneyRegister::RegisterItem* p = m_register->lastItem();
+ if(p && p->prevItem())
+ p = p->prevItem();
+ m_register->selectItem(p);
+ m_register->updateRegister(true);
+ m_register->blockSignals(false);
+ // we need to update the form manually as sending signals was blocked
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t)
+ m_form->slotSetTransaction(t);
+ }
+
+ if(m_needReload)
+ slotLoadView();
+
+ m_register->setFocus();
+}
+
+bool KGlobalLedgerView::focusNextPrevChild(bool next)
+{
+ bool rc = false;
+
+ // qDebug("KGlobalLedgerView::focusNextPrevChild(editmode=%s)", m_inEditMode ? "true" : "false");
+ if(m_inEditMode) {
+ QWidget *w = 0;
+ QWidget *currentWidget;
+
+ w = qApp->focusWidget();
+ while(w && m_tabOrderWidgets.find(w) == -1) {
+ // qDebug("'%s' not in list, use parent", w->className());
+ w = w->parentWidget();
+ }
+ // if(w) qDebug("tab order is at '%s'", w->className());
+ currentWidget = m_tabOrderWidgets.current();
+ w = next ? m_tabOrderWidgets.next() : m_tabOrderWidgets.prev();
+
+ do {
+ if(!w) {
+ w = next ? m_tabOrderWidgets.first() : m_tabOrderWidgets.last();
+ }
+
+ if(w != currentWidget
+ && ((w->focusPolicy() & TabFocus) == TabFocus)
+ && w->isVisible() && w->isEnabled()) {
+ // qDebug("Selecting '%s' as focus", w->className());
+ w->setFocus();
+ rc = true;
+ break;
+ }
+ w = next ? m_tabOrderWidgets.next() : m_tabOrderWidgets.prev();
+ } while(w != currentWidget);
+
+ } else
+ rc = KMyMoneyViewBase::focusNextPrevChild(next);
+
+ return rc;
+}
+
+
+void KGlobalLedgerView::show(void)
+{
+ if(m_needReload) {
+ if(!m_inEditMode) {
+ loadView();
+ m_needReload = false;
+ m_newAccountLoaded = false;
+ }
+
+ } else {
+ emit accountSelected(m_account);
+ KMyMoneyRegister::SelectedTransactions list(m_register);
+ emit transactionsSelected(list);
+ }
+
+ // don't forget base class implementation
+ KMyMoneyViewBase::show();
+}
+
+bool KGlobalLedgerView::eventFilter(QObject* o, QEvent* e)
+{
+ bool rc = false;
+
+ if(e->type() == QEvent::KeyPress) {
+ QKeyEvent *k = static_cast<QKeyEvent*>(e);
+ if(m_inEditMode) {
+ // qDebug("object = %s, key = %d", o->className(), k->key());
+ if(o == m_register) {
+ // we hide all key press events from the register
+ // while editing a transaction
+ rc = true;
+ }
+ } else {
+ // qDebug("object = %s, key = %d", o->className(), k->key());
+ if(o == m_register) {
+ if((k->state() & Qt::KeyButtonMask) == 0) {
+ switch(k->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ kmymoney2->action("transaction_edit")->activate();
+ rc = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(!rc)
+ rc = KMyMoneyViewBase::eventFilter(o, e);
+
+ return rc;
+}
+
+void KGlobalLedgerView::slotSortOptions(void)
+{
+ KSortOptionDlg* dlg = new KSortOptionDlg(this);
+
+ QString key;
+ QString sortOrder, def;
+ if(isReconciliationAccount()) {
+ key = "kmm-sort-reconcile";
+ def = KMyMoneyGlobalSettings::sortReconcileView();
+ } else {
+ key = "kmm-sort-std";
+ def = KMyMoneyGlobalSettings::sortNormalView();
+ }
+
+ // check if we have an account override of the sort order
+ if(!m_account.value(key).isEmpty())
+ sortOrder = m_account.value(key);
+
+ QString oldOrder = sortOrder;
+
+ dlg->setSortOption(sortOrder, def);
+
+ if(dlg->exec() == QDialog::Accepted) {
+ sortOrder = dlg->sortOption();
+ if(sortOrder != oldOrder) {
+ if(sortOrder.isEmpty()) {
+ m_account.deletePair(key);
+ } else {
+ m_account.setValue(key, sortOrder);
+ }
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->modifyAccount(m_account);
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ qDebug("Unable to update sort order for account '%s': %s", m_account.name().latin1(), e->what().latin1());
+ delete e;
+ }
+ }
+ }
+ delete dlg;
+}
+
+void KGlobalLedgerView::slotToggleTransactionMark(KMyMoneyRegister::Transaction* /* t */)
+{
+ if(!m_inEditMode) {
+ emit toggleReconciliationFlag();
+ }
+}
+
+void KGlobalLedgerView::slotKeepPostDate(const QDate& date)
+{
+ m_lastPostDate = date;
+}
+
+bool KGlobalLedgerView::canCreateTransactions(QString& tooltip) const
+{
+ bool rc = true;
+ if(m_account.id().isEmpty()) {
+ tooltip = i18n("Cannot create transactions when no account is selected.");
+ rc = false;
+ }
+ if(m_account.accountGroup() == MyMoneyAccount::Income
+ || m_account.accountGroup() == MyMoneyAccount::Expense) {
+ tooltip = i18n("Cannot create transactions in the context of a category.");
+ rc = false;
+ }
+ if(m_account.isClosed()) {
+ tooltip = i18n("Cannot create transactions in a closed account.");
+ rc = false;
+ }
+ return rc;
+}
+
+bool KGlobalLedgerView::canProcessTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ if(m_register->focusItem() == 0)
+ return false;
+
+ if(!m_register->focusItem()->isSelected()) {
+ tooltip = i18n("Cannot process transaction with focus if it is not selected.");
+ return false;
+ }
+ return list.count() > 0;
+}
+
+bool KGlobalLedgerView::canModifyTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ return canProcessTransactions(list,tooltip) && list.canModify();
+}
+
+bool KGlobalLedgerView::canDuplicateTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ return canProcessTransactions(list,tooltip) && list.canDuplicate();
+}
+
+bool KGlobalLedgerView::canEditTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ // check if we can edit the list of transactions. We can edit, if
+ //
+ // a) no mix of standard and investment transactions exist
+ // b) if a split transaction is selected, this is the only selection
+ // c) none of the splits is frozen
+ // d) the transaction having the current focus is selected
+
+ // check for d)
+ if(!canProcessTransactions(list, tooltip))
+ return false;
+ // check for c)
+ if (list.warnLevel() == 2) {
+ tooltip = i18n("Cannot edit transactions with frozen splits.");
+ return false;
+ }
+
+
+ bool rc = true;
+ int investmentTransactions = 0;
+ int normalTransactions = 0;
+
+ if(m_account.accountGroup() == MyMoneyAccount::Income
+ || m_account.accountGroup() == MyMoneyAccount::Expense) {
+ tooltip = i18n("Cannot edit transactions in the context of a category.");
+ rc = false;
+ }
+
+ KMyMoneyRegister::SelectedTransactions::const_iterator it_t;
+ for(it_t = list.begin(); rc && it_t != list.end(); ++it_t) {
+ if((*it_t).transaction().id().isEmpty()) {
+ tooltip = QString();
+ rc = false;
+ continue;
+ }
+
+ if(KMyMoneyUtils::transactionType((*it_t).transaction()) == KMyMoneyUtils::InvestmentTransaction)
+ ++investmentTransactions;
+ else
+ ++normalTransactions;
+
+ // check for a)
+ if(investmentTransactions != 0 && normalTransactions != 0) {
+ tooltip = i18n("Cannot edit investment transactions and non-investment transactions together.");
+ rc = false;
+ break;
+ }
+
+ // check for b) but only for normalTransactions
+ if((*it_t).transaction().splitCount() > 2 && normalTransactions != 0) {
+ if(list.count() > 1) {
+ tooltip = i18n("Cannot edit multiple split transactions at once.");
+ rc = false;
+ break;
+ }
+ }
+ }
+
+ // now check that we have the correct account type for investment transactions
+ if(rc == true && investmentTransactions != 0) {
+ if(m_account.accountType() != MyMoneyAccount::Investment) {
+ tooltip = i18n("Cannot edit investment transactions in the context of this account.");
+ rc = false;
+ }
+ }
+ return rc;
+}
+
+#include "kgloballedgerview.moc"
diff --git a/kmymoney2/views/kgloballedgerview.h b/kmymoney2/views/kgloballedgerview.h
new file mode 100644
index 0000000..861bd0e
--- /dev/null
+++ b/kmymoney2/views/kgloballedgerview.h
@@ -0,0 +1,403 @@
+/***************************************************************************
+ kgloballedgerview.h - description
+ -------------------
+ begin : Sat Jul 13 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KACCOUNTVIEW_H
+#define KACCOUNTVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qwidgetlist.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyview.h>
+#include <kmymoney/register.h>
+#include <kmymoney/transactionform.h>
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QPopupMenu;
+class QFrame;
+class QLabel;
+
+class KMyMoneyAccountCombo;
+class KToolBar;
+class KToolBarButton;
+class MyMoneyReport;
+class TransactionEditor;
+
+/**
+ * helper class implementing an event filter to detect mouse button press
+ * events on widgets outside a given set of widgets. This is used internally
+ * to detect when to leave the edit mode.
+ */
+class MousePressFilter : public QObject
+{
+ Q_OBJECT
+public:
+ MousePressFilter(QWidget* parent = 0, const char* name = 0);
+
+ /**
+ * Add widget @p w to the list of possible parent objects. See eventFilter() how
+ * they will be used.
+ */
+ void addWidget(QWidget* w);
+
+public slots:
+ /**
+ * This slot allows to activate/deactive the filter. By default the
+ * filter is active.
+ *
+ * @param state Allows to activate (@a true) or deactivate (@a false) the filter
+ */
+ void setFilterActive(bool state = true);
+
+ /**
+ * This slot allows to activate/deactive the filter. By default the
+ * filter is active.
+ *
+ * @param state Allows to deactivate (@a true) or activate (@a false) the filter
+ */
+ void setFilterDeactive(bool state = false) { setFilterActive(!state); }
+
+protected:
+ /**
+ * This method checks if the widget @p child is a child of
+ * the widget @p parent and returns either @a true or @a false.
+ *
+ * @param child pointer to child widget
+ * @param parent pointer to parent widget
+ * @retval true @p child points to widget which has @p parent as parent or grand-parent
+ * @retval false @p child points to a widget which is not related to @p parent
+ */
+ bool isChildOf(QWidget* child, QWidget* parent);
+
+ /**
+ * Reimplemented from base class. Sends out the mousePressedOnExternalWidget() signal
+ * if object @p o points to an object which is not a child widget of any added previously
+ * using the addWidget() method. The signal is sent out only once for each event @p e.
+ *
+ * @param o pointer to QObject
+ * @param e pointer to QEvent
+ * @return always returns @a false
+ */
+ bool eventFilter(QObject* o, QEvent* e);
+
+signals:
+ void mousePressedOnExternalWidget(bool&);
+
+private:
+ QValueList<QWidget*> m_parents;
+ QEvent* m_lastMousePressEvent;
+ bool m_filterActive;
+};
+
+/**
+ * @author Thomas Baumgart
+ */
+class KGlobalLedgerView : public KMyMoneyViewBase
+{
+ Q_OBJECT
+public:
+ KGlobalLedgerView(QWidget *parent=0, const char *name=0);
+ ~KGlobalLedgerView();
+
+ /**
+ * This method returns the id of the currently selected account
+ * or QString() if none is selected.
+ */
+ const QString accountId(void) const { return m_account.id(); }
+
+ /**
+ * Checks if new transactions can be created in the current context
+ *
+ * @param tooltip reference to string receiving the tooltip text
+ * which explains why the modify function is not available (in case
+ * of returning @c false)
+ *
+ * @retval true Yes, view allows to create transactions (tooltip is not changed)
+ * @retval false No, view does not support creation of transactions (tooltip is updated with message)
+ */
+ bool canCreateTransactions(QString& tooltip) const;
+
+ /**
+ * Checks if a list of transactions can be modified (edit/delete) in the current context
+ *
+ * @param list list of selected transactions
+ * @param tooltip reference to string receiving the tooltip text
+ * which explains why the modify function is not available (in case
+ * of returning @c false)
+ *
+ * @retval true Yes, view allows to edit/delete transactions (tooltip is not changed)
+ * @retval false No, view cannot edit/delete transactions (tooltip is updated with message)
+ */
+ bool canModifyTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ bool canDuplicateTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ /**
+ * Checks if the list of transactions can be edited in the current context
+ *
+ * @param list list of selected transactions
+ * @param tooltip reference to string receiving the tooltip text
+ * which explains why the edit function is not available (in case
+ * of returning @c false)
+ *
+ * @return @c true if edit operation is possible, @c false if not
+ */
+ bool canEditTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ TransactionEditor* startEdit(const KMyMoneyRegister::SelectedTransactions& list);
+
+ /**
+ * Method to prepare the ledger view to create a new transaction.
+ * Returns if successful or not.
+ *
+ * retval true Emtpy transaction selected.
+ * retval false Not successful (e.g. already editing a transaction)
+ */
+ bool selectEmptyTransaction(void);
+
+public slots:
+ void show(void);
+
+ /**
+ * This method loads the view with data from the MyMoney engine.
+ */
+ void slotLoadView(void);
+
+ /**
+ * This slot is used to select the correct ledger view type for
+ * the account specified by @p id in a specific mode.
+ *
+ * @param accountId Internal id used for the account to show
+ * @param transactionId Internal id used for the transaction to select.
+ * Default is QString() which will select the last
+ * transaction in the ledger if not the same account
+ *
+ * @retval true selection of account referenced by @p id succeeded
+ * @retval false selection of account failed
+ */
+ bool slotSelectAccount(const QString& accountId, const QString& transactionId = QString());
+
+ /**
+ * This method is provided for convenience and acts as the method above.
+ */
+ bool slotSelectAccount(const MyMoneyObject& acc);
+
+ /**
+ * Switch to reconciliation mode for account @a account.
+ * If @a account is MyMoneyAccount() (the default), reconciliation mode
+ * is turned off.
+ *
+ * @param account account for which reconciliation mode is activated.
+ * Default is MyMoneyAccount().
+ * @param reconciliationDate date of statment
+ * @param endingBalance The calculated ending balance for the statement
+ * Default ist 0.
+ */
+ void slotSetReconcileAccount(const MyMoneyAccount& account = MyMoneyAccount(), const QDate& reconciliationDate = QDate(), const MyMoneyMoney& endingBalance = MyMoneyMoney());
+
+ /**
+ * Select all transactions in the ledger that are not hidden.
+ */
+ void slotSelectAllTransactions(void);
+
+protected:
+ /**
+ * This method reloads the account selection combo box of the
+ * view with all asset and liability accounts from the engine.
+ * If the account id of the current account held in @p m_accountId is
+ * empty or if the referenced account does not exist in the engine,
+ * the first account found in the list will be made the current account.
+ */
+ void loadAccounts(void);
+
+ /**
+ * This method clears the register, form, transaction list. See @sa m_register,
+ * @sa m_transactionList
+ */
+ void clear(void);
+
+ void loadView(void);
+
+ void resizeEvent(QResizeEvent*);
+
+ void selectTransaction(const QString& id);
+
+ /**
+ * This method handles the focus of the keyboard. When in edit mode
+ * (m_inEditMode is true) the keyboard focus is handled
+ * according to the widgets that are referenced in m_tabOrderWidgets.
+ * If not in edit mode, the base class functionality is provided.
+ *
+ * @param next true if forward-tab, false if backward-tab was
+ * pressed by the user
+ */
+ bool focusNextPrevChild(bool next);
+
+ bool eventFilter(QObject* o, QEvent* e);
+
+ /**
+ * Returns @a true if setReconciliationAccount() has been called for
+ * the current loaded account.
+ *
+ * @retval true current account is in reconciliation mode
+ * @retval false current account is not in reconciliation mode
+ */
+ bool isReconciliationAccount(void) const;
+
+ /**
+ * Updates the values on the summary line beneath the register with
+ * the given values. The contents shown differs between reconciliation
+ * mode and normal mode.
+ *
+ * @param actBalance map of account indexed values to be used as actual balance
+ * @param clearedBalance map of account indexed values to be used as cleared balance
+ */
+ void updateSummaryLine(const QMap<QString, MyMoneyMoney>& actBalance, const QMap<QString, MyMoneyMoney>& clearedBalance);
+
+ /**
+ * setup the default action according to the current account type
+ */
+ void setupDefaultAction(void);
+
+protected slots:
+ void slotLeaveEditMode(const KMyMoneyRegister::SelectedTransactions& list);
+ void slotNewTransaction(void);
+ void slotNewTransaction(KMyMoneyRegister::Action);
+
+ /**
+ * Sets the contentsPos of the register to d->m_startPoint or makes
+ * the focus item visible if d->m_startPoint equals QPoint(-1, -1).
+ */
+ void slotUpdateViewPos(void);
+ void slotSortOptions(void);
+ void slotToggleTransactionMark(KMyMoneyRegister::Transaction* t);
+
+ void slotKeepPostDate(const QDate&);
+
+ void slotAboutToSelectItem(KMyMoneyRegister::RegisterItem*, bool&);
+
+protected:
+ /**
+ * This member keeps the date that was used as the last posting date.
+ * It will be updated whenever the user modifies the post date
+ * and is used to preset the posting date when new transactions are created.
+ * This member is initialised to the current date when the program is started.
+ */
+ static QDate m_lastPostDate;
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ // frames
+ QFrame* m_toolbarFrame;
+ QFrame* m_registerFrame;
+ QFrame* m_buttonFrame;
+ QFrame* m_formFrame;
+ QFrame* m_summaryFrame;
+
+ // widgets
+ KMyMoneyAccountCombo* m_accountComboBox;
+ KMyMoneyRegister::Register* m_register;
+ KToolBar* m_toolbar;
+ KToolBar* m_buttonbar;
+
+ /**
+ * This member holds the currently selected account
+ */
+ MyMoneyAccount m_account;
+
+ /**
+ * This member holds the transaction list
+ */
+ QValueList<QPair<MyMoneyTransaction, MyMoneySplit> > m_transactionList;
+
+ QLabel* m_leftSummaryLabel;
+ QLabel* m_centerSummaryLabel;
+ QLabel* m_rightSummaryLabel;
+
+ KMyMoneyTransactionForm::TransactionForm* m_form;
+
+ bool m_needReload;
+ bool m_newAccountLoaded;
+ bool m_inEditMode;
+
+ QWidgetList m_tabOrderWidgets;
+
+signals:
+ void accountSelected(const MyMoneyObject&);
+ void transactionsSelected(const KMyMoneyRegister::SelectedTransactions&);
+ void newTransaction(void);
+ void startEdit(void);
+ void endEdit(void);
+ void cancelOrEndEdit(bool&);
+
+ /**
+ * This signal is emitted, when a new report has been generated. A
+ * 'generated' report is halfway between a default report and a custom
+ * report. It's created by the system in response to the user's
+ * request, and it's usually filtered to be a little more specific
+ * than the usual default reports.
+ *
+ * The proper behaviour when getting this signal is to switch to the
+ * reports view and display the report. But it should NOT be added
+ * to the data file, unless the user customizes it further. That's
+ * because the user can always come back to the ledger UI to generate
+ * the report again.
+ *
+ * @param report reference to MyMoneyReport object that contains the report
+ * details
+ */
+ void reportGenerated(const MyMoneyReport& report);
+
+ void openContextMenu(void);
+
+ /**
+ * This signal is sent out, when the current selected transaction should
+ * be marked different
+ */
+ void toggleReconciliationFlag(void);
+
+private:
+ bool canProcessTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/views/khomeview.cpp b/kmymoney2/views/khomeview.cpp
new file mode 100644
index 0000000..95b7323
--- /dev/null
+++ b/kmymoney2/views/khomeview.cpp
@@ -0,0 +1,1940 @@
+/***************************************************************************
+ khomeview.cpp - description
+ -------------------
+ begin : Tue Jan 22 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qdatetime.h>
+#include <qapplication.h>
+#include <dom/dom_element.h>
+#include <dom/dom_doc.h>
+#include <dom/dom_text.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qbuffer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <khtmlview.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kmainwindow.h>
+#include <kactioncollection.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "khomeview.h"
+#include "../kmymoneyutils.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../mymoney/mymoneyforecast.h"
+#include "../kmymoney2.h"
+#include "../reports/kreportchartview.h"
+#include "../reports/pivottable.h"
+#include "../reports/pivotgrid.h"
+#include "../reports/reportaccount.h"
+#include "../kmymoneyglobalsettings.h"
+
+
+#define VIEW_LEDGER "ledger"
+#define VIEW_SCHEDULE "schedule"
+#define VIEW_WELCOME "welcome"
+#define VIEW_HOME "home"
+#define VIEW_REPORTS "reports"
+
+// in KOffice version < 1.5 KDCHART_PROPSET_NORMAL_DATA was a static const
+// but in 1.5 this has been changed into a #define'd value. So we have to
+// make sure, we use the right one.
+#ifndef KDCHART_PROPSET_NORMAL_DATA
+#define KMM_KDCHART_PROPSET_NORMAL_DATA KDChartParams::KDCHART_PROPSET_NORMAL_DATA
+#else
+#define KMM_KDCHART_PROPSET_NORMAL_DATA KDCHART_PROPSET_NORMAL_DATA
+#endif
+
+using namespace reports;
+
+class KHomeView::Private
+{
+ public:
+ Private() {}
+ void addNameIndex(QMap<QString, MyMoneyAccount> &idx, const MyMoneyAccount& account);
+};
+
+void KHomeView::Private::addNameIndex(QMap<QString, MyMoneyAccount> &idx, const MyMoneyAccount& account)
+{
+ QString key = account.name();
+
+ if(idx[key].id().isEmpty()) {
+ idx[key] = account;
+ //take care of accounts with duplicate names
+ } else if(idx[key].id() != account.id()) {
+ key = account.name() + "[%1]";
+ int dup = 2;
+ while(!idx[key.arg(dup)].id().isEmpty()
+ && idx[key.arg(dup)].id() != account.id())
+ ++dup;
+ idx[key.arg(dup)] = account;
+ }
+}
+
+KHomeView::KHomeView(QWidget *parent, const char *name ) :
+ KMyMoneyViewBase(parent, name, i18n("Home")),
+ d(new Private),
+ m_showAllSchedules(false),
+ m_needReload(true)
+{
+ m_part = new KHTMLPart(this, "htmlpart_km2");
+ addWidget(m_part->view());
+
+ m_filename = KMyMoneyUtils::findResource("appdata", QString("html/home%1.html"));
+
+// m_part->openURL(m_filename);
+ connect(m_part->browserExtension(), SIGNAL(openURLRequest(const KURL&, const KParts::URLArgs&)),
+ this, SLOT(slotOpenURL(const KURL&, const KParts::URLArgs&)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadView()));
+}
+
+KHomeView::~KHomeView()
+{
+ // if user wants to remember the font size, store it here
+ if (KMyMoneyGlobalSettings::rememberFontSize())
+ {
+ KMyMoneyGlobalSettings::setFontSizePercentage(m_part->zoomFactor());
+ //kdDebug() << "Storing font size: " << m_part->zoomFactor() << endl;
+ KMyMoneyGlobalSettings::self()->writeConfig();
+ }
+ delete d;
+}
+
+void KHomeView::slotLoadView(void)
+{
+ m_needReload = true;
+ if(isVisible()) {
+ loadView();
+ m_needReload = false;
+ }
+}
+
+void KHomeView::show(void)
+{
+ if(m_needReload) {
+ loadView();
+ m_needReload = false;
+ }
+ QWidget::show();
+}
+
+void KHomeView::slotPrintView(void)
+{
+ if(m_part && m_part->view())
+ m_part->view()->print();
+}
+
+void KHomeView::loadView(void)
+{
+ m_part->setZoomFactor( KMyMoneyGlobalSettings::fontSizePercentage() );
+ //kdDebug() << "Setting font size: " << m_part->zoomFactor() << endl;
+
+ QValueList<MyMoneyAccount> list;
+ MyMoneyFile::instance()->accountList(list);
+ if(list.count() == 0)
+ {
+ m_part->openURL(m_filename);
+
+#if 0
+ // (ace) I am experimenting with replacing links in the
+ // html depending on the state of the engine. It's not
+ // working. That's why it's #if0'd out.
+
+ DOM::Element e = m_part->document().getElementById("test");
+ if ( e.isNull() )
+ {
+ qDebug("Element id=test not found");
+ }
+ else
+ {
+ qDebug("Element id=test found!");
+ QString tagname = e.tagName().string();
+ qDebug("%s",tagname.latin1());
+ qDebug("%s id=%s",e.tagName().string().latin1(),e.getAttribute("id").string().latin1());
+
+ // Find the character data node
+ DOM::Node n = e.firstChild();
+ while (!n.isNull())
+ {
+ qDebug("Child type %u",static_cast<unsigned>(n.nodeType()));
+ if ( n.nodeType() == DOM::Node::TEXT_NODE )
+ {
+ DOM::Text t = n;
+ t.setData("Success!!");
+ e.replaceChild(n,t);
+ m_part->document().setDesignMode(true);
+ m_part->document().importNode(e,true);
+ m_part->document().updateRendering();
+
+ qDebug("Data is now %s",t.data().string().latin1());
+ }
+ n = n.nextSibling();
+ }
+ }
+#endif
+ } else {
+ //clear the forecast flag so it will be reloaded
+ m_forecast.setForecastDone(false);
+
+ QString filename = KGlobal::dirs()->findResource("appdata", "html/kmymoney2.css");
+ QString header = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"%1\">\n").arg(filename);
+
+ header += KMyMoneyUtils::variableCSS();
+
+ header += "</head><body id=\"summaryview\">\n";
+
+ QString footer = "</body></html>\n";
+
+ m_part->begin();
+ m_part->write(header);
+
+ m_part->write(QString("<div id=\"summarytitle\">%1</div>").arg(i18n("Your Financial Summary")));
+
+ QStringList settings = KMyMoneyGlobalSettings::itemList();
+
+ QStringList::ConstIterator it;
+
+ for(it = settings.begin(); it != settings.end(); ++it) {
+ int option = (*it).toInt();
+ if(option > 0) {
+ switch(option) {
+ case 1: // payments
+ showPayments();
+ break;
+
+ case 2: // preferred accounts
+ showAccounts(Preferred, i18n("Preferred Accounts"));
+ break;
+
+ case 3: // payment accounts
+ // Check if preferred accounts are shown separately
+ if(settings.find("2") == settings.end()) {
+ showAccounts(static_cast<paymentTypeE> (Payment | Preferred),
+ i18n("Payment Accounts"));
+ } else {
+ showAccounts(Payment, i18n("Payment Accounts"));
+ }
+ break;
+ case 4: // favorite reports
+ showFavoriteReports();
+ break;
+ case 5: // forecast
+ showForecast();
+ break;
+ case 6: // net worth graph over all accounts
+ showNetWorthGraph();
+ break;
+ case 8: // assets and liabilities
+ showAssetsLiabilities();
+ break;
+ case 9: // budget
+ showBudget();
+ break;
+ case 10: // cash flow summary
+ showCashFlowSummary();
+ break;
+
+
+ }
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+ }
+ }
+
+ m_part->write("<div id=\"returnlink\">");
+ m_part->write(link(VIEW_WELCOME, QString()) + i18n("Show KMyMoney welcome page") + linkend());
+ m_part->write("</div>");
+ m_part->write("<div id=\"vieweffect\"></div>");
+ m_part->write(footer);
+ m_part->end();
+
+ }
+}
+
+void KHomeView::showNetWorthGraph(void)
+{
+#ifdef HAVE_KDCHART
+ m_part->write(QString("<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">%1</div>\n<div class=\"gap\">&nbsp;</div>\n").arg(i18n("Networth Forecast")));
+
+ MyMoneyReport reportCfg = MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::userDefined, // overridden by the setDateFilter() call below
+ MyMoneyReport::eDetailTotal,
+ i18n("Networth Forecast"),
+ i18n("Generated Report"));
+
+ reportCfg.setChartByDefault(true);
+ reportCfg.setChartGridLines(false);
+ reportCfg.setChartDataLabels(false);
+ reportCfg.setChartType(MyMoneyReport::eChartLine);
+ reportCfg.setIncludingSchedules( false );
+ reportCfg.addAccountGroup(MyMoneyAccount::Asset);
+ reportCfg.addAccountGroup(MyMoneyAccount::Liability);
+ reportCfg.setColumnsAreDays( true );
+ reportCfg.setConvertCurrency( true );
+ reportCfg.setIncludingForecast( true );
+ reportCfg.setDateFilter(QDate::currentDate(),QDate::currentDate().addDays(+90));
+
+ reports::PivotTable table(reportCfg);
+
+ reports::KReportChartView* chartWidget = new reports::KReportChartView(0, 0);
+
+ table.drawChart(*chartWidget);
+
+ chartWidget->params()->setLineMarker(false);
+ chartWidget->params()->setLegendPosition(KDChartParams::NoLegend);
+ chartWidget->params()->setLineWidth(2);
+ chartWidget->params()->setDataColor(0, KGlobalSettings::textColor());
+
+ // draw future values in a different line style
+ KDChartPropertySet propSetFutureValue("future value", KMM_KDCHART_PROPSET_NORMAL_DATA);
+ propSetFutureValue.setLineStyle(KDChartPropertySet::OwnID, Qt::DotLine);
+ const int idPropFutureValue = chartWidget->params()->registerProperties(propSetFutureValue);
+
+ //KDChartPropertySet propSetLastValue("last value", idPropFutureValue);
+ //propSetLastValue.setExtraLinesAlign(KDChartPropertySet::OwnID, Qt::AlignLeft | Qt::AlignBottom);
+ //propSetLastValue.setExtraLinesWidth(KDChartPropertySet::OwnID, -4);
+ //propSetLastValue.setExtraLinesColor(KDChartPropertySet::OwnID, KMyMoneyGlobalSettings::listGridColor());
+ // propSetLastValue.setShowMarker(KDChartPropertySet::OwnID, true);
+ // propSetLastValue.setMarkerStyle(KDChartPropertySet::OwnID, KDChartParams::LineMarkerDiamond);
+
+ //const int idPropLastValue = chartWidget->params()->registerProperties(propSetLastValue);
+ for(int iCell = 0; iCell < 90; ++iCell) {
+ chartWidget->setProperty(0, iCell, idPropFutureValue);
+ }
+ //chartWidget->setProperty(0, 10, idPropLastValue);
+
+ // Adjust the size
+ if(width() < chartWidget->width()) {
+ int nh;
+ nh = (width()*chartWidget->height() ) / chartWidget->width();
+ chartWidget->resize(width()-80, nh);
+ }
+
+ QPixmap pm(chartWidget->width(), chartWidget->height());
+ pm.fill(KGlobalSettings::baseColor());
+ QPainter p(&pm);
+ chartWidget->paintTo(p);
+
+ QByteArray ba;
+ QBuffer buffer( ba );
+ buffer.open( IO_WriteOnly );
+ pm.save( &buffer, "PNG" ); // writes pixmap into ba in PNG format
+
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write("<tr>");
+ m_part->write(QString("<td><center><IMG SRC=\"data:image/png;base64,%1\" ALT=\"Networth\"></center></td>").arg(KCodecs::base64Encode(ba)));
+ m_part->write("</tr>");
+ m_part->write("</table></div></div>");
+
+ delete chartWidget;
+#endif
+}
+
+void KHomeView::showPayments(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneySchedule> overdues;
+ QValueList<MyMoneySchedule> schedule;
+ int i = 0;
+
+ //if forecast has not been executed yet, do it.
+ if(!m_forecast.isForecastDone())
+ doForecast();
+
+ schedule = file->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate::currentDate(),
+ QDate::currentDate().addMonths(1));
+ overdues = file->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate(), QDate(), true);
+
+ if(schedule.empty() && overdues.empty())
+ return;
+
+ // HACK
+ // Remove the finished schedules
+
+ QValueList<MyMoneySchedule>::Iterator d_it;
+ for (d_it=schedule.begin(); d_it!=schedule.end();)
+ {
+ // FIXME cleanup old code
+ // if ((*d_it).isFinished() || (*d_it).nextPayment((*d_it).lastPayment()) == QDate())
+ if ((*d_it).isFinished())
+ {
+ d_it = schedule.remove(d_it);
+ continue;
+ }
+ ++d_it;
+ }
+
+ for (d_it=overdues.begin(); d_it!=overdues.end();)
+ {
+ // FIXME cleanup old code
+ // if ((*d_it).isFinished() || (*d_it).nextPayment((*d_it).lastPayment()) == QDate())
+ if ((*d_it).isFinished())
+ {
+ d_it = overdues.remove(d_it);
+ continue;
+ }
+ ++d_it;
+ }
+
+ m_part->write("<div class=\"shadow\"><div class=\"displayblock\">");
+ m_part->write(QString("<div class=\"summaryheader\">%1</div>\n").arg(i18n("Payments")));
+
+ if(overdues.count() > 0) {
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+
+ qBubbleSort(overdues);
+ QValueList<MyMoneySchedule>::Iterator it;
+ QValueList<MyMoneySchedule>::Iterator it_f;
+
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write(QString("<tr class=\"itemtitle warningtitle\" ><td colspan=\"5\">%1</td></tr>\n").arg(showColoredAmount(i18n("Overdue payments"), true)));
+ m_part->write("<tr class=\"item warning\">");
+ m_part->write("<td class=\"left\" width=\"10%\">");
+ m_part->write(i18n("Date"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"left\" width=\"40%\">");
+ m_part->write(i18n("Schedule"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"left\" width=\"20%\">");
+ m_part->write(i18n("Account"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"15%\">");
+ m_part->write(i18n("Amount"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"15%\">");
+ m_part->write(i18n("Balance after"));
+ m_part->write("</td>");
+ m_part->write("</tr>");
+
+ for(it = overdues.begin(); it != overdues.end(); ++it) {
+ // determine number of overdue payments
+ QDate nextDate = (*it).adjustedNextDueDate();
+ int cnt = 0;
+ while(nextDate.isValid() && nextDate < QDate::currentDate()) {
+ ++cnt;
+ nextDate = (*it).nextPayment(nextDate);
+ // for single occurence nextDate will not change, so we
+ // better get out of here.
+ if((*it).occurence() == MyMoneySchedule::OCCUR_ONCE)
+ break;
+ }
+
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ showPaymentEntry(*it, cnt);
+ m_part->write("</tr>");
+ // make sure to not repeat overdues later again
+ for(it_f = schedule.begin(); it_f != schedule.end();) {
+ if((*it).id() == (*it_f).id()) {
+ it_f = schedule.remove(it_f);
+ continue;
+ }
+ ++it_f;
+ }
+ }
+ m_part->write("</table>");
+ }
+
+ if(schedule.count() > 0) {
+ qBubbleSort(schedule);
+
+ // Extract todays payments if any
+ QValueList<MyMoneySchedule> todays;
+ QValueList<MyMoneySchedule>::Iterator t_it;
+ for (t_it=schedule.begin(); t_it!=schedule.end();) {
+ if ((*t_it).nextDueDate() == QDate::currentDate()) {
+ todays.append(*t_it);
+ (*t_it).setNextDueDate((*t_it).nextPayment((*t_it).nextDueDate()));
+
+ //if nextDueDate is still currentDate then remove it from scheduled payments
+ if ((*t_it).nextDueDate() == QDate::currentDate()) {
+ t_it = schedule.remove(t_it);
+ continue;
+ }
+ }
+ ++t_it;
+ }
+
+ if (todays.count() > 0) {
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write(QString("<tr class=\"itemtitle\"><td class=\"left\" colspan=\"5\">%1</td></tr>\n").arg(i18n("Today's payments")));
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td class=\"left\" width=\"10%\">");
+ m_part->write(i18n("Date"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"left\" width=\"40%\">");
+ m_part->write(i18n("Schedule"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"left\" width=\"20%\">");
+ m_part->write(i18n("Account"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"15%\">");
+ m_part->write(i18n("Amount"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"15%\">");
+ m_part->write(i18n("Balance after"));
+ m_part->write("</td>");
+ m_part->write("</tr>");
+
+ for(t_it = todays.begin(); t_it != todays.end(); ++t_it) {
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ showPaymentEntry(*t_it);
+ m_part->write("</tr>");
+ }
+ m_part->write("</table>");
+ }
+
+ if (schedule.count() > 0)
+ {
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+
+ QValueList<MyMoneySchedule>::Iterator it;
+
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write(QString("<tr class=\"itemtitle\"><td class=\"left\" colspan=\"5\">%1</td></tr>\n").arg(i18n("Future payments")));
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td class=\"left\" width=\"10%\">");
+ m_part->write(i18n("Date"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"left\" width=\"40%\">");
+ m_part->write(i18n("Schedule"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"left\" width=\"20%\">");
+ m_part->write(i18n("Account"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"15%\">");
+ m_part->write(i18n("Amount"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"15%\">");
+ m_part->write(i18n("Balance after"));
+ m_part->write("</td>");
+ m_part->write("</tr>");
+
+ // show all or the first 6 entries
+ int cnt;
+ cnt = (m_showAllSchedules) ? -1 : 6;
+ bool needMoreLess = m_showAllSchedules;
+
+ QDate lastDate = QDate::currentDate().addMonths(1);
+ qBubbleSort(schedule);
+ do {
+ it = schedule.begin();
+ if(it == schedule.end())
+ break;
+
+ // if the next due date is invalid (schedule is finished)
+ // we remove it from the list
+ QDate nextDate = (*it).nextDueDate();
+ if(!nextDate.isValid()) {
+ schedule.remove(it);
+ continue;
+ }
+
+ if (nextDate > lastDate)
+ break;
+
+ if(cnt == 0) {
+ needMoreLess = true;
+ break;
+ }
+ if(cnt > 0)
+ --cnt;
+
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ showPaymentEntry(*it);
+ m_part->write("</tr>");
+
+ // for single occurence we have reported everything so we
+ // better get out of here.
+ if((*it).occurence() == MyMoneySchedule::OCCUR_ONCE) {
+ schedule.remove(it);
+ continue;
+ }
+
+ (*it).setNextDueDate((*it).nextPayment((*it).nextDueDate()));
+ qBubbleSort(schedule);
+ }
+ while(1);
+
+ if (needMoreLess) {
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ m_part->write("<td>");
+ if(m_showAllSchedules) {
+ m_part->write(link(VIEW_SCHEDULE, QString("?mode=%1").arg("reduced")) + i18n("Less...") + linkend());
+ } else {
+ m_part->write(link(VIEW_SCHEDULE, QString("?mode=%1").arg("full")) + i18n("More...") + linkend());
+ }
+ m_part->write("</td><td></td><td></td><td></td><td></td>");
+ m_part->write("</tr>");
+ }
+ m_part->write("</table>");
+ }
+ }
+ m_part->write("</div></div>");
+}
+
+void KHomeView::showPaymentEntry(const MyMoneySchedule& sched, int cnt)
+{
+ QString tmp;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ try {
+ MyMoneyAccount acc = sched.account();
+ if(acc.id()) {
+ MyMoneyTransaction t = sched.transaction();
+ // only show the entry, if it is still active
+ // FIXME clean old code
+ // if(!sched.isFinished() && sched.nextPayment(sched.lastPayment()) != QDate()) {
+ if(!sched.isFinished()) {
+ MyMoneySplit sp = t.splitByAccount(acc.id(), true);
+
+ QString pathEnter, pathSkip;
+ KGlobal::iconLoader()->loadIcon("key_enter", KIcon::Small, KIcon::SizeSmall, KIcon::DefaultState, &pathEnter);
+ KGlobal::iconLoader()->loadIcon("player_fwd", KIcon::Small, KIcon::SizeSmall, KIcon::DefaultState, &pathSkip);
+
+ //show payment date
+ tmp = QString("<td>") +
+ KGlobal::locale()->formatDate(sched.adjustedNextDueDate(), true) +
+ "</td><td>";
+ if(pathEnter.length() > 0)
+ tmp += link(VIEW_SCHEDULE, QString("?id=%1&mode=enter").arg(sched.id()), i18n("Enter schedule")) + QString("<img src=\"file://%1\" border=\"0\"></a>").arg(pathEnter) + linkend();
+ if(pathSkip.length() > 0)
+ tmp += "&nbsp;" + link(VIEW_SCHEDULE, QString("?id=%1&mode=skip").arg(sched.id()), i18n("Skip schedule")) + QString("<img src=\"file://%1\" border=\"0\"></a>").arg(pathSkip) + linkend();
+
+ tmp += QString("&nbsp;");
+ tmp += link(VIEW_SCHEDULE, QString("?id=%1&mode=edit").arg(sched.id()), i18n("Edit schedule")) + sched.name() + linkend();
+
+ //show quantity of payments overdue if any
+ if(cnt > 1)
+ tmp += i18n(" (%1 payments)").arg(cnt);
+
+ //show account of the main split
+ tmp += "</td><td>";
+ tmp += QString(file->account(acc.id()).name());
+
+ //show amount of the schedule
+ tmp += "</td><td align=\"right\">";
+
+ const MyMoneySecurity& currency = MyMoneyFile::instance()->currency(acc.currencyId());
+ QString amount = (sp.value()*cnt).formatMoney(acc, currency);
+ amount.replace(" ","&nbsp;");
+ tmp += showColoredAmount(amount, (sp.value()*cnt).isNegative()) ;
+ tmp += "</td>";
+ //show balance after payments
+ tmp += "<td align=\"right\">";
+ MyMoneyMoney payment = MyMoneyMoney((sp.value()*cnt));
+ QDate paymentDate = QDate(sched.nextDueDate());
+ MyMoneyMoney balanceAfter = forecastPaymentBalance(acc, payment, paymentDate);
+ QString balance = balanceAfter.formatMoney(acc, currency);
+ balance.replace(" ","&nbsp;");
+ tmp += showColoredAmount(balance, balanceAfter.isNegative());
+ tmp += "</td>";
+
+ // qDebug("paymentEntry = '%s'", tmp.latin1());
+ m_part->write(tmp);
+ }
+ }
+ } catch(MyMoneyException* e) {
+ qDebug("Unable to display schedule entry: %s", e->what().data());
+ delete e;
+ }
+}
+
+void KHomeView::showAccounts(KHomeView::paymentTypeE type, const QString& header)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyAccount> accounts;
+ QValueList<MyMoneyAccount>::Iterator it;
+ QValueList<MyMoneyAccount>::Iterator prevIt;
+ QMap<QString, MyMoneyAccount> nameIdx;
+
+ bool showClosedAccounts = kmymoney2->toggleAction("view_show_all_accounts")->isChecked();
+
+ // get list of all accounts
+ file->accountList(accounts);
+ for(it = accounts.begin(); it != accounts.end();) {
+ prevIt = it;
+ if(!(*it).isClosed() || showClosedAccounts) {
+ switch((*it).accountType()) {
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::Income:
+ // never show a category account
+ // Note: This might be different in a future version when
+ // the homepage also shows category based information
+ it = accounts.remove(it);
+ break;
+
+ // Asset and Liability accounts are only shown if they
+ // have the preferred flag set
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Investment:
+ // if preferred accounts are requested, then keep in list
+ if((*it).value("PreferredAccount") != "Yes"
+ || (type & Preferred) == 0) {
+ it = accounts.remove(it);
+ }
+ break;
+
+ // Check payment accounts. If payment and preferred is selected,
+ // then always show them. If only payment is selected, then
+ // show only if preferred flag is not set.
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::CreditCard:
+ switch(type & (Payment | Preferred)) {
+ case Payment:
+ if((*it).value("PreferredAccount") == "Yes")
+ it = accounts.remove(it);
+ break;
+
+ case Preferred:
+ if((*it).value("PreferredAccount") != "Yes")
+ it = accounts.remove(it);
+ break;
+
+ case Payment | Preferred:
+ break;
+
+ default:
+ it = accounts.remove(it);
+ break;
+ }
+ break;
+
+ // filter all accounts that are not used on homepage views
+ default:
+ it = accounts.remove(it);
+ break;
+ }
+
+ } else if((*it).isClosed() || (*it).isInvest()) {
+ // don't show if closed or a stock account
+ it = accounts.remove(it);
+ }
+
+ // if we still point to the same account we keep it in the list and move on ;-)
+ if(prevIt == it) {
+ d->addNameIndex(nameIdx, *it);
+ ++it;
+ }
+ }
+
+ if(accounts.count() > 0) {
+ QString tmp;
+ int i = 0;
+ tmp = "<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">" + header + "</div>\n<div class=\"gap\">&nbsp;</div>\n";
+ m_part->write(tmp);
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write("<tr class=\"item\"><td class=\"left\" width=\"35%\">");
+ m_part->write(i18n("Account"));
+ m_part->write("</td><td width=\"25%\" class=\"right\">");
+ m_part->write(i18n("Current Balance"));
+ m_part->write("</td>");
+ //only show limit info if user chose to do so
+ if(KMyMoneyGlobalSettings::showLimitInfo()) {
+ m_part->write("<td width=\"40%\" class=\"right\">");
+ m_part->write(i18n("To Minimum Balance / Maximum Credit"));
+ m_part->write("</td>");
+ }
+ m_part->write("</tr>");
+
+
+ QMap<QString, MyMoneyAccount>::const_iterator it_m;
+ for(it_m = nameIdx.begin(); it_m != nameIdx.end(); ++it_m) {
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ showAccountEntry(*it_m);
+ m_part->write("</tr>");
+ }
+ m_part->write("</table></div></div>");
+ }
+}
+
+void KHomeView::showAccountEntry(const MyMoneyAccount& acc)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneySecurity currency = file->currency(acc.currencyId());
+ MyMoneyMoney value;
+
+ bool showLimit = KMyMoneyGlobalSettings::showLimitInfo();
+
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ //investment accounts show the balances of all its subaccounts
+ value = investmentBalance(acc);
+
+ //investment accounts have no minimum balance
+ showAccountEntry(acc, value, MyMoneyMoney(), showLimit);
+ } else {
+ //get balance for normal accounts
+ value = file->balance(acc.id(), QDate::currentDate());
+
+ //if credit card or checkings account, show maximum credit
+ if( acc.accountType() == MyMoneyAccount::CreditCard ||
+ acc.accountType() == MyMoneyAccount::Checkings ) {
+ QString maximumCredit = acc.value("maxCreditAbsolute");
+ MyMoneyMoney maxCredit = MyMoneyMoney(maximumCredit);
+ showAccountEntry(acc, value, value - maxCredit, showLimit);
+ } else {
+ //otherwise use minimum balance
+ QString minimumBalance = acc.value("minBalanceAbsolute");
+ MyMoneyMoney minBalance = MyMoneyMoney(minimumBalance);
+ showAccountEntry(acc, value, value - minBalance, showLimit);
+ }
+ }
+}
+
+void KHomeView::showAccountEntry(const MyMoneyAccount& acc, const MyMoneyMoney& value, const MyMoneyMoney& valueToMinBal, const bool showMinBal)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString tmp;
+ MyMoneySecurity currency = file->currency(acc.currencyId());
+ QString amount;
+ QString amountToMinBal;
+
+ //format amounts
+ amount = value.formatMoney(acc, currency);
+ amount.replace(" ","&nbsp;");
+ if(showMinBal) {
+ amountToMinBal = valueToMinBal.formatMoney(acc, currency);
+ amountToMinBal.replace(" ","&nbsp;");
+ }
+
+ tmp = QString("<td>") +
+ link(VIEW_LEDGER, QString("?id=%1").arg(acc.id())) + acc.name() + linkend() + "</td>";
+
+ //show account balance
+ tmp += QString("<td class=\"right\">%1</td>").arg(showColoredAmount(amount, value.isNegative()));
+
+ //show minimum balance column if requested
+ if(showMinBal) {
+ //if it is an investment, show minimum balance empty
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ tmp += QString("<td class=\"right\">&nbsp;</td>");
+ } else {
+ //show minimum balance entry
+ tmp += QString("<td class=\"right\">%1</td>").arg(showColoredAmount(amountToMinBal, valueToMinBal.isNegative()));
+ }
+ }
+ // qDebug("accountEntry = '%s'", tmp.latin1());
+ m_part->write(tmp);
+}
+
+MyMoneyMoney KHomeView::investmentBalance(const MyMoneyAccount& acc)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyMoney value;
+
+ value = file->balance(acc.id());
+ QValueList<QString>::const_iterator it_a;
+ for(it_a = acc.accountList().begin(); it_a != acc.accountList().end(); ++it_a) {
+ MyMoneyAccount stock = file->account(*it_a);
+ try {
+ MyMoneyMoney val;
+ MyMoneyMoney balance = file->balance(stock.id());
+ MyMoneySecurity security = file->security(stock.currencyId());
+ MyMoneyPrice price = file->price(stock.currencyId(), security.tradingCurrency());
+ val = (balance * price.rate(security.tradingCurrency())).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()));
+ // adjust value of security to the currency of the account
+ MyMoneySecurity accountCurrency = file->currency(acc.currencyId());
+ val = val * file->price(security.tradingCurrency(), accountCurrency.id()).rate(accountCurrency.id());
+ val = val.convert(acc.fraction());
+ value += val;
+ } catch(MyMoneyException* e) {
+ qWarning("%s", (QString("cannot convert stock balance of %1 to base currency: %2").arg(stock.name(), e->what())).data());
+ delete e;
+ }
+ }
+ return value;
+}
+
+void KHomeView::showFavoriteReports(void)
+{
+ QValueList<MyMoneyReport> reports = MyMoneyFile::instance()->reportList();
+
+ if ( reports.count() > 0 )
+ {
+ bool firstTime = 1;
+ int row = 0;
+ QValueList<MyMoneyReport>::const_iterator it_report = reports.begin();
+ while( it_report != reports.end() )
+ {
+ if ( (*it_report).isFavorite() ) {
+ if(firstTime) {
+ m_part->write(QString("<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">%1</div>\n<div class=\"gap\">&nbsp;</div>\n").arg(i18n("Favorite Reports")));
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write("<tr class=\"item\"><td class=\"left\" width=\"40%\">");
+ m_part->write(i18n("Report"));
+ m_part->write("</td><td width=\"60%\" class=\"left\">");
+ m_part->write(i18n("Comment"));
+ m_part->write("</td></tr>");
+ firstTime = false;
+ }
+
+ m_part->write(QString("<tr class=\"row-%1\"><td>%2%3%4</td><td align=\"left\">%5</td></tr>")
+ .arg(row++ & 0x01 ? "even" : "odd")
+ .arg(link(VIEW_REPORTS, QString("?id=%1").arg((*it_report).id())))
+ .arg((*it_report).name())
+ .arg(linkend())
+ .arg((*it_report).comment())
+ );
+ }
+
+ ++it_report;
+ }
+ if(!firstTime)
+ m_part->write("</table></div></div>");
+ }
+}
+
+void KHomeView::showForecast(void)
+{
+ QMap<QString, MyMoneyAccount> nameIdx;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyAccount> accList;
+
+ // if forecast has not been executed yet, do it.
+ if(!m_forecast.isForecastDone())
+ doForecast();
+
+ accList = m_forecast.accountList();
+
+ // add it to a map to have it ordered by name
+ QValueList<MyMoneyAccount>::const_iterator accList_t = accList.begin();
+ for ( ; accList_t != accList.end(); ++accList_t ) {
+ d->addNameIndex(nameIdx, *accList_t);
+ }
+
+ if(nameIdx.count() > 0) {
+ int i = 0;
+
+ int colspan = 1;
+ // get begin day
+ int beginDay = QDate::currentDate().daysTo(m_forecast.beginForecastDate());
+ // if begin day is today skip to next cycle
+ if(beginDay == 0)
+ beginDay = m_forecast.accountsCycle();
+
+ // Now output header
+ m_part->write(QString("<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">%1</div>\n<div class=\"gap\">&nbsp;</div>\n").arg(i18n("%1 Day Forecast").arg(m_forecast.forecastDays())));
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write("<tr class=\"item\"><td class=\"left\" width=\"40%\">");
+ m_part->write(i18n("Account"));
+ m_part->write("</td>");
+ int colWidth = 55/ (m_forecast.forecastDays() / m_forecast.accountsCycle());
+ for(i = 0; (i*m_forecast.accountsCycle() + beginDay) <= m_forecast.forecastDays(); ++i) {
+ m_part->write(QString("<td width=\"%1%\" class=\"right\">").arg(colWidth));
+
+ m_part->write(i18n("%1 days").arg(i*m_forecast.accountsCycle() + beginDay));
+ m_part->write("</td>");
+ colspan++;
+ }
+ m_part->write("</tr>");
+
+ // Now output entries
+ i = 0;
+
+ QMap<QString, MyMoneyAccount>::ConstIterator it_account;
+ for(it_account = nameIdx.begin(); it_account != nameIdx.end(); ++it_account) {
+ //MyMoneyAccount acc = (*it_n);
+
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ m_part->write(QString("<td width=\"40%\">") +
+ link(VIEW_LEDGER, QString("?id=%1").arg((*it_account).id())) + (*it_account).name() + linkend() + "</td>");
+
+ int dropZero = -1; //account dropped below zero
+ int dropMinimum = -1; //account dropped below minimum balance
+ QString minimumBalance = (*it_account).value("minimumBalance");
+ MyMoneyMoney minBalance = MyMoneyMoney(minimumBalance);
+ MyMoneySecurity currency;
+ MyMoneyMoney forecastBalance;
+
+ //change account to deep currency if account is an investment
+ if((*it_account).isInvest()) {
+ MyMoneySecurity underSecurity = file->security((*it_account).currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security((*it_account).currencyId());
+ }
+
+ for (int f = beginDay; f <= m_forecast.forecastDays(); f += m_forecast.accountsCycle()) {
+ forecastBalance = m_forecast.forecastBalance(*it_account, QDate::currentDate().addDays(f));
+ QString amount;
+ amount = forecastBalance.formatMoney( *it_account, currency);
+ amount.replace(" ","&nbsp;");
+ m_part->write(QString("<td width=\"%1%\" align=\"right\">").arg(colWidth));
+ m_part->write(QString("%1</td>").arg(showColoredAmount(amount, forecastBalance.isNegative())));
+ }
+
+ m_part->write("</tr>");
+
+ //Check if the account is going to be below zero or below the minimal balance in the forecast period
+
+ //Check if the account is going to be below minimal balance
+ dropMinimum = m_forecast.daysToMinimumBalance(*it_account);
+
+ //Check if the account is going to be below zero in the future
+ dropZero = m_forecast.daysToZeroBalance(*it_account);
+
+
+ // spit out possible warnings
+ QString msg;
+
+ // if a minimum balance has been specified, an appropriate warning will
+ // only be shown, if the drop below 0 is on a different day or not present
+
+ if(dropMinimum != -1
+ && !minBalance.isZero()
+ && (dropMinimum < dropZero
+ || dropZero == -1)) {
+ switch(dropMinimum) {
+ case -1:
+ break;
+ case 0:
+ msg = i18n("The balance of %1 is below the minimum balance %2 today.").arg((*it_account).name()).arg(minBalance.formatMoney(*it_account, currency));
+ msg = showColoredAmount(msg, true);
+ break;
+ default:
+ msg = i18n("The balance of %1 will drop below the minimum balance %2 in %3 days.").arg((*it_account).name()).arg(minBalance.formatMoney(*it_account, currency)).arg(dropMinimum-1);
+ msg = showColoredAmount(msg, true);
+ break;
+ }
+
+ if(!msg.isEmpty()) {
+ m_part->write(QString("<tr class=\"warning\" style=\"font-weight: normal;\" ><td colspan=%2 align=\"center\" >%1</td></tr>").arg(msg).arg(colspan));
+ }
+ }
+ // a drop below zero is always shown
+ msg = QString();
+ switch(dropZero) {
+ case -1:
+ break;
+ case 0:
+ if((*it_account).accountGroup() == MyMoneyAccount::Asset) {
+ msg = i18n("The balance of %1 is below %2 today.").arg((*it_account).name()).arg(MyMoneyMoney().formatMoney(*it_account, currency));
+ msg = showColoredAmount(msg, true);
+ break;
+ }
+ if((*it_account).accountGroup() == MyMoneyAccount::Liability) {
+ msg = i18n("The balance of %1 is above %2 today.").arg((*it_account).name()).arg(MyMoneyMoney().formatMoney(*it_account, currency));
+ break;
+ }
+ break;
+ default:
+ if((*it_account).accountGroup() == MyMoneyAccount::Asset) {
+ msg = i18n("The balance of %1 will drop below %2 in %3 days.").arg((*it_account).name()).arg(MyMoneyMoney().formatMoney(*it_account, currency)).arg(dropZero);
+ msg = showColoredAmount(msg, true);
+ break;
+ }
+ if((*it_account).accountGroup() == MyMoneyAccount::Liability) {
+ msg = i18n("The balance of %1 will raise above %2 in %3 days.").arg((*it_account).name()).arg(MyMoneyMoney().formatMoney(*it_account, currency)).arg(dropZero);
+ break;
+ }
+ }
+ if(!msg.isEmpty()) {
+ m_part->write(QString("<tr class=\"warning\"><td colspan=%2 align=\"center\" ><b>%1</b></td></tr>").arg(msg).arg(colspan));
+ }
+ }
+ m_part->write("</table></div></div>");
+
+ }
+}
+
+const QString KHomeView::link(const QString& view, const QString& query, const QString& _title) const
+{
+ QString titlePart;
+ QString title(_title);
+ if(!title.isEmpty())
+ titlePart = QString(" title=\"%1\"").arg(title.replace(" ", "&nbsp;"));
+
+ return QString("<a href=\"/%1%2\"%3>").arg(view, query, titlePart);
+}
+
+const QString KHomeView::linkend(void) const
+{
+ return "</a>";
+}
+
+void KHomeView::slotOpenURL(const KURL &url, const KParts::URLArgs& /* args */)
+{
+ QString protocol = url.protocol();
+ QString view = url.fileName(false);
+ QString id = url.queryItem("id").data();
+ QString mode = url.queryItem("mode").data();
+
+ if ( protocol == "http" )
+ {
+ KApplication::kApplication()->invokeBrowser(url.prettyURL());
+ }
+ else if ( protocol == "mailto" )
+ {
+ KApplication::kApplication()->invokeMailer(url);
+ }
+ else
+ {
+ if(view == VIEW_LEDGER) {
+ emit ledgerSelected(id, QString());
+
+ } else if(view == VIEW_SCHEDULE) {
+ if(mode == "enter") {
+ emit scheduleSelected(id);
+ KMainWindow* mw = dynamic_cast<KMainWindow*>(qApp->mainWidget());
+ Q_CHECK_PTR(mw);
+ QTimer::singleShot(0, mw->actionCollection()->action("schedule_enter"), SLOT(activate()));
+
+ } else if(mode == "edit") {
+ emit scheduleSelected(id);
+ KMainWindow* mw = dynamic_cast<KMainWindow*>(qApp->mainWidget());
+ Q_CHECK_PTR(mw);
+ QTimer::singleShot(0, mw->actionCollection()->action("schedule_edit"), SLOT(activate()));
+
+ } else if(mode == "skip") {
+ emit scheduleSelected(id);
+ KMainWindow* mw = dynamic_cast<KMainWindow*>(qApp->mainWidget());
+ Q_CHECK_PTR(mw);
+ QTimer::singleShot(0, mw->actionCollection()->action("schedule_skip"), SLOT(activate()));
+
+ } else if(mode == "full") {
+ m_showAllSchedules = true;
+ loadView();
+
+ } else if(mode == "reduced") {
+ m_showAllSchedules = false;
+ loadView();
+ }
+
+ } else if(view == VIEW_REPORTS) {
+ emit reportSelected(id);
+
+ } else if(view == VIEW_WELCOME) {
+ KMainWindow* mw = dynamic_cast<KMainWindow*>(qApp->mainWidget());
+ Q_CHECK_PTR(mw);
+ if ( mode == "whatsnew" )
+ {
+ QString fname = KMyMoneyUtils::findResource("appdata",QString("html/whats_new%1.html"));
+ if(!fname.isEmpty())
+ m_part->openURL(fname);
+ }
+ else
+ m_part->openURL(m_filename);
+
+ } else if(view == "action") {
+ KMainWindow* mw = dynamic_cast<KMainWindow*>(qApp->mainWidget());
+ Q_CHECK_PTR(mw);
+ QTimer::singleShot(0, mw->actionCollection()->action( id ), SLOT(activate()));
+
+ } else if(view == VIEW_HOME) {
+ QValueList<MyMoneyAccount> list;
+ MyMoneyFile::instance()->accountList(list);
+ if(list.count() == 0) {
+ KMessageBox::information(this, i18n("Before KMyMoney can give you detailed information about your financial status, you need to create at least one account. Until then, KMyMoney shows the welcome page instead."));
+ }
+ loadView();
+
+ } else {
+ qDebug("Unknown view '%s' in KHomeView::slotOpenURL()", view.latin1());
+ }
+ }
+}
+
+void KHomeView::showAssetsLiabilities(void)
+{
+ QValueList<MyMoneyAccount> accounts;
+ QValueList<MyMoneyAccount>::Iterator it;
+ QMap<QString, MyMoneyAccount> nameAssetsIdx;
+ QMap<QString, MyMoneyAccount> nameLiabilitiesIdx;
+ MyMoneyMoney netAssets;
+ MyMoneyMoney netLiabilities;
+ QString fontStart, fontEnd;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ int prec = MyMoneyMoney::denomToPrec(file->baseCurrency().smallestAccountFraction());
+ int i = 0;
+
+
+ // get list of all accounts
+ file->accountList(accounts);
+ for(it = accounts.begin(); it != accounts.end();) {
+ if(!(*it).isClosed()) {
+ switch((*it).accountType()) {
+ // group all assets into one list but make sure that investment accounts always show up
+ case MyMoneyAccount::Investment:
+ d->addNameIndex(nameAssetsIdx, *it);
+ break;
+
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::AssetLoan:
+ // list account if it's the last in the hierarchy or has transactions in it
+ if((*it).accountList().isEmpty() || (file->transactionCount((*it).id()) > 0)) {
+ d->addNameIndex(nameAssetsIdx, *it);
+ }
+ break;
+
+ // group the liabilities into the other
+ case MyMoneyAccount::CreditCard:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Loan:
+ // list account if it's the last in the hierarchy or has transactions in it
+ if((*it).accountList().isEmpty() || (file->transactionCount((*it).id()) > 0)) {
+ d->addNameIndex(nameLiabilitiesIdx, *it);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ ++it;
+ }
+
+ //only do it if we have assets or liabilities account
+ if(nameAssetsIdx.count() > 0 || nameLiabilitiesIdx.count() > 0) {
+ //print header
+ m_part->write("<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">" + i18n("Assets and Liabilities Summary") + "</div>\n<div class=\"gap\">&nbsp;</div>\n");
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ //column titles
+ m_part->write("<tr class=\"item\"><td class=\"left\" width=\"30%\">");
+ m_part->write(i18n("Asset Accounts"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"15%\" class=\"right\">");
+ m_part->write(i18n("Current Balance"));
+ m_part->write("</td>");
+ //intermediate row to separate both columns
+ m_part->write("<td width=\"10%\" class=\"setcolor\"></td>");
+ m_part->write("<td class=\"left\" width=\"30%\">");
+ m_part->write(i18n("Liability Accounts"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"15%\" class=\"right\">");
+ m_part->write(i18n("Current Balance"));
+ m_part->write("</td></tr>");
+
+ //get asset and liability accounts
+ QMap<QString, MyMoneyAccount>::const_iterator asset_it = nameAssetsIdx.begin();
+ QMap<QString,MyMoneyAccount>::const_iterator liabilities_it = nameLiabilitiesIdx.begin();
+ for(; asset_it != nameAssetsIdx.end() || liabilities_it != nameLiabilitiesIdx.end();) {
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+ //write an asset account if we still have any
+ if(asset_it != nameAssetsIdx.end()) {
+ MyMoneyMoney value;
+ //investment accounts consolidate the balance of its subaccounts
+ if( (*asset_it).accountType() == MyMoneyAccount::Investment) {
+ value = investmentBalance(*asset_it);
+ } else {
+ value = MyMoneyFile::instance()->balance((*asset_it).id(), QDate::currentDate());
+ }
+ //calculate balance for foreign currency accounts
+ if((*asset_it).currencyId() != file->baseCurrency().id()) {
+ ReportAccount repAcc = ReportAccount((*asset_it).id());
+ MyMoneyMoney curPrice = repAcc.baseCurrencyPrice(QDate::currentDate());
+ MyMoneyMoney baseValue = value * curPrice;
+ baseValue = baseValue.convert(10000);
+ netAssets += baseValue;
+ } else {
+ netAssets += value;
+ }
+ //show the account without minimum balance
+ showAccountEntry(*asset_it, value, MyMoneyMoney(), false);
+ ++asset_it;
+ } else {
+ //write a white space if we don't
+ m_part->write("<td></td><td></td>");
+ }
+
+ //leave the intermediate column empty
+ m_part->write("<td class=\"setcolor\"></td>");
+
+ //write a liability account
+ if(liabilities_it != nameLiabilitiesIdx.end()) {
+ MyMoneyMoney value;
+ value = MyMoneyFile::instance()->balance((*liabilities_it).id(), QDate::currentDate());
+ //calculate balance if foreign currency
+ if((*liabilities_it).currencyId() != file->baseCurrency().id()) {
+ ReportAccount repAcc = ReportAccount((*liabilities_it).id());
+ MyMoneyMoney curPrice = repAcc.baseCurrencyPrice(QDate::currentDate());
+ MyMoneyMoney baseValue = value * curPrice;
+ baseValue = baseValue.convert(10000);
+ netLiabilities += baseValue;
+ } else {
+ netLiabilities += value;
+ }
+ //show the account without minimum balance
+ showAccountEntry(*liabilities_it, value, MyMoneyMoney(), false);
+ ++liabilities_it;
+ } else {
+ //leave the space empty if we run out of liabilities
+ m_part->write("<td></td><td></td>");
+ }
+ m_part->write("</tr>");
+ }
+ //calculate net worth
+ MyMoneyMoney netWorth = netAssets+netLiabilities;
+
+ //format assets, liabilities and net worth
+ QString amountAssets = netAssets.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountLiabilities = netLiabilities.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountNetWorth = netWorth.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ amountAssets.replace(" ","&nbsp;");
+ amountLiabilities.replace(" ","&nbsp;");
+ amountNetWorth.replace(" ","&nbsp;");
+
+ m_part->write(QString("<tr class=\"row-%1\" style=\"font-weight:bold;\">").arg(i++ & 0x01 ? "even" : "odd"));
+
+ //print total for assets
+ m_part->write(QString("<td class=\"left\">%1</td><td align=\"right\">%2</td>").arg(i18n("Total Assets")).arg(showColoredAmount(amountAssets, netAssets.isNegative())));
+
+ //leave the intermediate column empty
+ m_part->write("<td class=\"setcolor\"></td>");
+
+ //print total liabilities
+ m_part->write(QString("<td class=\"left\">%1</td><td align=\"right\">%2</td>").arg(i18n("Total Liabilities")).arg(showColoredAmount(amountLiabilities, netLiabilities.isNegative())));
+ m_part->write("</tr>");
+
+ //print net worth
+ m_part->write(QString("<tr class=\"row-%1\" style=\"font-weight:bold;\">").arg(i++ & 0x01 ? "even" : "odd"));
+
+ m_part->write("<td></td><td></td><td class=\"setcolor\"></td>");
+ m_part->write(QString("<td class=\"left\">%1</td><td align=\"right\">%2</td>").arg(i18n("Net Worth")).arg(showColoredAmount(amountNetWorth, netWorth.isNegative() )));
+
+ m_part->write("</tr>");
+ m_part->write("</table>");
+ m_part->write("</div></div>");
+ }
+}
+
+void KHomeView::showBudget(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ if ( file->countBudgets() ) {
+ int prec = MyMoneyMoney::denomToPrec(file->baseCurrency().smallestAccountFraction());
+ int i = 0;
+
+ //config report just like "Monthly Budgeted vs Actual
+ MyMoneyReport reportCfg = MyMoneyReport(
+ MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentMonth,
+ MyMoneyReport::eDetailAll,
+ i18n("Monthly Budgeted vs. Actual"),
+ i18n("Generated Report"));
+
+ reportCfg.setBudget("Any",true);
+
+ reports::PivotTable table(reportCfg);
+
+ PivotGrid grid = table.grid();
+
+ //div header
+ m_part->write("<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">" + i18n("Budget") + "</div>\n<div class=\"gap\">&nbsp;</div>\n");
+
+ //display budget summary
+ m_part->write("<table width=\"75%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write("<tr class=\"itemtitle\">");
+ m_part->write("<td class=\"left\" colspan=\"3\">");
+ m_part->write(i18n("Current Month Summary"));
+ m_part->write("</td></tr>");
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td class=\"right\" width=\"33%\">");
+ m_part->write(i18n("Budgeted"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"33%\">");
+ m_part->write(i18n("Actual"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"33%\">");
+ m_part->write(i18n("Difference"));
+ m_part->write("</td></tr>");
+
+ m_part->write(QString("<tr class=\"row-odd\">"));
+
+ MyMoneyMoney totalBudgetValue = grid.m_total[eBudget].m_total;
+ MyMoneyMoney totalActualValue = grid.m_total[eActual].m_total;
+ MyMoneyMoney totalBudgetDiffValue = grid.m_total[eBudgetDiff].m_total;
+
+ QString totalBudgetAmount = totalBudgetValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString totalActualAmount = totalActualValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString totalBudgetDiffAmount = totalBudgetDiffValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+
+ m_part->write(QString("<td align=\"right\">%1</td>").arg(showColoredAmount(totalBudgetAmount, totalBudgetValue.isNegative())));
+ m_part->write(QString("<td align=\"right\">%1</td>").arg(showColoredAmount(totalActualAmount, totalActualValue.isNegative())));
+ m_part->write(QString("<td align=\"right\">%1</td>").arg(showColoredAmount(totalBudgetDiffAmount, totalBudgetDiffValue.isNegative())));
+ m_part->write("</tr>");
+ m_part->write("</table>");
+
+ //budget overrun
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+ m_part->write("<table width=\"75%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ m_part->write("<tr class=\"itemtitle\">");
+ m_part->write("<td class=\"left\" colspan=\"4\">");
+ m_part->write(i18n("Budget Overruns"));
+ m_part->write("</td></tr>");
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td class=\"left\" width=\"30%\">");
+ m_part->write(i18n("Account"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"20%\">");
+ m_part->write(i18n("Budgeted"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"20%\">");
+ m_part->write(i18n("Actual"));
+ m_part->write("</td>");
+ m_part->write("<td class=\"right\" width=\"20%\">");
+ m_part->write(i18n("Difference"));
+ m_part->write("</td></tr>");
+
+
+ PivotGrid::iterator it_outergroup = grid.begin();
+ while ( it_outergroup != grid.end() )
+ {
+ i = 0;
+ PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin();
+ while ( it_innergroup != (*it_outergroup).end() )
+ {
+ PivotInnerGroup::iterator it_row = (*it_innergroup).begin();
+ while ( it_row != (*it_innergroup).end() )
+ {
+ //column number is 1 because the report includes only current month
+ if(it_row.data()[eBudgetDiff][1].isNegative()) {
+ //get report account to get the name later
+ ReportAccount rowname = it_row.key();
+
+ //write the outergroup if it is the first row of outergroup being shown
+ if(i == 0) {
+ m_part->write("<tr style=\"font-weight:bold;\">");
+ m_part->write(QString("<td class=\"left\" colspan=\"4\">%1</td>").arg(KMyMoneyUtils::accountTypeToString( rowname.accountType())));
+ m_part->write("</tr>");
+ }
+ m_part->write(QString("<tr class=\"row-%1\">").arg(i++ & 0x01 ? "even" : "odd"));
+
+ //get values from grid
+ MyMoneyMoney actualValue = it_row.data()[eActual][1];
+ MyMoneyMoney budgetValue = it_row.data()[eBudget][1];
+ MyMoneyMoney budgetDiffValue = it_row.data()[eBudgetDiff][1];
+
+ //format amounts
+ QString actualAmount = actualValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString budgetAmount = budgetValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString budgetDiffAmount = budgetDiffValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+
+ //account name
+ m_part->write(QString("<td>") + link(VIEW_LEDGER, QString("?id=%1").arg(rowname.id())) + rowname.name() + linkend() + "</td>");
+
+ //show amounts
+ m_part->write(QString("<td align=\"right\">%1</td>").arg(showColoredAmount(budgetAmount, budgetValue.isNegative())));
+ m_part->write(QString("<td align=\"right\">%1</td>").arg(showColoredAmount(actualAmount, actualValue.isNegative())));
+ m_part->write(QString("<td align=\"right\">%1</td>").arg(showColoredAmount(budgetDiffAmount, budgetDiffValue.isNegative())));
+ m_part->write("</tr>");
+ }
+ ++it_row;
+ }
+ ++it_innergroup;
+ }
+ ++it_outergroup;
+ }
+
+ //if no negative differences are found, then inform that
+ if(i == 0) {
+ m_part->write(QString("<tr class=\"row-%1\" style=\"font-weight:bold;\">").arg(i++ & 0x01 ? "even" : "odd"));
+ m_part->write(QString("<td class=\"center\" colspan=\"4\">%1</td>").arg(i18n("No Budget Categories have been overrun")));
+ m_part->write("</tr>");
+ }
+ m_part->write("</table></div></div>");
+ }
+}
+
+QString KHomeView::showColoredAmount(const QString& amount, bool isNegative)
+{
+ if(isNegative) {
+ //if negative, get the settings for negative numbers
+ return QString("<font color=\"%1\">%2</font>").arg(KMyMoneyGlobalSettings::listNegativeValueColor().name(), amount);
+ }
+
+ //if positive, return the same string
+ return amount;
+}
+
+void KHomeView::doForecast(void)
+{
+ //clear m_accountList because forecast is about to changed
+ m_accountList.clear();
+
+ //reinitialize the object
+ m_forecast = MyMoneyForecast();
+
+ //If forecastDays lower than accountsCycle, adjust to the first cycle
+ if(m_forecast.accountsCycle() > m_forecast.forecastDays())
+ m_forecast.setForecastDays(m_forecast.accountsCycle());
+
+ //Get all accounts of the right type to calculate forecast
+ m_forecast.doForecast();
+}
+
+MyMoneyMoney KHomeView::forecastPaymentBalance(const MyMoneyAccount& acc, const MyMoneyMoney& payment, QDate& paymentDate)
+{
+ //if paymentDate before or equal to currentDate set it to current date plus 1
+ //so we get to accumulate forecast balance correctly
+ if(paymentDate <= QDate::currentDate())
+ paymentDate = QDate::currentDate().addDays(1);
+
+ //check if the account is already there
+ if(m_accountList.find(acc.id()) == m_accountList.end()
+ || m_accountList[acc.id()].find(paymentDate) == m_accountList[acc.id()].end())
+ {
+ if(paymentDate == QDate::currentDate()) {
+ m_accountList[acc.id()][paymentDate] = m_forecast.forecastBalance(acc, paymentDate);
+ } else {
+ m_accountList[acc.id()][paymentDate] = m_forecast.forecastBalance(acc, paymentDate.addDays(-1));
+ }
+ }
+ m_accountList[acc.id()][paymentDate] = m_accountList[acc.id()][paymentDate] + payment;
+ return m_accountList[acc.id()][paymentDate];
+}
+
+void KHomeView::showCashFlowSummary()
+{
+ MyMoneyTransactionFilter filter;
+ MyMoneyMoney incomeValue;
+ MyMoneyMoney expenseValue;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ int prec = MyMoneyMoney::denomToPrec(file->baseCurrency().smallestAccountFraction());
+
+ //set start and end of month dates
+ QDate startOfMonth = QDate(QDate::currentDate().year(), QDate::currentDate().month(), 1);
+ QDate endOfMonth = QDate(QDate::currentDate().year(), QDate::currentDate().month(), QDate::currentDate().daysInMonth());
+
+ //Add total income and expenses for this month
+ //get transactions for current month
+ filter.setDateFilter(startOfMonth, endOfMonth);
+ filter.setReportAllSplits(false);
+
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ //if no transaction then skip and print total in zero
+ if(transactions.size() > 0) {
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction;
+
+ //get all transactions for this month
+ for(it_transaction = transactions.begin(); it_transaction != transactions.end(); ++it_transaction ) {
+
+ //get the splits for each transaction
+ const QValueList<MyMoneySplit>& splits = (*it_transaction).splits();
+ QValueList<MyMoneySplit>::const_iterator it_split;
+ for(it_split = splits.begin(); it_split != splits.end(); ++it_split) {
+ if(!(*it_split).shares().isZero()) {
+ ReportAccount repSplitAcc = ReportAccount((*it_split).accountId());
+
+ //only add if it is an income or expense
+ if(repSplitAcc.isIncomeExpense()) {
+ MyMoneyMoney value;
+
+ //convert to base currency if necessary
+ if(repSplitAcc.currencyId() != file->baseCurrency().id()) {
+ MyMoneyMoney curPrice = repSplitAcc.baseCurrencyPrice((*it_transaction).postDate());
+ value = ((*it_split).shares() * MyMoneyMoney(-1, 1)) * curPrice;
+ value = value.convert(10000);
+ } else {
+ value = ((*it_split).shares() * MyMoneyMoney(-1, 1));
+ }
+
+ //store depending on account type
+ if(repSplitAcc.accountType() == MyMoneyAccount::Income) {
+ incomeValue += value;
+ } else {
+ expenseValue += value;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //format income and expenses
+ QString amountIncome = incomeValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountExpense = expenseValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ amountIncome.replace(" ","&nbsp;");
+ amountExpense.replace(" ","&nbsp;");
+
+ //calculate schedules
+
+ //Add all schedules for this month
+ MyMoneyMoney scheduledIncome;
+ MyMoneyMoney scheduledExpense;
+ MyMoneyMoney scheduledLiquidTransfer;
+ MyMoneyMoney scheduledOtherTransfer;
+
+ //get overdues and schedules until the end of this month
+ QValueList<MyMoneySchedule> schedule = file->scheduleList("", MyMoneySchedule::TYPE_ANY,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ QDate(),
+ endOfMonth);
+
+ //Remove the finished schedules
+ QValueList<MyMoneySchedule>::Iterator finished_it;
+ for (finished_it=schedule.begin(); finished_it!=schedule.end();) {
+ if ((*finished_it).isFinished()) {
+ finished_it = schedule.remove(finished_it);
+ continue;
+ }
+ ++finished_it;
+ }
+
+ //add income and expenses
+ QValueList<MyMoneySchedule>::Iterator sched_it;
+ for (sched_it=schedule.begin(); sched_it!=schedule.end();) {
+ QDate nextDate = (*sched_it).nextDueDate();
+ int cnt = 0;
+
+ while(nextDate.isValid() && nextDate <= endOfMonth) {
+ ++cnt;
+ nextDate = (*sched_it).nextPayment(nextDate);
+ // for single occurence nextDate will not change, so we
+ // better get out of here.
+ if((*sched_it).occurence() == MyMoneySchedule::OCCUR_ONCE)
+ break;
+ }
+
+ MyMoneyAccount acc = (*sched_it).account();
+ if(acc.id()) {
+ MyMoneyTransaction transaction = (*sched_it).transaction();
+ // only show the entry, if it is still active
+
+ MyMoneySplit sp = transaction.splitByAccount(acc.id(), true);
+
+ // take care of the autoCalc stuff
+ if((*sched_it).type() == MyMoneySchedule::TYPE_LOANPAYMENT) {
+ QDate nextDate = (*sched_it).nextPayment((*sched_it).lastPayment());
+
+ //make sure we have all 'starting balances' so that the autocalc works
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ QMap<QString, MyMoneyMoney> balanceMap;
+
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s ) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ // collect all overdues on the first day
+ QDate schedDate = nextDate;
+ if(QDate::currentDate() >= nextDate)
+ schedDate = QDate::currentDate().addDays(1);
+
+ balanceMap[acc.id()] += file->balance(acc.id());
+ }
+ KMyMoneyUtils::calculateAutoLoan(*sched_it, transaction, balanceMap);
+ }
+
+ //go through the splits and assign to liquid or other transfers
+ const QValueList<MyMoneySplit> splits = transaction.splits();
+ QValueList<MyMoneySplit>::const_iterator split_it;
+ for (split_it = splits.begin(); split_it != splits.end(); ++split_it) {
+ if( (*split_it).accountId() != acc.id() ) {
+ ReportAccount repSplitAcc = ReportAccount((*split_it).accountId());
+
+ //get the shares and multiply by the quantity of occurences in the period
+ MyMoneyMoney value = (*split_it).shares() * cnt;
+
+ //convert to foreign currency if needed
+ if(repSplitAcc.currencyId() != file->baseCurrency().id()) {
+ MyMoneyMoney curPrice = repSplitAcc.baseCurrencyPrice(QDate::currentDate());
+ value = value * curPrice;
+ value = value.convert(10000);
+ }
+
+ if(( repSplitAcc.isLiquidLiability()
+ || repSplitAcc.isLiquidAsset() )
+ && acc.accountGroup() != repSplitAcc.accountGroup()) {
+ scheduledLiquidTransfer += value;
+ } else if(repSplitAcc.isAssetLiability()
+ && !repSplitAcc.isLiquidLiability()
+ && !repSplitAcc.isLiquidAsset() ) {
+ scheduledOtherTransfer += value;
+ } else if(repSplitAcc.isIncomeExpense()) {
+ //income and expenses are stored as negative values
+ if(repSplitAcc.accountType() == MyMoneyAccount::Income)
+ scheduledIncome -= value;
+ if(repSplitAcc.accountType() == MyMoneyAccount::Expense)
+ scheduledExpense -= value;
+ }
+ }
+ }
+ }
+ ++sched_it;
+ }
+
+ //format the currency strings
+ QString amountScheduledIncome = scheduledIncome.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountScheduledExpense = scheduledExpense.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountScheduledLiquidTransfer = scheduledLiquidTransfer.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountScheduledOtherTransfer = scheduledOtherTransfer.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+
+ amountScheduledIncome.replace(" ","&nbsp;");
+ amountScheduledExpense.replace(" ","&nbsp;");
+ amountScheduledLiquidTransfer.replace(" ","&nbsp;");
+ amountScheduledOtherTransfer.replace(" ","&nbsp;");
+
+ //get liquid assets and liabilities
+ QValueList<MyMoneyAccount> accounts;
+ QValueList<MyMoneyAccount>::const_iterator account_it;
+ MyMoneyMoney liquidAssets;
+ MyMoneyMoney liquidLiabilities;
+
+ // get list of all accounts
+ file->accountList(accounts);
+ for(account_it = accounts.begin(); account_it != accounts.end();) {
+ if(!(*account_it).isClosed()) {
+ switch((*account_it).accountType()) {
+ //group all assets into one list
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ {
+ MyMoneyMoney value = MyMoneyFile::instance()->balance((*account_it).id(), QDate::currentDate());
+ //calculate balance for foreign currency accounts
+ if((*account_it).currencyId() != file->baseCurrency().id()) {
+ ReportAccount repAcc = ReportAccount((*account_it).id());
+ MyMoneyMoney curPrice = repAcc.baseCurrencyPrice(QDate::currentDate());
+ MyMoneyMoney baseValue = value * curPrice;
+ liquidAssets += baseValue;
+ liquidAssets = liquidAssets.convert(10000);
+ } else {
+ liquidAssets += value;
+ }
+ break;
+ }
+ //group the liabilities into the other
+ case MyMoneyAccount::CreditCard:
+ {
+ MyMoneyMoney value;
+ value = MyMoneyFile::instance()->balance((*account_it).id(), QDate::currentDate());
+ //calculate balance if foreign currency
+ if((*account_it).currencyId() != file->baseCurrency().id()) {
+ ReportAccount repAcc = ReportAccount((*account_it).id());
+ MyMoneyMoney curPrice = repAcc.baseCurrencyPrice(QDate::currentDate());
+ MyMoneyMoney baseValue = value * curPrice;
+ liquidLiabilities += baseValue;
+ liquidLiabilities = liquidLiabilities.convert(10000);
+ } else {
+ liquidLiabilities += value;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ ++account_it;
+ }
+ //calculate net worth
+ MyMoneyMoney liquidWorth = liquidAssets+liquidLiabilities;
+
+ //format assets, liabilities and net worth
+ QString amountLiquidAssets = liquidAssets.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountLiquidLiabilities = liquidLiabilities.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountLiquidWorth = liquidWorth.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ amountLiquidAssets.replace(" ","&nbsp;");
+ amountLiquidLiabilities.replace(" ","&nbsp;");
+ amountLiquidWorth.replace(" ","&nbsp;");
+
+ //show the summary
+ m_part->write("<div class=\"shadow\"><div class=\"displayblock\"><div class=\"summaryheader\">" + i18n("Cash Flow Summary") + "</div>\n<div class=\"gap\">&nbsp;</div>\n");
+
+ //print header
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ //income and expense title
+ m_part->write("<tr class=\"itemtitle\">");
+ m_part->write("<td class=\"left\" colspan=\"4\">");
+ m_part->write(i18n("Income and Expenses of Current Month"));
+ m_part->write("</td></tr>");
+ //column titles
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Income"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Scheduled Income"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Expenses"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Scheduled Expenses"));
+ m_part->write("</td>");
+ m_part->write("</tr>");
+
+ //add row with banding
+ m_part->write(QString("<tr class=\"row-even\" style=\"font-weight:bold;\">"));
+
+ //print current income
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountIncome, incomeValue.isNegative())));
+
+ //print the scheduled income
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountScheduledIncome, scheduledIncome.isNegative())));
+
+ //print current expenses
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountExpense, expenseValue.isNegative())));
+
+ //print the scheduled expenses
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountScheduledExpense, scheduledExpense.isNegative())));
+ m_part->write("</tr>");
+
+ m_part->write("</table>");
+
+ //print header of assets and liabilities
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ //assets and liabilities title
+ m_part->write("<tr class=\"itemtitle\">");
+ m_part->write("<td class=\"left\" colspan=\"4\">");
+ m_part->write(i18n("Liquid Assets and Liabilities"));
+ m_part->write("</td></tr>");
+ //column titles
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Liquid Assets"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Transfers to Liquid Liabilities"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Liquid Liabilities"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Other Transfers"));
+ m_part->write("</td>");
+ m_part->write("</tr>");
+
+ //add row with banding
+ m_part->write(QString("<tr class=\"row-even\" style=\"font-weight:bold;\">"));
+
+ //print current liquid assets
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountLiquidAssets, liquidAssets.isNegative())));
+
+ //print the scheduled transfers
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountScheduledLiquidTransfer, scheduledLiquidTransfer.isNegative())));
+
+ //print current liabilities
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountLiquidLiabilities, liquidLiabilities.isNegative())));
+
+ //print the scheduled transfers
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountScheduledOtherTransfer, scheduledOtherTransfer.isNegative())));
+
+
+ m_part->write("</tr>");
+
+ m_part->write("</table>");
+
+ //final conclusion
+ MyMoneyMoney profitValue = incomeValue + expenseValue + scheduledIncome + scheduledExpense;
+ MyMoneyMoney expectedAsset = liquidAssets + scheduledIncome + scheduledExpense + scheduledLiquidTransfer + scheduledOtherTransfer;
+ MyMoneyMoney expectedLiabilities = liquidLiabilities + scheduledLiquidTransfer;
+
+ QString amountExpectedAsset = expectedAsset.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountExpectedLiabilities = expectedLiabilities.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ QString amountProfit = profitValue.formatMoney(file->baseCurrency().tradingSymbol(), prec);
+ amountProfit.replace(" ","&nbsp;");
+ amountExpectedAsset.replace(" ","&nbsp;");
+ amountExpectedLiabilities.replace(" ","&nbsp;");
+
+
+
+ //print header of cash flow status
+ m_part->write("<div class=\"gap\">&nbsp;</div>\n");
+ m_part->write("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" class=\"summarytable\" >");
+ //income and expense title
+ m_part->write("<tr class=\"itemtitle\">");
+ m_part->write("<td class=\"left\" colspan=\"4\">");
+ m_part->write(i18n("Cash Flow Status"));
+ m_part->write("</td></tr>");
+ //column titles
+ m_part->write("<tr class=\"item\">");
+ m_part->write("<td>&nbsp;</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Expected Liquid Assets"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Expected Liquid Liabilities"));
+ m_part->write("</td>");
+ m_part->write("<td width=\"25%\" class=\"center\">");
+ m_part->write(i18n("Expected Profit/Loss"));
+ m_part->write("</td>");
+ m_part->write("</tr>");
+
+ //add row with banding
+ m_part->write(QString("<tr class=\"row-even\" style=\"font-weight:bold;\">"));
+ m_part->write("<td>&nbsp;</td>");
+
+ //print expected assets
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountExpectedAsset, expectedAsset.isNegative())));
+
+ //print expected liabilities
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountExpectedLiabilities, expectedLiabilities.isNegative())));
+
+ //print expected profit
+ m_part->write(QString("<td align=\"right\">%2</td>").arg(showColoredAmount(amountProfit, profitValue.isNegative())));
+
+ m_part->write("</tr>");
+
+ m_part->write("</table>");
+
+ m_part->write("</div></div>");
+
+
+}
+
+// Make sure, that these definitions are only used within this file
+// this does not seem to be necessary, but when building RPMs the
+// build option 'final' is used and all CPP files are concatenated.
+// So it could well be, that in another CPP file these definitions
+// are also used.
+#undef VIEW_LEDGER
+#undef VIEW_SCHEDULE
+#undef VIEW_WELCOME
+#undef VIEW_HOME
+#undef VIEW_REPORTS
+
+#include "khomeview.moc"
diff --git a/kmymoney2/views/khomeview.h b/kmymoney2/views/khomeview.h
new file mode 100644
index 0000000..213fd91
--- /dev/null
+++ b/kmymoney2/views/khomeview.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ khomeview.h - description
+ -------------------
+ begin : Tue Jan 22 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KHOMEVIEW_H
+#define KHOMEVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qwidget.h>
+class QVBoxLayout;
+class QFrame;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <khtml_part.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../mymoney/mymoneyscheduled.h"
+#include "../mymoney/mymoneyaccount.h"
+#include "../mymoney/mymoneyforecast.h"
+#include "../views/kmymoneyview.h"
+
+/**
+ * Displays a 'home page' for the user. Similar to concepts used in
+ * quicken and m$-money.
+ *
+ * @author Michael Edwardes
+ *
+ * @short A view containing the home page for kmymoney2.
+**/
+class KHomeView : public KMyMoneyViewBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Definition of bitmap used as argument for showAccounts().
+ */
+ enum paymentTypeE {
+ Preferred = 1, ///< show preferred accounts
+ Payment = 2 ///< show payment accounts
+ };
+
+ KHomeView(QWidget *parent=0, const char *name=0);
+ ~KHomeView();
+
+protected:
+ void showPayments(void);
+ void showPaymentEntry(const MyMoneySchedule&, int cnt = 1);
+ void showAccounts(paymentTypeE type, const QString& hdr);
+ void showAccountEntry(const MyMoneyAccount&);
+ void showFavoriteReports(void);
+ void showForecast(void);
+ void showNetWorthGraph(void);
+ void showSummary(void);
+ void showAssetsLiabilities(void);
+ void showIncomeExpenseSummary(void);
+ void showSchedulesSummary(void);
+ void showBudget(void);
+ void showCashFlowSummary(void);
+
+ const QString link(const QString& view, const QString& query, const QString& title = QString()) const;
+ const QString linkend(void) const;
+ void loadView(void);
+
+public slots:
+ /**
+ * Overridden so we can emit the activated signal.
+ *
+ * @return Nothing.
+ */
+ void show(void);
+
+ void slotOpenURL(const KURL &url, const KParts::URLArgs& args);
+ void slotLoadView(void);
+
+ /**
+ * Print the current view
+ */
+ void slotPrintView(void);
+
+signals:
+ void ledgerSelected(const QString& id, const QString& transaction);
+ void scheduleSelected(const QString& id);
+ void reportSelected(const QString& id);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ /**
+ * daily balances of an account
+ */
+ typedef QMap<QDate, MyMoneyMoney> dailyBalances;
+
+ /**
+ * Print an account and its balance and limit
+ */
+ void showAccountEntry(const MyMoneyAccount& acc, const MyMoneyMoney& value, const MyMoneyMoney& valueToMinBal, const bool showMinBal);
+
+ /**
+ * @param acc the investment account
+ * @return the balance in the currency of the investment account
+ */
+ MyMoneyMoney investmentBalance(const MyMoneyAccount& acc);
+
+ /**
+ * Print text in the color set for negative numbers, if @p amount is negative
+ * abd @p isNegative is true
+ */
+ QString showColoredAmount(const QString& amount, bool isNegative);
+
+ /**
+ * Run the forecast
+ */
+ void doForecast(void);
+
+ /**
+ * Calculate the forecast balance after a payment has been made
+ */
+ MyMoneyMoney forecastPaymentBalance(const MyMoneyAccount& acc, const MyMoneyMoney& payment, QDate& paymentDate);
+
+ KHTMLPart* m_part;
+ QVBoxLayout* m_qvboxlayoutPage;
+ QString m_filename;
+ bool m_showAllSchedules;
+ bool m_needReload;
+ MyMoneyForecast m_forecast;
+
+ /**
+ * daily forecast balance of accounts
+ */
+ QMap<QString, dailyBalances> m_accountList;
+
+};
+
+#endif
diff --git a/kmymoney2/views/kinstitutionsview.cpp b/kmymoney2/views/kinstitutionsview.cpp
new file mode 100644
index 0000000..2c3ac5d
--- /dev/null
+++ b/kmymoney2/views/kinstitutionsview.cpp
@@ -0,0 +1,353 @@
+/***************************************************************************
+ kinstitutionsview.cpp
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qheader.h>
+#include <qlabel.h>
+#include <qtabwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include "kinstitutionsview.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../kmymoney2.h"
+
+KInstitutionsView::KInstitutionsView(QWidget *parent, const char *name) :
+ KInstitutionsViewDecl(parent,name),
+ m_needReload(false)
+{
+ m_accountTree->header()->setLabel(0, i18n("Institution/Account"));
+
+ connect(m_accountTree, SIGNAL(selectObject(const MyMoneyObject&)), this, SIGNAL(selectObject(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(openContextMenu(const MyMoneyObject&)), this, SIGNAL(openContextMenu(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(valueChanged(void)), this, SLOT(slotUpdateNetWorth(void)));
+ connect(m_accountTree, SIGNAL(openObject(const MyMoneyObject&)), this, SIGNAL(openObject(const MyMoneyObject&)));
+ connect(m_accountTree, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&)), this, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadAccounts()));
+}
+
+KInstitutionsView::~KInstitutionsView()
+{
+}
+
+void KInstitutionsView::show(void)
+{
+ if(m_needReload) {
+ loadAccounts();
+ m_needReload = false;
+ }
+
+ // don't forget base class implementation
+ KInstitutionsViewDecl::show();
+
+ // if we have a selected account, let the application know about it
+ KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
+ if(item) {
+ emit selectObject(item->itemObject());
+ }
+}
+
+void KInstitutionsView::polish(void)
+{
+ KInstitutionsViewDecl::polish();
+ m_accountTree->setResizeMode(QListView::LastColumn);
+ m_accountTree->restoreLayout("Institution View Settings");
+}
+
+void KInstitutionsView::slotLoadAccounts(void)
+{
+ if(isVisible()) {
+ loadAccounts();
+ } else {
+ m_needReload = true;
+ }
+}
+
+void KInstitutionsView::loadAccounts(void)
+{
+ QMap<QString, bool> isOpen;
+
+ ::timetrace("start load institutions view");
+ // remember the id of the current selected item
+ KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
+ QString selectedItemId = (item) ? item->id() : QString();
+
+ // keep a map of all 'expanded' accounts
+ QListViewItemIterator it_lvi(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item && item->isOpen()) {
+ isOpen[item->id()] = true;
+ }
+ ++it_lvi;
+ }
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_accountTree->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_accountTree->setUpdatesEnabled(false);
+
+ // clear the current contents and recreate it
+ m_accountTree->clear();
+ m_accountMap.clear();
+ m_securityMap.clear();
+ m_transactionCountMap.clear();
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QValueList<MyMoneyAccount> alist;
+ file->accountList(alist);
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ for(it_a = alist.begin(); it_a != alist.end(); ++it_a) {
+ m_accountMap[(*it_a).id()] = *it_a;
+ }
+
+ // we need to make sure we show stock accounts
+ // under the right institution (the one of the parent account)
+ QMap<QString, MyMoneyAccount>::iterator it_am;
+ for(it_am = m_accountMap.begin(); it_am != m_accountMap.end(); ++it_am) {
+ if((*it_am).isInvest()) {
+ (*it_am).setInstitutionId(m_accountMap[(*it_am).parentAccountId()].institutionId());
+ }
+ }
+
+ QValueList<MyMoneySecurity> slist = file->currencyList();
+ slist += file->securityList();
+ QValueList<MyMoneySecurity>::const_iterator it_s;
+ for(it_s = slist.begin(); it_s != slist.end(); ++it_s) {
+ m_securityMap[(*it_s).id()] = *it_s;
+ }
+
+ m_transactionCountMap = file->transactionCountMap();
+
+ m_accountTree->setBaseCurrency(file->baseCurrency());
+
+ // create the items
+ try {
+ const MyMoneySecurity& security = file->baseCurrency();
+ m_accountTree->setBaseCurrency(security);
+
+ MyMoneyInstitution none;
+ none.setName(i18n("Accounts with no institution assigned"));
+ KMyMoneyAccountTreeItem* noInstitutionItem = new KMyMoneyAccountTreeItem(m_accountTree, none);
+ noInstitutionItem->setPixmap(0,none.pixmap());
+ loadSubAccounts(noInstitutionItem, QString());
+
+ // hide it, if unused
+ noInstitutionItem->setVisible(noInstitutionItem->childCount() != 0);
+
+ QValueList<MyMoneyInstitution> list = file->institutionList();
+ QValueList<MyMoneyInstitution>::const_iterator it_i;
+ for(it_i = list.begin(); it_i != list.end(); ++it_i) {
+ KMyMoneyAccountTreeItem* item = new KMyMoneyAccountTreeItem(m_accountTree, *it_i);
+ item->setPixmap(0, none.pixmap());
+ loadSubAccounts(item, (*it_i).id());
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << "Problem in institutions view: " << e->what();
+ delete e;
+ }
+
+ // scan through the list of accounts and re-expand those that were
+ // expanded and re-select the one that was probably selected before
+ it_lvi = QListViewItemIterator(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item) {
+ if(item->id() == selectedItemId)
+ m_accountTree->setSelected(item, true);
+ if(isOpen.find(item->id()) != isOpen.end())
+ item->setOpen(true);
+ }
+ ++it_lvi;
+ }
+
+ // reposition viewport
+ m_accountTree->setContentsPos(startPoint.x(), startPoint.y());
+
+ // turn updates back on
+ m_accountTree->setUpdatesEnabled(true);
+ m_accountTree->repaintContents();
+
+ ::timetrace("done load institutions view");
+}
+
+void KInstitutionsView::loadSubAccounts(KMyMoneyAccountTreeItem* parent)
+{
+ bool showClosedAccounts = kmymoney2->toggleAction("view_show_all_accounts")->isChecked();
+ const MyMoneyAccount& account = dynamic_cast<const MyMoneyAccount&>(parent->itemObject());
+ QValueList<QString>::const_iterator it_a;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ for(it_a = account.accountList().begin(); it_a != account.accountList().end(); ++it_a) {
+ MyMoneyAccount acc = m_accountMap[(*it_a)];
+ if(!acc.isInvest())
+ continue;
+ if(acc.isClosed() && !showClosedAccounts)
+ continue;
+ const MyMoneySecurity& security = m_securityMap[acc.currencyId()];
+ QValueList<MyMoneyPrice> prices;
+ prices += file->price(acc.currencyId(), security.tradingCurrency());
+ if(security.tradingCurrency() != file->baseCurrency().id()) {
+ MyMoneySecurity sec = m_securityMap[security.tradingCurrency()];
+ prices += file->price(sec.id(), file->baseCurrency().id());
+ }
+ KMyMoneyAccountTreeItem* item = new KMyMoneyAccountTreeItem(parent, acc, prices, security);
+ if(acc.id() == m_reconciliationAccount.id())
+ item->setReconciliation(true);
+ }
+}
+
+void KInstitutionsView::loadSubAccounts(KMyMoneyAccountTreeItem* parent, const QString& institutionId)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QMap<QString, MyMoneyAccount>::const_iterator it_a;
+ MyMoneyMoney value;
+ bool showClosedAccounts = kmymoney2->toggleAction("view_show_all_accounts")->isChecked();
+
+ for(it_a = m_accountMap.begin(); it_a != m_accountMap.end(); ++it_a) {
+ const MyMoneyAccount& acc = *it_a;
+ MyMoneyMoney factor(1,1);
+ switch(acc.accountGroup()) {
+ case MyMoneyAccount::Liability:
+ factor = MyMoneyMoney(-1,1);
+ // tricky fall through here
+
+ case MyMoneyAccount::Asset:
+ if(acc.institutionId() == institutionId
+ && !acc.isInvest()
+ && (!acc.isClosed() || showClosedAccounts)) {
+ QValueList<MyMoneyPrice> prices;
+ MyMoneySecurity security = file->baseCurrency();
+ try {
+ if(acc.currencyId() != file->baseCurrency().id()) {
+ security = m_securityMap[acc.currencyId()];
+ prices += file->price(acc.currencyId(), file->baseCurrency().id());
+ }
+
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << __PRETTY_FUNCTION__ << " caught exception while adding " << acc.name() << "[" << acc.id() << "]: " << e->what();
+ delete e;
+ }
+
+ KMyMoneyAccountTreeItem* item = new KMyMoneyAccountTreeItem(parent, acc, prices, security);
+ if(acc.id() == m_reconciliationAccount.id())
+ item->setReconciliation(true);
+
+ if(acc.accountType() == MyMoneyAccount::Investment)
+ loadSubAccounts(item);
+ value += (item->totalValue() * factor);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // the calulated value for the institution is not correct as
+ // it does not take the negative sign for liability accounts
+ // into account. So we correct this here with the value we
+ // have calculated while filling the list
+ parent->adjustTotalValue(-parent->totalValue()); // load a 0
+ parent->adjustTotalValue(value); // now store the new value
+
+ // we need to call slotUpdateNetWorth() here manually, because
+ // KMyMoneyAccountTreeItem::adjustTotalValue() does not send out
+ // the valueChanged() signal
+ slotUpdateNetWorth();
+}
+
+void KInstitutionsView::slotUpdateNetWorth(void)
+{
+ MyMoneyMoney netWorth;
+
+ // calculate by going through the account trees top items
+ // and summing up the total value shown there
+ KMyMoneyAccountTreeItem* item = dynamic_cast<KMyMoneyAccountTreeItem*>(m_accountTree->firstChild());
+ while(item) {
+ netWorth += item->totalValue();
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(item->nextSibling());
+ }
+
+ QString s(i18n("Net Worth: "));
+
+ // FIXME figure out how to deal with the approximate
+ // if(!(file->totalValueValid(assetAccount.id()) & file->totalValueValid(liabilityAccount.id())))
+ // s += "~ ";
+
+ s.replace(QString(" "), QString("&nbsp;"));
+ if(netWorth.isNegative()) {
+ s += "<b><font color=\"red\">";
+ }
+ const MyMoneySecurity& sec = MyMoneyFile::instance()->baseCurrency();
+ QString v(netWorth.formatMoney(sec));
+ s += v.replace(QString(" "), QString("&nbsp;"));
+ if(netWorth.isNegative()) {
+ s += "</font></b>";
+ }
+
+ m_totalProfitsLabel->setFont(KMyMoneyGlobalSettings::listCellFont());
+ m_totalProfitsLabel->setText(s);
+}
+
+void KInstitutionsView::slotReconcileAccount(const MyMoneyAccount& acc, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance)
+{
+ Q_UNUSED(reconciliationDate);
+ Q_UNUSED(endingBalance);
+
+ // scan through the list of accounts and mark all non
+ // expanded and re-select the one that was probably selected before
+ QListViewItemIterator it_lvi(m_accountTree);
+ KMyMoneyAccountTreeItem* item;
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item) {
+ item->setReconciliation(false);
+ }
+ ++it_lvi;
+ }
+
+ m_reconciliationAccount = acc;
+ if(!acc.id().isEmpty()) {
+ it_lvi = QListViewItemIterator(m_accountTree);
+ while(it_lvi.current()) {
+ item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
+ if(item && item->itemObject().id() == acc.id()) {
+ item->setReconciliation(true);
+ break;
+ }
+ ++it_lvi;
+ }
+ }
+}
+
+
+#include "kinstitutionsview.moc"
diff --git a/kmymoney2/views/kinstitutionsview.h b/kmymoney2/views/kinstitutionsview.h
new file mode 100644
index 0000000..3a35713
--- /dev/null
+++ b/kmymoney2/views/kinstitutionsview.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ kinstitutionssview.h
+ -------------------
+ copyright : (C) 2005 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KINSTITUTIONSVIEW_H
+#define KINSTITUTIONSVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/mymoneyutils.h>
+
+#include "../views/kinstitutionsviewdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class implements the institutions hierarchical 'view'.
+ */
+class KInstitutionsView : public KInstitutionsViewDecl
+{
+ Q_OBJECT
+private:
+
+public:
+ KInstitutionsView(QWidget *parent=0, const char *name=0);
+ virtual ~KInstitutionsView();
+
+public slots:
+ void slotLoadAccounts(void);
+
+ /**
+ * Override the base class behaviour to include all updates that
+ * happened in the meantime.
+ */
+ void show(void);
+
+ /**
+ * Override the base class behaviour to restore the layout. Do not
+ * do this in show() because show() itself may change the layout
+ * in undesired ways.
+ */
+ void polish(void);
+
+ void slotReconcileAccount(const MyMoneyAccount& acc, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance);
+
+protected:
+ void loadAccounts(void);
+
+ // load accounts that are kept at a specific institution
+ void loadSubAccounts(KMyMoneyAccountTreeItem* parent, const QString& institutionId);
+
+ // load stock accounts under the investment account (parent)
+ void loadSubAccounts(KMyMoneyAccountTreeItem* parent);
+
+protected slots:
+ void slotUpdateNetWorth(void);
+
+private:
+ /**
+ * This method returns an icon according to the account type
+ * passed in the argument @p type.
+ *
+ * @param type account type as defined in MyMoneyAccount::accountTypeE
+ */
+ const QPixmap accountImage(const MyMoneyAccount::accountTypeE type) const;
+
+signals:
+ /**
+ * This signal serves as proxy for KMyMoneyAccountTree::selectObject()
+ */
+ void selectObject(const MyMoneyObject&);
+
+ /**
+ * This signal serves as proxy for
+ * KMyMoneyAccountTree::openContextMenu(const MyMoneyObject&)
+ */
+ void openContextMenu(const MyMoneyObject& obj);
+
+ /**
+ * This signal will be emitted when the left mouse button is double
+ * clicked (actually the KDE executed setting is used) on an account
+ * or institution.
+ */
+ void openObject(const MyMoneyObject& obj);
+
+ /**
+ * This signal is emitted, when the user selected to reparent the
+ * account @p acc to be a subordinate account of @p institution.
+ *
+ * @param acc const reference to account to be reparented
+ * @param institution const reference to new institution
+ */
+ void reparent(const MyMoneyAccount& acc, const MyMoneyInstitution& institution);
+
+private:
+ MyMoneyAccount m_reconciliationAccount;
+ QMap<QString, MyMoneyAccount> m_accountMap;
+ QMap<QString, MyMoneySecurity> m_securityMap;
+ QMap<QString, unsigned long> m_transactionCountMap;
+
+ /// set if a view needs to be reloaded during show()
+ bool m_needReload;
+};
+
+#endif
diff --git a/kmymoney2/views/kinstitutionsviewdecl.ui b/kmymoney2/views/kinstitutionsviewdecl.ui
new file mode 100644
index 0000000..3a0a740
--- /dev/null
+++ b/kmymoney2/views/kinstitutionsviewdecl.ui
@@ -0,0 +1,82 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KInstitutionsViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KInstitutionsViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>610</width>
+ <height>378</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KMyMoneyAccountTree">
+ <property name="name">
+ <cstring>m_accountTree</cstring>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_totalProfitsLabel</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Total Profits:</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kinvestmentlistitem.cpp b/kmymoney2/views/kinvestmentlistitem.cpp
new file mode 100644
index 0000000..c2c41d9
--- /dev/null
+++ b/kmymoney2/views/kinvestmentlistitem.cpp
@@ -0,0 +1,294 @@
+/***************************************************************************
+ kinvestmentlistitem.cpp - description
+ -------------------
+ begin : Wed Feb 6 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpainter.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "kinvestmentlistitem.h"
+
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyfile.h>
+
+KInvestmentListItem::KInvestmentListItem(KListView* parent, const MyMoneyAccount& account)
+ : KListViewItem(parent)
+{
+ bColumn5Negative = false;
+ bColumn6Negative = false;
+ bColumn7Negative = false;
+ bColumn8Negative = false;
+ bColumn9Negative = false;
+
+ m_account = account;
+ m_listView = parent;
+
+ MyMoneySecurity security;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ security = file->security(m_account.currencyId());
+ m_tradingCurrency = file->security(security.tradingCurrency());
+
+ int prec = MyMoneyMoney::denomToPrec(m_tradingCurrency.smallestAccountFraction());
+
+ QValueList<MyMoneyTransaction> transactionList;
+ // FIXME PRICE
+ // equity_price_history history = equity.priceHistory();
+
+ //column 0 (COLUMN_NAME_INDEX) is the name of the stock
+ setText(COLUMN_NAME_INDEX, m_account.name());
+
+ //column 1 (COLUMN_SYMBOL_INDEX) is the ticker symbol
+ setText(COLUMN_SYMBOL_INDEX, security.tradingSymbol());
+
+ //column 2 is the net value (price * quantity owned)
+ MyMoneyPrice price = file->price(m_account.currencyId(), m_tradingCurrency.id());
+ if(price.isValid()) {
+ setText(COLUMN_VALUE_INDEX, (file->balance(m_account.id()) * price.rate(m_tradingCurrency.id())).formatMoney(m_tradingCurrency.tradingSymbol(), prec));
+ } else {
+ setText(COLUMN_VALUE_INDEX, "---");
+ }
+
+ //column 3 (COLUMN_QUANTITY_INDEX) is the quantity of shares owned
+ prec = MyMoneyMoney::denomToPrec(security.smallestAccountFraction());
+ setText(COLUMN_QUANTITY_INDEX, file->balance(m_account.id()).formatMoney("", prec));
+
+ //column 4 is the current price
+ // Get the price precision from the configuration
+ prec = KMyMoneyGlobalSettings::pricePrecision();
+
+ // prec = MyMoneyMoney::denomToPrec(m_tradingCurrency.smallestAccountFraction());
+ if(price.isValid()) {
+ setText(COLUMN_PRICE_INDEX, price.rate(m_tradingCurrency.id()).formatMoney(m_tradingCurrency.tradingSymbol(), prec));
+ } else {
+ setText(COLUMN_PRICE_INDEX, "---");
+ }
+}
+
+KInvestmentListItem::~KInvestmentListItem()
+{
+}
+
+// FIXME PRICE
+#if 0
+const QString KInvestmentListItem::calculate1WeekGain(const equity_price_history& history)
+{
+ return calculateGain(history, -7, 0, false, bColumn6Negative);
+}
+
+const QString KInvestmentListItem::calculate4WeekGain(const equity_price_history& history)
+{
+ return calculateGain(history, -28, 0, false, bColumn7Negative);
+}
+
+const QString KInvestmentListItem::calculate3MonthGain(const equity_price_history& history)
+{
+ return calculateGain(history, 0, -3, false, bColumn8Negative);
+}
+
+const QString KInvestmentListItem::calculateYTDGain(const equity_price_history& history)
+{
+ return calculateGain(history, 0, 0, true, bColumn9Negative);
+}
+
+const QString KInvestmentListItem::calculateGain(const equity_price_history& history, int dayDifference, int monthDifference, bool YTD, bool& bNegative)
+{
+ bNegative = false;
+ if(history.isEmpty())
+ {
+ return QString("0.0%");
+ }
+ else
+ {
+ bool bFoundCurrent = false, bFoundComparison = false;
+ QDate tempDate, comparisonDate = QDate::currentDate();
+
+ if(YTD)
+ {
+ //if it is YTD, set the date to 01/01/<current year>
+ comparisonDate.setYMD(comparisonDate.year(), 1, 1);
+ }
+ else
+ {
+ comparisonDate = comparisonDate.addDays(dayDifference);
+ comparisonDate = comparisonDate.addMonths(monthDifference);
+ }
+
+ MyMoneyMoney comparisonValue, currentValue;
+
+ //find the current value, or closest to the current value.
+ equity_price_history::ConstIterator itToday = history.end();
+ for(tempDate = QDate::currentDate(); tempDate >= comparisonDate; )
+ {
+ itToday = history.find(tempDate);
+ if(itToday != history.end())
+ {
+ currentValue = itToday.data();
+ bFoundCurrent = true;
+ break;
+ }
+
+ tempDate = tempDate.addDays(-1);
+ }
+
+ if(!bFoundCurrent)
+ {
+ return QString("0.0%");
+ }
+
+ //find a date that is closest to a week old, not older, and not today's date. Because its a QMap, this map
+ //should already be sorted earliest to latest.
+ for(equity_price_history::ConstIterator it = history.begin(); it != history.end(); ++it)
+ {
+ if(it.key() >= comparisonDate && it.key() < QDate::currentDate())
+ {
+ comparisonDate = it.key();
+ comparisonValue = it.data();
+ bFoundComparison = true;
+ break;
+ }
+ }
+
+ if(!bFoundComparison)
+ {
+ return QString("0.0%");
+ }
+
+ //qDebug("Current date/value to use is %s/%s, Previous is %s/%s", tempDate.toString().data(), currentValue.toString().data(), comparisonDate.toString().data(), comparisonValue.toString().data());
+
+ //compute the percentage difference
+ if(comparisonValue != currentValue)
+ {
+ double result = (currentValue.toDouble() / comparisonValue.toDouble()) * 100.0;
+ result -= 100.0;
+ if(result < 0.0)
+ {
+ bNegative = true;
+ }
+
+ QString ds = QString("%1%").arg(result, 0, 'f', 3);
+ return ds;
+
+ /*MyMoneyMoney result = (currentValue / comparisonValue);
+ result = result * 100;
+ result = result - 100;
+ qDebug("final result = %s", result.toString().data());
+ return QString(result.formatMoney("", 3) + "%");*/
+ }
+ }
+ return QString("");
+}
+#endif
+
+int KInvestmentListItem::compare(QListViewItem* i, int col, bool ascending) const
+{
+ KInvestmentListItem* item = dynamic_cast<KInvestmentListItem*>(i);
+ // do special sorting only for numeric columns
+ // in all other cases use the standard sorting
+ if(item) {
+ switch(col) {
+ case COLUMN_VALUE_INDEX:
+ case COLUMN_QUANTITY_INDEX:
+ case COLUMN_PRICE_INDEX:
+ {
+ bool inv1 = text(col) == "---";
+ bool inv2 = item->text(col) == "---";
+ if(!inv1 && !inv2) {
+ MyMoneyMoney result = MyMoneyMoney(text(col)) - MyMoneyMoney(item->text(col));
+ if(result.isNegative())
+ return -1;
+ if(result.isZero())
+ return 0;
+ return 1;
+ } else if(inv1 && inv2) {
+ return 0;
+ } else if(inv1) {
+ return -1;
+ }
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // do standard sorting here
+ return KListViewItem::compare(i, col, ascending);
+}
+
+void KInvestmentListItem::paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int align)
+{
+ bool bPaintRed = false;
+ if((column == COLUMN_RAWGAIN_INDEX && bColumn5Negative) ||
+ (column == COLUMN_1WEEKGAIN_INDEX && bColumn6Negative) ||
+ (column == COLUMN_4WEEKGAIN_INDEX && bColumn7Negative) ||
+ (column == COLUMN_3MONGAIN_INDEX && bColumn8Negative) ||
+ (column == COLUMN_YTDGAIN_INDEX && bColumn9Negative))
+ {
+ bPaintRed = true;
+ }
+
+ p->save();
+
+ QColorGroup cg2(cg);
+
+ if(isAlternate())
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+
+#ifndef KMM_DESIGNER
+ QFont font = KMyMoneyGlobalSettings::listCellFont();
+ // strike out closed accounts
+ if(m_account.isClosed())
+ font.setStrikeOut(true);
+
+ p->setFont(font);
+#endif
+
+ if(bPaintRed)
+ {
+ QColorGroup _cg( cg2);
+ QColor c = _cg.text();
+ _cg.setColor(QColorGroup::Text, Qt::red);
+ QListViewItem::paintCell(p, _cg, column, width, align);
+ _cg.setColor(QColorGroup::Text, c);
+ }
+ else
+ {
+ QListViewItem::paintCell(p, cg2, column, width, align);
+ }
+
+ p->restore();
+}
diff --git a/kmymoney2/views/kinvestmentlistitem.h b/kmymoney2/views/kinvestmentlistitem.h
new file mode 100644
index 0000000..d0ad62b
--- /dev/null
+++ b/kmymoney2/views/kinvestmentlistitem.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ kinvestmentlistitem.h - description
+ -------------------
+ begin : Wed Feb 6 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KINVESTMENTLISTITEM_H
+#define KINVESTMENTLISTITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneyobserver.h>
+
+//indexes for the various columns on the summary view
+#define COLUMN_NAME_INDEX 0
+#define COLUMN_SYMBOL_INDEX 1
+#define COLUMN_VALUE_INDEX 2
+#define COLUMN_QUANTITY_INDEX 3
+#define COLUMN_PRICE_INDEX 4
+#define COLUMN_COSTBASIS_INDEX 5
+#define COLUMN_RAWGAIN_INDEX 6
+#define COLUMN_1WEEKGAIN_INDEX 7
+#define COLUMN_4WEEKGAIN_INDEX 8
+#define COLUMN_3MONGAIN_INDEX 9
+#define COLUMN_YTDGAIN_INDEX 10
+
+/**
+ * @author Kevin Tambascio
+ * @author Thomas Baumgart
+ */
+class KInvestmentListItem : public KListViewItem
+{
+public:
+ KInvestmentListItem(KListView* parent, const MyMoneyAccount& security);
+ ~KInvestmentListItem();
+
+ QString securityId() const { return m_account.currencyId(); };
+ const MyMoneyAccount& account(void) const { return m_account; };
+ const MyMoneySecurity tradingCurrency(void) const { return m_tradingCurrency; };
+
+ /**
+ * Helper method to show the right order
+ */
+ int compare(QListViewItem* i, int col, bool ascending) const;
+
+
+protected:
+ void paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int align);
+
+private:
+ // FIXME PRICE
+#if 0
+ const QString calculate1WeekGain(const equity_price_history& history);
+ const QString calculate4WeekGain(const equity_price_history& history);
+ const QString calculate3MonthGain(const equity_price_history& history);
+ const QString calculateYTDGain(const equity_price_history& history);
+ const QString calculateGain(const equity_price_history& history, int dayDifference, int monthDifference, bool YTD, bool& bNegative);
+#endif
+
+private:
+ KListView* m_listView;
+ MyMoneyAccount m_account;
+ MyMoneySecurity m_tradingCurrency;
+ bool bColumn5Negative, bColumn6Negative, bColumn7Negative, bColumn8Negative, bColumn9Negative;
+};
+
+#endif
diff --git a/kmymoney2/views/kinvestmentview.cpp b/kmymoney2/views/kinvestmentview.cpp
new file mode 100644
index 0000000..ae8cc11
--- /dev/null
+++ b/kmymoney2/views/kinvestmentview.cpp
@@ -0,0 +1,322 @@
+/***************************************************************************
+ kinvestmentview.cpp - description
+ -------------------
+ begin : Mon Mar 12 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <typeinfo>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneyinvesttransaction.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/kmymoneyaccountcombo.h>
+#include <kmymoney/kmymoneycurrencyselector.h>
+
+#include "../kmymoney2.h"
+
+#include "kinvestmentview.h"
+#include "kinvestmentlistitem.h"
+
+class KInvestmentView::Private
+{
+public:
+ Private() :
+ m_needReload(false),
+ m_newAccountLoaded(false),
+ m_recursion(false),
+ m_precision(2) {}
+
+ MyMoneyAccount m_account;
+ bool m_needReload;
+ bool m_newAccountLoaded;
+ bool m_recursion;
+ int m_precision;
+};
+
+
+
+KInvestmentView::KInvestmentView(QWidget *parent, const char *name) :
+ KInvestmentViewDecl(parent,name),
+ d(new Private)
+{
+ m_table->setRootIsDecorated(false);
+ // m_table->setColumnText(0, i18n("Symbol"));
+ m_table->addColumn(i18n("Name"));
+ m_table->addColumn(i18n("Symbol"));
+
+ int col = m_table->addColumn(i18n("Value"));
+ m_table->setColumnAlignment(col, Qt::AlignRight);
+
+ col = m_table->addColumn(i18n("Quantity"));
+ m_table->setColumnAlignment(col, Qt::AlignRight);
+
+ col = m_table->addColumn(i18n("Price"));
+ m_table->setColumnAlignment(col, Qt::AlignRight);
+
+ m_table->setMultiSelection(false);
+ m_table->setColumnWidthMode(0, QListView::Maximum);
+ m_table->header()->setResizeEnabled(true);
+ m_table->setAllColumnsShowFocus(true);
+ m_table->setShowSortIndicator(true);
+ m_table->restoreLayout(KGlobal::config(), "Investment Settings");
+
+ connect(m_table, SIGNAL(contextMenu(KListView*, QListViewItem* , const QPoint&)),
+ this, SLOT(slotListContextMenu(KListView*, QListViewItem*, const QPoint&)));
+ connect(m_table, SIGNAL(selectionChanged(QListViewItem *)), this, SLOT(slotSelectionChanged(QListViewItem *)));
+
+ connect(m_accountComboBox, SIGNAL(accountSelected(const QString&)),
+ this, SLOT(slotSelectAccount(const QString&)));
+
+ connect(m_table, SIGNAL(doubleClicked(QListViewItem*,const QPoint&, int)), kmymoney2->action("investment_edit"), SLOT(activate()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadView()));
+}
+
+KInvestmentView::~KInvestmentView()
+{
+ m_table->saveLayout(KGlobal::config(), "Investment Settings");
+ delete d;
+}
+
+void KInvestmentView::slotSelectionChanged(QListViewItem *item)
+{
+ kmymoney2->slotSelectInvestment();
+
+ KInvestmentListItem *pItem = dynamic_cast<KInvestmentListItem*>(item);
+ if(pItem) {
+ try {
+ MyMoneyAccount account = MyMoneyFile::instance()->account(pItem->account().id());
+ kmymoney2->slotSelectInvestment(account);
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ }
+}
+
+void KInvestmentView::slotListContextMenu(KListView* /* lv */, QListViewItem* /*item*/, const QPoint& /*point*/)
+{
+ kmymoney2->slotSelectInvestment();
+ KInvestmentListItem *pItem = dynamic_cast<KInvestmentListItem*>(m_table->selectedItem());
+ if(pItem) {
+ kmymoney2->slotSelectInvestment(MyMoneyFile::instance()->account(pItem->account().id()));
+ }
+ emit investmentRightMouseClick();
+}
+
+void KInvestmentView::slotLoadView(void)
+{
+ d->m_needReload = true;
+ if(isVisible()) {
+ loadView();
+ d->m_needReload = false;
+ // force a new account if the current one is empty
+ d->m_newAccountLoaded = d->m_account.id().isEmpty();
+ }
+}
+
+void KInvestmentView::loadAccounts(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // check if the current account still exists and make it the
+ // current account
+ if(!d->m_account.id().isEmpty()) {
+ try {
+ d->m_account = file->account(d->m_account.id());
+ } catch(MyMoneyException *e) {
+ delete e;
+ d->m_account = MyMoneyAccount();
+ }
+ }
+
+ m_accountComboBox->loadList(MyMoneyAccount::Investment);
+
+ if(d->m_account.id().isEmpty()) {
+ QStringList list = m_accountComboBox->accountList();
+ if(list.count()) {
+ QStringList::Iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ MyMoneyAccount a = file->account(*it);
+ if(a.accountType() == MyMoneyAccount::Investment) {
+ if(a.value("PreferredAccount") == "Yes") {
+ d->m_account = a;
+ break;
+ } else if(d->m_account.id().isEmpty()) {
+ d->m_account = a;
+ }
+ }
+ }
+ }
+ }
+
+ if(!d->m_account.id().isEmpty()) {
+ m_accountComboBox->setSelected(d->m_account);
+ try {
+ d->m_precision = MyMoneyMoney::denomToPrec(d->m_account.fraction());
+ } catch(MyMoneyException *e) {
+ qDebug("Security %s for account %s not found", d->m_account.currencyId().data(), d->m_account.name().data());
+ delete e;
+ d->m_precision = 2;
+ }
+ }
+}
+
+
+bool KInvestmentView::slotSelectAccount(const MyMoneyObject& obj)
+{
+ if(typeid(obj) != typeid(MyMoneyAccount))
+ return false;
+
+ if(d->m_recursion)
+ return false;
+
+ d->m_recursion = true;
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(obj);
+ bool rc = slotSelectAccount(acc.id());
+ d->m_recursion = false;
+ return rc;
+}
+
+bool KInvestmentView::slotSelectAccount(const QString& id, const QString& transactionId, const bool /* reconciliation*/)
+{
+ bool rc = true;
+
+ if(!id.isEmpty()) {
+ // if the account id differs, then we have to do something
+ if(d->m_account.id() != id) {
+ try {
+ d->m_account = MyMoneyFile::instance()->account(id);
+ // if a stock account is selected, we show the
+ // the corresponding parent (investment) account
+ if(d->m_account.isInvest()) {
+ d->m_account = MyMoneyFile::instance()->account(d->m_account.parentAccountId());
+ }
+ // TODO if we don't have an investment account, then we should switch to the ledger view
+ d->m_newAccountLoaded = true;
+ if(d->m_account.accountType() == MyMoneyAccount::Investment) {
+ slotLoadView();
+ } else {
+ emit accountSelected(id, transactionId);
+ d->m_account = MyMoneyAccount();
+ d->m_needReload = true;
+ rc = false;
+ }
+
+ } catch(MyMoneyException* e) {
+ qDebug("Unable to retrieve account %s", id.data());
+ delete e;
+ rc = false;
+ }
+ } else {
+ emit accountSelected(d->m_account);
+ }
+ }
+
+ return rc;
+}
+
+void KInvestmentView::clear(void)
+{
+ // setup header font
+ QFont font = KMyMoneyGlobalSettings::listHeaderFont();
+ QFontMetrics fm( font );
+ int height = fm.lineSpacing()+6;
+ m_table->header()->setMinimumHeight(height);
+ m_table->header()->setMaximumHeight(height);
+ m_table->header()->setFont(font);
+
+ // setup cell font
+ font = KMyMoneyGlobalSettings::listCellFont();
+ m_table->setFont(font);
+
+ // clear the table
+ m_table->clear();
+
+ // and the selected account in the combo box
+ m_accountComboBox->setSelected(QString());
+}
+
+void KInvestmentView::loadView(void)
+{
+ // no account selected
+ emit accountSelected(MyMoneyAccount());
+
+ // clear the current contents ...
+ clear();
+
+ // ... load the combobox widget and select current account ...
+ loadAccounts();
+
+ if(d->m_account.id().isEmpty()) {
+ // if we don't have an account we bail out
+ setEnabled(false);
+ return;
+ }
+ setEnabled(true);
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ bool showClosedAccounts = kmymoney2->toggleAction("view_show_all_accounts")->isChecked()
+ || !KMyMoneyGlobalSettings::hideClosedAccounts();
+ try {
+ d->m_account = file->account(d->m_account.id());
+ QStringList securities = d->m_account.accountList();
+
+ for(QStringList::ConstIterator it = securities.begin(); it != securities.end(); ++it) {
+ MyMoneyAccount acc = file->account(*it);
+ if(!acc.isClosed() || showClosedAccounts)
+ new KInvestmentListItem(m_table, acc);
+ }
+ } catch(MyMoneyException* e) {
+ qDebug("KInvestmentView::loadView() - selected account does not exist anymore");
+ d->m_account = MyMoneyAccount();
+ delete e;
+ }
+
+ // and tell everyone what's selected
+ emit accountSelected(d->m_account);
+}
+
+void KInvestmentView::show(void)
+{
+ if(d->m_needReload) {
+ loadView();
+ d->m_needReload = false;
+ d->m_newAccountLoaded = false;
+
+ } else {
+ emit accountSelected(d->m_account);
+ }
+
+ // don't forget base class implementation
+ KInvestmentViewDecl::show();
+}
+
+#include "kinvestmentview.moc"
diff --git a/kmymoney2/views/kinvestmentview.h b/kmymoney2/views/kinvestmentview.h
new file mode 100644
index 0000000..ba0aecc
--- /dev/null
+++ b/kmymoney2/views/kinvestmentview.h
@@ -0,0 +1,136 @@
+/***************************************************************************
+ kinvestmentview.h - description
+ -------------------
+ begin : Tue Jan 29 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KINVESTMENTVIEW_H
+#define KINVESTMENTVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyaccount.h>
+#include "kinvestmentviewdecl.h"
+#include "kinvestmentlistitem.h"
+
+class MyMoneyTransaction;
+class MyMoneyInvestTransaction;
+
+/**
+ * @author Kevin Tambascio
+ */
+
+class KInvestmentView : public KInvestmentViewDecl
+{
+ Q_OBJECT
+
+public:
+ KInvestmentView(QWidget *parent=0, const char *name=0);
+ ~KInvestmentView();
+
+ /**
+ * Start reconciliation for the account in the current view
+ */
+ void reconcileAccount(void);
+
+public slots:
+ /**
+ * This slot is used to reload all data from the MyMoneyFile engine.
+ * All existing data in the view will be discarded.
+ * Call this e.g. if a new file has been loaded.
+ */
+ void slotLoadView(void);
+
+ /**
+ * This slot is used to select the correct ledger view type for
+ * the account specified by @p id. If @p transactionId is not
+ * empty, then the respective transaction will be selected.
+ *
+ * @param accountId Internal id used for the account to show
+ * @param transactionId Internal id used for the transaction to select
+ * @param reconciliation if true, the account will be selected in
+ * reconciliation mode. If false, it will
+ * be selected in regular ledger mode.
+ *
+ * @retval true selection of account referenced by @p id succeeded
+ * @retval false selection of account failed
+ */
+ bool slotSelectAccount(const QString& accountId, const QString& transactionId = QString(), const bool reconciliation = false);
+
+ /**
+ * This method is provided for convenience and acts as the method above.
+ */
+ bool slotSelectAccount(const MyMoneyObject& acc);
+
+ void show(void);
+
+protected:
+ /**
+ * This method reloads the account selection combo box of the
+ * view with all asset and liability accounts from the engine.
+ * If the account id of the current account held in @p m_accountId is
+ * empty or if the referenced account does not exist in the engine,
+ * the first account found in the list will be made the current account.
+ */
+ void loadAccounts(void);
+
+ /**
+ * clear the view
+ */
+ void clear(void);
+
+ void loadView(void);
+
+protected slots:
+ /**
+ * This slot receives the signal from the listview @c lv control that the context menu
+ * was requested for @c item at @c point.
+ */
+ void slotListContextMenu(KListView* lv, QListViewItem* item, const QPoint& point);
+
+ void slotSelectionChanged(QListViewItem *item);
+
+
+signals:
+ /**
+ * This signal is emitted, if an account has been selected
+ * which cannot handled by this view.
+ */
+ void accountSelected(const QString& accountId, const QString& transactionId);
+
+ void accountSelected(const MyMoneyObject&);
+
+ void investmentRightMouseClick(void);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kmymoney2/views/kinvestmentviewdecl.ui b/kmymoney2/views/kinvestmentviewdecl.ui
new file mode 100644
index 0000000..1c74d50
--- /dev/null
+++ b/kmymoney2/views/kinvestmentviewdecl.ui
@@ -0,0 +1,83 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KInvestmentViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KInvestmentViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>707</width>
+ <height>346</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Investment Summary</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Select Account:</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyAccountCombo">
+ <property name="name">
+ <cstring>m_accountComboBox</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>280</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>m_table</cstring>
+ </property>
+ <property name="font">
+ <font>
+ </font>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Summary of the equities contained in this account, showing your holdings and their most recent price.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kmymoneyfile.cpp b/kmymoney2/views/kmymoneyfile.cpp
new file mode 100644
index 0000000..4046cc0
--- /dev/null
+++ b/kmymoney2/views/kmymoneyfile.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ kmymoneyfile.cpp - description
+ -------------------
+ begin : Mon Jun 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+/*
+ * This file is currently not used anymore, but kept here for reference purposes
+ */
+#if 0
+
+#include <klocale.h>
+
+#include "kmymoneyfile.h"
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+
+KMyMoneyFile::KMyMoneyFile()
+{
+ // m_file = MyMoneyFile::instance();
+ m_storage = new MyMoneySeqAccessMgr;
+ // m_file->attachStorage(m_storage);
+ m_open = false; // lie a little bit for now
+}
+
+/*
+KMyMoneyFile::KMyMoneyFile(const QString&)
+{
+}
+*/
+
+KMyMoneyFile::~KMyMoneyFile()
+{
+ if(m_storage) {
+ MyMoneyFile::instance()->detachStorage(m_storage);
+ delete m_storage;
+ }
+
+ // if(m_file)
+ // delete m_file;
+}
+
+/*
+KMyMoneyFile *KMyMoneyFile::instance()
+{
+ if (_instance == 0) {
+ _instance = new KMyMoneyFile;
+ }
+
+ return _instance;
+}
+
+MyMoneyFile* KMyMoneyFile::file()
+{
+ return m_file;
+}
+*/
+
+MyMoneySeqAccessMgr* KMyMoneyFile::storage()
+{
+ return m_storage;
+}
+
+void KMyMoneyFile::reset()
+{
+/*
+ delete m_storage;
+ delete m_file;
+ m_storage = new MyMoneySeqAccessMgr;
+ m_file = new MyMoneyFile(m_storage);
+*/
+}
+
+void KMyMoneyFile::open()
+{
+ if(m_storage != 0)
+ close();
+
+ m_storage = new MyMoneySeqAccessMgr;
+ MyMoneyFile::instance()->attachStorage(m_storage);
+ m_open = true;
+}
+
+void KMyMoneyFile::close()
+{
+ if(m_storage != 0) {
+ MyMoneyFile::instance()->detachStorage(m_storage);
+ delete m_storage;
+ m_storage = 0;
+ }
+ m_open = false;
+}
+
+bool KMyMoneyFile::isOpen()
+{
+ return m_open;
+}
+
+#endif
diff --git a/kmymoney2/views/kmymoneyfile.h b/kmymoney2/views/kmymoneyfile.h
new file mode 100644
index 0000000..ccda128
--- /dev/null
+++ b/kmymoney2/views/kmymoneyfile.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ kmymoneyfile.h - description
+ -------------------
+ begin : Mon Jun 10 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYFILE_H
+#define KMYMONEYFILE_H
+
+/*
+ * This file is currently not used anymore, but kept here for reference purposes
+ */
+#if 0
+#include "../mymoney/mymoneyaccount.h"
+class MyMoneySeqAccessMgr;
+
+/**
+ *@author Michael Edwardes
+ */
+
+class KMyMoneyFile {
+private:
+ // static KMyMoneyFile *_instance;
+ // MyMoneyFile *m_file;
+ MyMoneySeqAccessMgr *m_storage;
+ bool m_open;
+
+protected:
+ // KMyMoneyFile(const QString&);
+
+public:
+ KMyMoneyFile();
+ ~KMyMoneyFile();
+// static KMyMoneyFile *instance();
+
+ // MyMoneyFile* file();
+ MyMoneySeqAccessMgr* storage();
+ void reset();
+ void open();
+ void close();
+ bool isOpen();
+
+};
+#endif
+#endif
diff --git a/kmymoney2/views/kmymoneytransaction.cpp b/kmymoney2/views/kmymoneytransaction.cpp
new file mode 100644
index 0000000..ee16a6a
--- /dev/null
+++ b/kmymoney2/views/kmymoneytransaction.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+ kmymoneytransaction.cpp - description
+ -------------------
+ begin : Fri Sep 5 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include "kmymoneytransaction.h"
+
+KMyMoneyTransaction::KMyMoneyTransaction()
+{
+}
+
+KMyMoneyTransaction::KMyMoneyTransaction(const MyMoneyTransaction& t) :
+ MyMoneyTransaction(t)
+{
+}
+
+KMyMoneyTransaction::~KMyMoneyTransaction()
+{
+}
+
+void KMyMoneyTransaction::setSplitId(const QString& id)
+{
+ m_splitId = id;
+}
+
+
diff --git a/kmymoney2/views/kmymoneytransaction.h b/kmymoney2/views/kmymoneytransaction.h
new file mode 100644
index 0000000..4deb184
--- /dev/null
+++ b/kmymoney2/views/kmymoneytransaction.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ kmymoneytransaction.h - description
+ -------------------
+ begin : Fri Sep 5 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYTRANSACTION_H
+#define KMYMONEYTRANSACTION_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytransaction.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class is used to store the information required to
+ * display a transaction in a ledger view (register).
+ * It is derived from MyMoneyTransaction but contains additional
+ * information.
+ */
+class KMyMoneyTransaction : public MyMoneyTransaction {
+public:
+ KMyMoneyTransaction();
+ KMyMoneyTransaction(const MyMoneyTransaction& t);
+ ~KMyMoneyTransaction();
+
+ void setSplitId(const QString& id);
+ const QString& splitId(void) const { return m_splitId; };
+
+private:
+ QString m_splitId;
+};
+
+
+#endif
diff --git a/kmymoney2/views/kmymoneyview.cpp b/kmymoney2/views/kmymoneyview.cpp
new file mode 100644
index 0000000..8719d79
--- /dev/null
+++ b/kmymoney2/views/kmymoneyview.cpp
@@ -0,0 +1,2248 @@
+/***************************************************************************
+ kmymoneyview.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ 2004 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <unistd.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qprogressdialog.h>
+#include <qtextcodec.h>
+#include <qstatusbar.h>
+
+#include <qcursor.h>
+#include <qregexp.h>
+#include <qlayout.h>
+#include <qobjectlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kicontheme.h>
+#include <kiconloader.h>
+
+#include <kmessagebox.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+#include <ktempfile.h>
+#include <ksavefile.h>
+#include <kfilterdev.h>
+#include <kfilterbase.h>
+#include <kfileitem.h>
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+// This is include is required here, because later it will produce
+// compile errors on gcc 3.2 as we redefine new() in case of _CHECK_MEMORY
+// being defined. To avoid these problems, we just include the header
+// already here in this case
+#ifdef _CHECK_MEMORY
+#include <string>
+#endif
+
+#include "../dialogs/kendingbalancedlg.h"
+#include "../dialogs/kchooseimportexportdlg.h"
+#include "../dialogs/kcsvprogressdlg.h"
+#include "../dialogs/kimportdlg.h"
+#include "../dialogs/kexportdlg.h"
+#include "../dialogs/knewloanwizard.h"
+#include "../dialogs/kcurrencyeditdlg.h"
+#include "../dialogs/kfindtransactiondlg.h"
+#include "../dialogs/knewbankdlg.h"
+#include "../dialogs/knewfiledlg.h"
+
+#include "../mymoney/storage/mymoneyseqaccessmgr.h"
+#include "../mymoney/storage/mymoneydatabasemgr.h"
+#include "../mymoney/storage/imymoneystorageformat.h"
+#include "../mymoney/storage/mymoneystoragebin.h"
+#include "../mymoney/mymoneyexception.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+#include "../mymoney/storage/mymoneystoragesql.h"
+#include "../converter/mymoneygncreader.h"
+#include "../mymoney/storage/mymoneystorageanon.h"
+
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "kmymoneyview.h"
+#include "khomeview.h"
+#include "kaccountsview.h"
+#include "kcategoriesview.h"
+#include "kinstitutionsview.h"
+#include "kpayeesview.h"
+#include "kscheduledview.h"
+#include "kgloballedgerview.h"
+#include "kinvestmentview.h"
+#include "kreportsview.h"
+#include "kbudgetview.h"
+#include "kforecastview.h"
+
+#include <kmymoney/kmymoneytitlelabel.h>
+
+
+#include "../kmymoney2.h"
+#include "../kmymoneyutils.h"
+
+#include <libkgpgfile/kgpgfile.h>
+
+#define COMPRESSION_MIME_TYPE "application/x-gzip"
+#define RECOVER_KEY_ID "0xD2B08440"
+
+
+KMyMoneyView::KMyMoneyView(QWidget *parent, const char *name)
+ : KJanusWidget(parent, name, KJanusWidget::IconList),
+ // m_bankRightClick(false),
+ m_inConstructor(true),
+ m_fileOpen(false),
+ m_fmode(0600)
+{
+ // the global variable kmymoney2 is not yet assigned. So we construct it here
+ QObject* kmymoney2 = parent->parent();
+ const int iconSize = (KMyMoneyGlobalSettings::iconSize()+1)*16;
+ newStorage();
+
+ // Page 0
+ m_homeViewFrame = addVBoxPage( i18n("Home"), i18n("Home"),
+ DesktopIcon("home", iconSize));
+
+ m_homeView = new KHomeView(m_homeViewFrame, "HomeView");
+ connect(m_homeView, SIGNAL(ledgerSelected(const QString&, const QString&)),
+ this, SLOT(slotLedgerSelected(const QString&, const QString&)));
+ connect(m_homeView, SIGNAL(scheduleSelected(const QString&)),
+ this, SLOT(slotScheduleSelected(const QString&)));
+ connect(m_homeView, SIGNAL(reportSelected(const QString&)),
+ this, SLOT(slotShowReport(const QString&)));
+
+ // Page 1
+ m_institutionsViewFrame = addVBoxPage( i18n("Institutions"), i18n("Institutions"),
+ DesktopIcon("institutions", iconSize));
+ addTitleBar(m_institutionsViewFrame, i18n("Institutions"));
+ m_institutionsView = new KInstitutionsView(m_institutionsViewFrame, "InstitutionsView");
+ connect(m_institutionsView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ connect(m_institutionsView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectInstitution(const MyMoneyObject&)));
+ connect(m_institutionsView, SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, SLOT(slotShowAccountContextMenu(const MyMoneyObject&)));
+ connect(m_institutionsView, SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, SLOT(slotShowInstitutionContextMenu(const MyMoneyObject&)));
+ connect(m_institutionsView, SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, SLOT(slotInstitutionEdit(const MyMoneyObject&)));
+ connect(m_institutionsView, SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, SLOT(slotAccountOpen(const MyMoneyObject&)));
+ connect(m_institutionsView, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&)), kmymoney2, SLOT(slotReparentAccount(const MyMoneyAccount&, const MyMoneyInstitution&)));
+ connect(this, SIGNAL(reconciliationStarts(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&)), m_institutionsView, SLOT(slotReconcileAccount(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&)));
+
+ // Page 2
+ m_accountsViewFrame = addVBoxPage( i18n("Accounts"), i18n("Accounts"),
+ DesktopIcon("accounts", iconSize));
+ addTitleBar(m_accountsViewFrame, i18n("Accounts"));
+ m_accountsView = new KAccountsView(m_accountsViewFrame, "AccountsView");
+ connect(m_accountsView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ connect(m_accountsView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectInstitution(const MyMoneyObject&)));
+ connect(m_accountsView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectInvestment(const MyMoneyObject&)));
+ connect(m_accountsView, SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, SLOT(slotShowAccountContextMenu(const MyMoneyObject&)));
+ connect(m_accountsView, SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, SLOT(slotAccountOpen(const MyMoneyObject&)));
+ connect(m_accountsView, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotReparentAccount(const MyMoneyAccount&, const MyMoneyAccount&)));
+ connect(this, SIGNAL(kmmFilePlugin(unsigned int)), m_accountsView, SLOT(slotUpdateIconPos(unsigned int)));
+ connect(this, SIGNAL(reconciliationStarts(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&)), m_accountsView, SLOT(slotReconcileAccount(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&)));
+
+ // Page 3
+ m_scheduleViewFrame = addVBoxPage( i18n("Scheduled\ntransactions"), i18n("Bills & Reminders"),
+ DesktopIcon("schedule", iconSize));
+ addTitleBar(m_scheduleViewFrame, i18n("Scheduled transactions"));
+ m_scheduledView = new KScheduledView(m_scheduleViewFrame, "ScheduledView");
+ connect(kmymoney2, SIGNAL(fileLoaded(const KURL&)), m_scheduledView, SLOT(slotReloadView()));
+ connect(m_scheduledView, SIGNAL(scheduleSelected(const MyMoneySchedule&)), kmymoney2, SLOT(slotSelectSchedule(const MyMoneySchedule&)));
+ connect(m_scheduledView, SIGNAL(openContextMenu()), kmymoney2, SLOT(slotShowScheduleContextMenu()));
+ connect(m_scheduledView, SIGNAL(enterSchedule()), kmymoney2, SLOT(slotScheduleEnter()));
+ connect(m_scheduledView, SIGNAL(skipSchedule()), kmymoney2, SLOT(slotScheduleSkip()));
+ connect(m_scheduledView, SIGNAL(editSchedule()), kmymoney2, SLOT(slotScheduleEdit()));
+
+ // Page 4
+ m_categoriesViewFrame = addVBoxPage( i18n("Categories"), i18n("Categories"),
+ DesktopIcon("categories", iconSize));
+ addTitleBar(m_categoriesViewFrame, i18n("Categories"));
+ m_categoriesView = new KCategoriesView(m_categoriesViewFrame, "CategoriesView");
+ connect(m_categoriesView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ connect(m_categoriesView, SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectInstitution(const MyMoneyObject&)));
+ connect(m_categoriesView, SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, SLOT(slotShowAccountContextMenu(const MyMoneyObject&)));
+ connect(m_categoriesView, SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, SLOT(slotAccountOpen(const MyMoneyObject&)));
+ connect(m_categoriesView, SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, SLOT(slotReparentAccount(const MyMoneyAccount&, const MyMoneyAccount&)));
+
+ // Page 5
+ m_payeesViewFrame = addVBoxPage( i18n("Payees"), i18n("Payees"),
+ DesktopIcon("payee", iconSize));
+ addTitleBar(m_payeesViewFrame, i18n("Payees"));
+ m_payeesView = new KPayeesView(m_payeesViewFrame, "PayeesView");
+ connect(kmymoney2, SIGNAL(payeeCreated(const QString&)), m_payeesView, SLOT(slotSelectPayeeAndTransaction(const QString&)));
+ connect(kmymoney2, SIGNAL(payeeRename()), m_payeesView, SLOT(slotStartRename()));
+ connect(m_payeesView, SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, SLOT(slotShowPayeeContextMenu()));
+ connect(m_payeesView, SIGNAL(selectObjects(const QValueList<MyMoneyPayee>&)), kmymoney2, SLOT(slotSelectPayees(const QValueList<MyMoneyPayee>&)));
+ connect(m_payeesView, SIGNAL(transactionSelected(const QString&, const QString&)),
+ this, SLOT(slotLedgerSelected(const QString&, const QString&)));
+
+ // Page 6
+ m_ledgerViewFrame = addVBoxPage( i18n("Ledgers"), i18n("Ledgers"),
+ DesktopIcon("ledger", iconSize));
+ m_ledgerView = new KGlobalLedgerView(m_ledgerViewFrame, "GlobalLedgerView");
+ connect(m_ledgerView, SIGNAL(accountSelected(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ connect(m_ledgerView, SIGNAL(openContextMenu()), kmymoney2, SLOT(slotShowTransactionContextMenu()));
+ connect(m_ledgerView, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)), kmymoney2, SLOT(slotSelectTransactions(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(m_ledgerView, SIGNAL(newTransaction()), kmymoney2, SLOT(slotTransactionsNew()));
+ connect(m_ledgerView, SIGNAL(cancelOrEndEdit(bool&)), kmymoney2, SLOT(slotTransactionsCancelOrEnter(bool&)));
+ connect(m_ledgerView, SIGNAL(startEdit()), kmymoney2, SLOT(slotTransactionsEdit()));
+ connect(m_ledgerView, SIGNAL(endEdit()), kmymoney2, SLOT(slotTransactionsEnter()));
+ connect(m_ledgerView, SIGNAL(toggleReconciliationFlag()), kmymoney2, SLOT(slotToggleReconciliationFlag()));
+ connect(this, SIGNAL(reconciliationStarts(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&)), m_ledgerView, SLOT(slotSetReconcileAccount(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&)));
+ connect(kmymoney2, SIGNAL(selectAllTransactions()), m_ledgerView, SLOT(slotSelectAllTransactions()));
+
+ // Page 7
+ m_investmentViewFrame = addVBoxPage( i18n("Investments"), i18n("Investments"),
+ DesktopIcon("investments", iconSize));
+ addTitleBar(m_investmentViewFrame, i18n("Investments"));
+ m_investmentView = new KInvestmentView(m_investmentViewFrame, "InvestmentView");
+ connect(m_investmentView, SIGNAL(accountSelected(const QString&, const QString&)),
+ this, SLOT(slotLedgerSelected(const QString&, const QString&)));
+ connect(m_investmentView, SIGNAL(accountSelected(const MyMoneyObject&)), kmymoney2, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ connect(m_investmentView, SIGNAL(investmentRightMouseClick()), kmymoney2, SLOT(slotShowInvestmentContextMenu()));
+
+ // Page 8
+ m_reportsViewFrame = addVBoxPage(i18n("Reports"), i18n("Reports"),
+ DesktopIcon("report", iconSize));
+ m_reportsView = new KReportsView(m_reportsViewFrame, "ReportsView");
+
+ // Page 9
+ m_budgetViewFrame = addVBoxPage(i18n("Budgets"), i18n("Budgets"),
+ DesktopIcon("budget", iconSize));
+ addTitleBar(m_budgetViewFrame, i18n("Budgets"));
+ m_budgetView = new KBudgetView(m_budgetViewFrame, "BudgetView");
+ connect(kmymoney2, SIGNAL(fileLoaded(const KURL&)), m_budgetView, SLOT(slotRefreshView()));
+ connect(m_budgetView, SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, SLOT(slotShowBudgetContextMenu()));
+ connect(m_budgetView, SIGNAL(selectObjects(const QValueList<MyMoneyBudget>&)), kmymoney2, SLOT(slotSelectBudget(const QValueList<MyMoneyBudget>&)));
+ connect(kmymoney2, SIGNAL(budgetRename()), m_budgetView, SLOT(slotStartRename()));
+
+ // Page 10
+ m_forecastViewFrame = addVBoxPage( i18n("Forecast"), i18n("Forecast"),
+ DesktopIcon("forcast", iconSize));
+ addTitleBar(m_forecastViewFrame, i18n("Forecast"));
+ m_forecastView = new KForecastView(m_forecastViewFrame, "ForecastView");
+
+ // get rid of the title text
+ QWidget* widget = dynamic_cast<QWidget*>(child("KJanusWidgetTitleLabel", "QLabel"));
+ if(widget)
+ widget->hide();
+
+ // and the separator below it
+ widget = dynamic_cast<QWidget*>(child(0, "KSeparator"));
+ if(widget)
+ widget->hide();
+
+ // select the page first, before connecting the aboutToShow signal
+ // because we don't want to override the information stored in the config file
+ showPage(0);
+ connect(this, SIGNAL(aboutToShowPage(QWidget*)), this, SLOT(slotRememberPage(QWidget*)));
+
+ m_inConstructor = false;
+}
+
+KMyMoneyView::~KMyMoneyView()
+{
+ removeStorage();
+}
+
+void KMyMoneyView::addTitleBar(QWidget* parent, const QString& title)
+{
+ KMyMoneyTitleLabel* label = new KMyMoneyTitleLabel( parent, "titleLabel" );
+ label->setMinimumSize( QSize( 100, 30 ) );
+ label->setRightImageFile("pics/titlelabel_background.png" );
+ label->setText(title);
+}
+
+void KMyMoneyView::showTitleBar(bool show)
+{
+ QObjectList *l = queryList( 0, "titleLabel" );
+ QObjectListIterator it( *l ); // iterate over the labels
+ QObject *obj;
+
+ while ( (obj = it.current()) != 0 ) {
+ // for each found object...
+ ++it;
+ ((QWidget*)obj)->setShown( show );
+ }
+ delete l; // delete the list, not the objects
+}
+
+bool KMyMoneyView::showPage(int index)
+{
+ // reset all selected items before showing the selected view
+ // but not while we're in our own constructor
+ if(!m_inConstructor && index != activePageIndex()) {
+ kmymoney2->slotResetSelections();
+ }
+
+ // pretend we're in the constructor to avoid calling the
+ // above resets. For some reason which I don't know the details
+ // of, KJanusWidget::showPage() calls itself recursively. This
+ // screws up the action handling, as items could have been selected
+ // in the meantime. We prevent this by setting the m_inConstructor
+ // to true and reset it to the previos value when we leave this method.
+ bool prevConstructor = m_inConstructor;
+ m_inConstructor = true;
+
+ bool rc = KJanusWidget::showPage(index);
+
+ m_inConstructor = prevConstructor;
+
+ if(!m_inConstructor) {
+ // fixup some actions that are dependant on the view
+ // this does not work during construction
+ kmymoney2->slotUpdateActions();
+ }
+
+ return rc;
+}
+
+bool KMyMoneyView::canPrint(void)
+{
+ bool rc = (
+ activePageIndex() == pageIndex(m_reportsViewFrame) ||
+ activePageIndex() == pageIndex(m_homeViewFrame)
+ );
+ return rc;
+}
+
+bool KMyMoneyView::canCreateTransactions(const KMyMoneyRegister::SelectedTransactions& /* list */, QString& tooltip) const
+{
+ // we can only create transactions in the ledger view so
+ // we check that this is the active page
+
+ bool rc = (activePageIndex() == pageIndex(m_ledgerViewFrame));
+ if(rc)
+ rc = m_ledgerView->canCreateTransactions(tooltip);
+ else
+ tooltip = i18n("Creating transactions can only be performed in the ledger view");
+ return rc;
+}
+
+bool KMyMoneyView::canModifyTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ // we can only modify transactions in the ledger view so
+ // we check that this is the active page
+
+ bool rc = (activePageIndex() == pageIndex(m_ledgerViewFrame));
+
+ if(rc) {
+ rc = m_ledgerView->canModifyTransactions(list, tooltip);
+ } else {
+ tooltip = i18n("Modifying transactions can only be performed in the ledger view");
+ }
+ return rc;
+}
+
+bool KMyMoneyView::canDuplicateTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ // we can only duplicate transactions in the ledger view so
+ // we check that this is the active page
+
+ bool rc = (activePageIndex() == pageIndex(m_ledgerViewFrame));
+
+ if(rc) {
+ rc = m_ledgerView->canDuplicateTransactions(list, tooltip);
+ } else {
+ tooltip = i18n("Duplicating transactions can only be performed in the ledger view");
+ }
+ return rc;
+}
+
+bool KMyMoneyView::canEditTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const
+{
+ bool rc;
+ // we can only edit transactions in the ledger view so
+ // we check that this is the active page
+
+ if((rc = canModifyTransactions(list, tooltip)) == true) {
+ tooltip = i18n("Edit the current selected transactions");
+ rc = m_ledgerView->canEditTransactions(list, tooltip);
+ }
+ return rc;
+}
+
+bool KMyMoneyView::createNewTransaction(void)
+{
+ bool rc = false;
+ KMyMoneyRegister::SelectedTransactions list;
+ QString txt;
+ if(canCreateTransactions(list, txt)) {
+ rc = m_ledgerView->selectEmptyTransaction();
+ }
+ return rc;
+}
+
+TransactionEditor* KMyMoneyView::startEdit(const KMyMoneyRegister::SelectedTransactions& list)
+{
+ TransactionEditor* editor = 0;
+ QString txt;
+ if(canEditTransactions(list, txt) || canCreateTransactions(list, txt)) {
+ editor = m_ledgerView->startEdit(list);
+ }
+ return editor;
+}
+
+void KMyMoneyView::newStorage(storageTypeE t)
+{
+ removeStorage();
+ MyMoneyFile* file = MyMoneyFile::instance();
+ if (t == Memory) file->attachStorage(new MyMoneySeqAccessMgr);
+ else file->attachStorage(new MyMoneyDatabaseMgr);
+}
+
+void KMyMoneyView::removeStorage(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ IMyMoneyStorage* p = file->storage();
+ if(p != 0) {
+ file->detachStorage(p);
+ delete p;
+ }
+}
+
+void KMyMoneyView::enableViews(int state)
+{
+ if(state == -1)
+ state = m_fileOpen;
+
+ m_accountsViewFrame->setEnabled(state);
+ m_institutionsViewFrame->setEnabled(state);
+ m_scheduleViewFrame->setEnabled(state);
+ m_categoriesViewFrame->setEnabled(state);
+ m_payeesViewFrame->setEnabled(state);
+ m_budgetViewFrame->setEnabled(state);
+ m_ledgerViewFrame->setEnabled(state);
+ m_investmentViewFrame->setEnabled(state);
+ m_reportsViewFrame->setEnabled(state);
+ m_forecastViewFrame->setEnabled(state);
+
+ emit viewStateChanged(state != 0);
+}
+
+void KMyMoneyView::slotLedgerSelected(const QString& _accId, const QString& transaction)
+{
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(_accId);
+ QString accId(_accId);
+
+ switch(acc.accountType()) {
+ case MyMoneyAccount::Stock:
+ // if a stock account is selected, we show the
+ // the corresponding parent (investment) account
+ acc = MyMoneyFile::instance()->account(acc.parentAccountId());
+ accId = acc.id();
+ // tricky fall through here
+
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::CreditCard:
+ case MyMoneyAccount::Loan:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::Investment:
+ case MyMoneyAccount::Equity:
+ showPage(pageIndex(m_ledgerViewFrame));
+ m_ledgerView->slotSelectAccount(accId, transaction);
+ break;
+
+ case MyMoneyAccount::CertificateDep:
+ case MyMoneyAccount::MoneyMarket:
+ case MyMoneyAccount::Currency:
+ qDebug("No ledger view available for account type %d", acc.accountType());
+ break;
+
+ default:
+ qDebug("Unknown account type %d in KMyMoneyView::slotLedgerSelected", acc.accountType());
+ break;
+ }
+}
+
+void KMyMoneyView::slotPayeeSelected(const QString& payee, const QString& account, const QString& transaction)
+{
+ showPage(pageIndex(m_payeesViewFrame));
+ m_payeesView->slotSelectPayeeAndTransaction(payee, account, transaction);
+}
+
+void KMyMoneyView::slotScheduleSelected(const QString& scheduleId)
+{
+ MyMoneySchedule sched = MyMoneyFile::instance()->schedule(scheduleId);
+ kmymoney2->slotSelectSchedule(sched);
+}
+
+void KMyMoneyView::slotShowReport(const QString& reportid)
+{
+ showPage(pageIndex(m_reportsViewFrame));
+ m_reportsView->slotOpenReport(reportid);
+}
+
+void KMyMoneyView::slotShowReport(const MyMoneyReport& report)
+{
+ showPage(pageIndex(m_reportsViewFrame));
+ m_reportsView->slotOpenReport(report);
+}
+
+bool KMyMoneyView::fileOpen(void)
+{
+ return m_fileOpen;
+}
+
+void KMyMoneyView::closeFile(void)
+{
+ if ( m_reportsView )
+ m_reportsView->slotCloseAll();
+
+ emit kmmFilePlugin (preClose);
+ if (isDatabase())
+ MyMoneyFile::instance()->storage()->close(); // to log off a database user
+ newStorage();
+ slotShowHomePage();
+
+ emit kmmFilePlugin (postClose);
+ m_fileOpen = false;
+}
+
+void KMyMoneyView::ungetString(QIODevice *qfile, char *buf, int len)
+{
+ buf = &buf[len-1];
+ while(len--) {
+ qfile->ungetch(*buf--);
+ }
+}
+
+bool KMyMoneyView::readFile(const KURL& url)
+{
+ QString filename;
+
+// newStorage();
+ m_fileOpen = false;
+ bool isEncrypted = false;
+
+ IMyMoneyStorageFormat* pReader = NULL;
+
+#if KDE_IS_VERSION(3,2,0)
+ if(!url.isValid()) {
+#else
+ if(url.isMalformed()) {
+#endif
+ qDebug("Invalid URL '%s'", url.url().latin1());
+ return false;
+ }
+
+ if (url.protocol() == "sql") { // handle reading of database
+ //newStorage(Database);
+ MyMoneyFile::instance()->detachStorage();
+ m_fileType = KmmDb;
+ // get rid of the mode parameter which is now redundant
+ KURL newUrl(url);
+ if (!url.queryItem("mode").isNull()) {
+ newUrl.removeQueryItem("mode");
+ }
+ return (openDatabase(newUrl)); // on error, any message will have been displayed
+ }
+
+ newStorage();
+
+ if(url.isLocalFile()) {
+ filename = url.path();
+
+ } else {
+ if(!KIO::NetAccess::download(url, filename, NULL)) {
+ KMessageBox::detailedError(this,
+ i18n("Error while loading file '%1'!").arg(url.url()),
+ KIO::NetAccess::lastErrorString(),
+ i18n("File access error"));
+ return false;
+ }
+ }
+
+ // let's glimps into the file to figure out, if it's one
+ // of the old (uncompressed) or new (compressed) files.
+ QFile file(filename);
+ QFileInfo info(file);
+ if(!info.isFile()) {
+ QString msg=i18n("<b>%1</b> is not a KMyMoney file.").arg(filename);
+ KMessageBox::error(this, QString("<p>")+msg, i18n("Filetype Error"));
+ return false;
+ }
+ m_fmode = 0600;
+ m_fmode |= info.permission(QFileInfo::ReadGroup) ? 040 : 0;
+ m_fmode |= info.permission(QFileInfo::WriteGroup) ? 020 : 0;
+ m_fmode |= info.permission(QFileInfo::ReadOther) ? 004 : 0;
+ m_fmode |= info.permission(QFileInfo::WriteOther) ? 002 : 0;
+
+ QIODevice *qfile = 0;
+ bool rc = true;
+
+ // There's a problem with the KFilterDev and KGPGFile classes:
+ // One supports the at(n) member but not ungetch() together with
+ // readBlock() and the other does not provide an at(n) method but
+ // supports readBlock() that considers the ungetch() buffer. QFile
+ // supports everything so this is not a problem. We solve the problem
+ // for now by keeping track of which method can be used.
+ bool haveAt = true;
+
+ emit kmmFilePlugin (preOpen);
+ ::timetrace("start reading file");
+ if(file.open(IO_ReadOnly)) {
+ QByteArray hdr(2);
+ int cnt;
+ cnt = file.readBlock(hdr.data(), 2);
+ file.close();
+
+ if(cnt == 2) {
+ if(QString(hdr) == QString("\037\213")) { // gzipped?
+ ::timetrace("detected GZIP");
+ qfile = KFilterDev::deviceForFile(filename, COMPRESSION_MIME_TYPE);
+ } else if(QString(hdr) == QString("--")){ // PGP ASCII armored?
+ ::timetrace("detected GPG");
+ if(KGPGFile::GPGAvailable()) {
+ ::timetrace("have GPG");
+ qfile = new KGPGFile(filename);
+ haveAt = false;
+ isEncrypted = true;
+ } else {
+ KMessageBox::sorry(this, QString("<qt>%1</qt>"). arg(i18n("GPG is not available for decryption of file <b>%1</b>").arg(filename)));
+ qfile = new QFile(file.name());
+ }
+ } else {
+ // we can't use file directly, as we delete qfile later on
+ qfile = new QFile(file.name());
+ }
+
+ ::timetrace("open file");
+ if(qfile->open(IO_ReadOnly)) {
+ try {
+ hdr.resize(8);
+ if(qfile->readBlock(hdr.data(), 8) == 8) {
+ if(haveAt)
+ qfile->at(0);
+ else
+ ungetString(qfile, hdr.data(), 8);
+
+ // Ok, we got the first block of 8 bytes. Read in the two
+ // unsigned long int's by preserving endianess. This is
+ // achieved by reading them through a QDataStream object
+ Q_INT32 magic0, magic1;
+ QDataStream s(hdr, IO_ReadOnly);
+ s >> magic0;
+ s >> magic1;
+
+ // If both magic numbers match (we actually read in the
+ // text 'KMyMoney' then we assume a binary file and
+ // construct a reader for it. Otherwise, we construct
+ // an XML reader object.
+ //
+ // The expression magic0 < 30 is only used to create
+ // a binary reader if we assume an old binary file. This
+ // should be removed at some point. An alternative is to
+ // check the beginning of the file against an pattern
+ // of the XML file (e.g. '?<xml' ).
+ if((magic0 == MAGIC_0_50 && magic1 == MAGIC_0_51)
+ || magic0 < 30) {
+ // we do not support this file format anymore
+ pReader = 0;
+ m_fileType = KmmBinary;
+ } else {
+ ::timetrace("is not binary format");
+ // Scan the first 70 bytes to see if we find something
+ // we know. For now, we support our own XML format and
+ // GNUCash XML format. If the file is smaller, then it
+ // contains no valid data and we reject it anyway.
+ hdr.resize(70);
+ if(qfile->readBlock(hdr.data(), 70) == 70) {
+ if(haveAt)
+ qfile->at(0);
+ else
+ ungetString(qfile, hdr.data(), 70);
+ QRegExp kmyexp("<!DOCTYPE KMYMONEY-FILE>");
+ QRegExp gncexp("<gnc-v(\\d+)");
+ QCString txt(hdr, 70);
+ if(kmyexp.search(txt) != -1) {
+ ::timetrace("is XML format");
+ pReader = new MyMoneyStorageXML;
+ m_fileType = KmmXML;
+ } else if(gncexp.search(txt) != -1) {
+ ::timetrace("is GNC format");
+ MyMoneyFileTransaction ft;
+ loadDefaultCurrencies(); // currency list required for gnc
+ loadAncientCurrencies(); // these too
+ ft.commit();
+ pReader = new MyMoneyGncReader;
+ m_fileType = GncXML;
+ }
+ }
+ }
+ if(pReader) {
+ pReader->setProgressCallback(&KMyMoneyView::progressCallback);
+ ::timetrace("read data to memory");
+ pReader->readFile(qfile, dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()));
+ ::timetrace("done reading to memory");
+ } else {
+ if(m_fileType == KmmBinary) {
+ KMessageBox::sorry(this, QString("<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.").arg(filename)));
+ } else {
+ KMessageBox::sorry(this, QString("<qt>%1</qt>"). arg(i18n("File <b>%1</b> contains an unknown file format!").arg(filename)));
+ }
+ rc = false;
+ }
+ } else {
+ KMessageBox::sorry(this, QString("<qt>%1</qt>"). arg(i18n("Cannot read from file <b>%1</b>!").arg(filename)));
+ rc = false;
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::sorry(this, QString("<qt>%1</qt>"). arg(i18n("Cannot load file <b>%1</b>. Reason: %2").arg(filename, e->what())));
+ delete e;
+ rc = false;
+ }
+ if(pReader) {
+ pReader->setProgressCallback(0);
+ delete pReader;
+ }
+ qfile->close();
+ } else {
+ KMessageBox::sorry(this, QString("<qt>%1</qt>"). arg(i18n("File <b>%1</b> not found!").arg(filename)));
+ rc = false;
+ }
+ delete qfile;
+ }
+ } else {
+ KMessageBox::sorry(this, QString("<qt>%1</qt>"). arg(i18n("File <b>%1</b> not found!").arg(filename)));
+ rc = false;
+ }
+
+ ::timetrace("done reading file");
+ if(rc == false)
+ return rc;
+
+ // make sure we setup the encryption key correctly
+ MyMoneyFileTransaction ft;
+ if(isEncrypted && MyMoneyFile::instance()->value("kmm-encryption-key").isEmpty()) {
+ MyMoneyFile::instance()->setValue("kmm-encryption-key", KMyMoneyGlobalSettings::gpgRecipientList().join(","));
+ }
+
+ // make sure we setup the name of the base accounts in translated form
+ try {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ checkAccountName(file->asset(), i18n("Asset"));
+ checkAccountName(file->liability(), i18n("Liability"));
+ checkAccountName(file->income(), i18n("Income"));
+ checkAccountName(file->expense(), i18n("Expense"));
+ checkAccountName(file->equity(), i18n("Equity"));
+ ft.commit();
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+
+ // if a temporary file was constructed by NetAccess::download,
+ // then it will be removed with the next call. Otherwise, it
+ // stays untouched on the local filesystem
+ KIO::NetAccess::removeTempFile(filename);
+ return initializeStorage();
+}
+
+void KMyMoneyView::checkAccountName(const MyMoneyAccount& _acc, const QString& name) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ if(_acc.name() != name) {
+ MyMoneyAccount acc(_acc);
+ acc.setName(name);
+ file->modifyAccount(acc);
+ }
+}
+
+bool KMyMoneyView::openDatabase (const KURL& url) {
+ ::timetrace("start opening database");
+ m_fileOpen = false;
+
+ // open the database
+ IMyMoneySerialize* pStorage = dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage());
+ MyMoneyDatabaseMgr* pDBMgr = 0;
+ if (! pStorage) {
+ pDBMgr = new MyMoneyDatabaseMgr;
+ pStorage = dynamic_cast<IMyMoneySerialize*> (pDBMgr);
+ }
+ KSharedPtr <MyMoneyStorageSql> reader = pStorage->connectToDatabase (url);
+ KURL dbURL (url);
+ bool retry = true;
+ while (retry) {
+ switch (reader->open(dbURL, IO_ReadWrite)) {
+ case 0: // opened okay
+ retry = false;
+ break;
+ case 1: // permanent error
+ KMessageBox::detailedError (this, i18n("Can't open database %1\n").arg(dbURL.prettyURL()), reader->lastError());
+ if (pDBMgr) {
+ removeStorage();
+ delete pDBMgr;
+ }
+ return false;
+ case -1: // retryable error
+ if (KMessageBox::warningYesNo (this, reader->lastError(), PACKAGE) == KMessageBox::No) {
+ if (pDBMgr) {
+ removeStorage();
+ delete pDBMgr;
+ }
+ return false;
+ } else {
+ QString options = dbURL.queryItem("options") + ",override";
+ dbURL.removeQueryItem("mode"); // now redundant
+ dbURL.removeQueryItem("options");
+ dbURL.addQueryItem("options", options);
+ }
+ }
+ }
+ if (pDBMgr) {
+ removeStorage();
+ MyMoneyFile::instance()->attachStorage(pDBMgr);
+ }
+ // single user mode; read some of the data into memory
+ // FIXME - readFile no longer relevant?
+ // tried removing it but then then got no indication that loading was complete
+ // also, didn't show home page
+ reader->setProgressCallback(&KMyMoneyView::progressCallback);
+ if (!reader->readFile()) {
+ KMessageBox::detailedError (0,
+ i18n("An unrecoverable error occurred while reading the database"),
+ reader->lastError().latin1(),
+ i18n("Database malfunction"));
+ return false;
+ }
+ m_fileOpen = true;
+ reader->setProgressCallback(0);
+ ::timetrace("done opening database");
+ return initializeStorage();
+}
+
+bool KMyMoneyView::initializeStorage()
+{
+ bool blocked = MyMoneyFile::instance()->signalsBlocked();
+ MyMoneyFile::instance()->blockSignals(true);
+
+ // we check, if we have any currency in the file. If not, we load
+ // all the default currencies we know.
+ MyMoneyFileTransaction ft;
+ try {
+ loadDefaultCurrencies();
+ loadAncientCurrencies();
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ MyMoneyFile::instance()->blockSignals(blocked);
+ return false;
+ }
+
+ // make sure, we have a base currency and all accounts are
+ // also assigned to a currency.
+ if(MyMoneyFile::instance()->baseCurrency().id().isEmpty()) {
+ // Stay in this endless loop until we have a base currency,
+ // as without it the application does not work anymore.
+ while(MyMoneyFile::instance()->baseCurrency().id().isEmpty())
+ selectBaseCurrency();
+
+ } else {
+ // in some odd intermediate cases there could be files out there
+ // that have a base currency set, but still have accounts that
+ // do not have a base currency assigned. This call will take
+ // care of it. We can safely remove it later.
+ //
+ // Another work-around for this scenario is to remove the base
+ // currency setting from the XML file by removing the line
+ //
+ // <PAIR key="kmm-baseCurrency" value="xxx" />
+ //
+ // and restart the application with this file. This will force to
+ // run the above loop.
+ selectBaseCurrency();
+ }
+
+ KConfig *config = KGlobal::config();
+ int page;
+ config->setGroup("General Options");
+ if(KMyMoneyGlobalSettings::startLastViewSelected() != 0) {
+ config->setGroup("Last Use Settings");
+ page = config->readNumEntry("LastViewSelected", 0);
+ } else {
+ page = pageIndex(m_homeViewFrame);
+ }
+
+ ::timetrace("start fixing file");
+
+ // For debugging purposes, we can turn off the automatic fix manually
+ // by setting the entry in kmymoney2rc to true
+ config->setGroup("General Options");
+ if(config->readBoolEntry("SkipFix", false) != true) {
+ MyMoneyFileTransaction ft;
+ try {
+ // Check if we have to modify the file before we allow to work with it
+ IMyMoneyStorage* s = MyMoneyFile::instance()->storage();
+ while (s->fileFixVersion() < s->currentFixVersion()) {
+ qDebug("%s", (QString("testing fileFixVersion %1 < %2").arg(s->fileFixVersion()).arg(s->currentFixVersion())).data());
+ switch (s->fileFixVersion()) {
+ case 0:
+ fixFile_0();
+ s->setFileFixVersion(1);
+ break;
+
+ case 1:
+ fixFile_1();
+ s->setFileFixVersion(2);
+ break;
+
+ case 2:
+ fixFile_2();
+ s->setFileFixVersion(3);
+ break;
+
+ // add new levels above. Don't forget to increase currentFixVersion() for all
+ // the storage backends this fix applies to
+ default:
+ throw new MYMONEYEXCEPTION(i18n("Unknown fix level in input file"));
+ }
+ }
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ MyMoneyFile::instance()->blockSignals(blocked);
+ return false;
+ }
+ } else {
+ qDebug("Skipping automatic transaction fix!");
+ }
+ MyMoneyFile::instance()->blockSignals(blocked);
+
+ // FIXME: we need to check, if it's necessary to have this
+ // automatic funcitonality
+ // if there's no asset account, then automatically start the
+ // new account wizard
+ // kmymoney2->createInitialAccount();
+
+ ::timetrace("file open");
+ m_fileOpen = true;
+ emit kmmFilePlugin (postOpen);
+
+ // inform everyone about new data
+ MyMoneyFile::instance()->preloadCache();
+ MyMoneyFile::instance()->forceDataChanged();
+
+ // if we currently see a different page, then select the right one
+ if(page != activePageIndex()) {
+ showPage(page);
+ }
+
+ return true;
+}
+
+void KMyMoneyView::saveToLocalFile(QFile* qfile, IMyMoneyStorageFormat* pWriter, bool plaintext, const QString& keyList)
+{
+ QIODevice *dev = qfile;
+ KFilterBase *base = 0;
+ QIODevice *statusDevice = dev;
+
+ bool encryptedOk = true;
+ bool encryptRecover = false;
+ if(!keyList.isEmpty()) {
+ if(!KGPGFile::GPGAvailable()) {
+ KMessageBox::sorry(this, 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"));
+ encryptedOk = false;
+ }
+
+ if(KMyMoneyGlobalSettings::encryptRecover()) {
+ encryptRecover = true;
+ if(!KGPGFile::keyAvailable(QString(RECOVER_KEY_ID))) {
+ KMessageBox::sorry(this, QString("<p>")+i18n("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>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=\"http://kmymoney2.sourceforge.net/\">KMyMoney web-site</a>. This time your data will not be encrypted with the KMyMoney recover key.").arg(RECOVER_KEY_ID), i18n("GPG-Key not found"));
+ encryptRecover = false;
+ }
+ }
+
+ QStringList keys = QStringList::split(",", keyList);
+ QStringList::const_iterator it_s;
+ for(it_s = keys.begin(); it_s != keys.begin(); ++it_s) {
+ if(!KGPGFile::keyAvailable(*it_s)) {
+ KMessageBox::sorry(this, QString("<p>")+i18n("You have specified to encrypt your data for the user-id</p><p><center><b>%1</b>.</center></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.").arg(*it_s), i18n("GPG-Key not found"));
+ encryptedOk = false;
+ }
+ }
+
+ if(encryptedOk == true) {
+ QString msg = QString("<p>") + i18n("You have configured to save your data in encrypted form using GPG. Please be aware, that this is a brand new feature which is yet untested. Make sure, you have the necessary understanding that you might loose all your data if you store it encrypted and cannot decrypt it later on! If unsure, answer <b>No</b>.");
+
+ if(KMessageBox::questionYesNo(this, msg, i18n("Store GPG encrypted"), KStdGuiItem::yes(), KStdGuiItem::no(), "StoreEncrypted") == KMessageBox::No) {
+ encryptedOk = false;
+ }
+ }
+ }
+
+ int mask = umask((~m_fmode) & 0777);
+ bool blocked = MyMoneyFile::instance()->signalsBlocked();
+ MyMoneyFile::instance()->blockSignals(true);
+ MyMoneyFileTransaction ft;
+ MyMoneyFile::instance()->deletePair("kmm-encryption-key");
+ if(!keyList.isEmpty() && encryptedOk == true && !plaintext ) {
+ qfile->close();
+ base++;
+ KGPGFile *kgpg = new KGPGFile(qfile->name());
+ if(kgpg) {
+ QStringList keys = QStringList::split(",", keyList);
+ QStringList::const_iterator it_s;
+ for(it_s = keys.begin(); it_s != keys.end(); ++it_s) {
+ kgpg->addRecipient((*it_s).latin1());
+ }
+ if(encryptRecover) {
+ kgpg->addRecipient(RECOVER_KEY_ID);
+ }
+ MyMoneyFile::instance()->setValue("kmm-encryption-key", keyList);
+ }
+ statusDevice = dev = kgpg;
+ if(!dev || !dev->open(IO_WriteOnly)) {
+ MyMoneyFile::instance()->blockSignals(blocked);
+ delete dev;
+ throw new MYMONEYEXCEPTION(i18n("Unable to open file '%1' for writing.").arg(qfile->name()));
+ }
+
+ } else if(!plaintext) {
+
+ base = KFilterBase::findFilterByMimeType( COMPRESSION_MIME_TYPE );
+ if(base) {
+ qfile->close();
+ base->setDevice(qfile, false);
+ // we need to reopen the file to set the mode inside the filter stuff
+ dev = new KFilterDev(base, true);
+ if(!dev || !dev->open(IO_WriteOnly)) {
+ MyMoneyFile::instance()->blockSignals(blocked);
+ delete dev;
+ throw new MYMONEYEXCEPTION(i18n("Unable to open file '%1' for writing.").arg(qfile->name()));
+ }
+ statusDevice = base->device();
+ }
+ }
+ umask(mask);
+ ft.commit();
+
+ pWriter->setProgressCallback(&KMyMoneyView::progressCallback);
+ dev->resetStatus();
+ pWriter->writeFile(dev, dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()));
+ MyMoneyFile::instance()->blockSignals(blocked);
+ if(statusDevice->status() != IO_Ok) {
+ throw new MYMONEYEXCEPTION(i18n("Failure while writing to '%1'").arg(qfile->name()));
+ }
+ pWriter->setProgressCallback(0);
+
+ if(base != 0) {
+ dev->flush();
+ dev->close();
+ if(statusDevice->status() != IO_Ok) {
+ delete dev;
+ throw new MYMONEYEXCEPTION(i18n("Failure while writing to '%1'").arg(qfile->name()));
+ }
+ delete dev;
+ } else
+ qfile->close();
+}
+
+bool KMyMoneyView::saveFile(const KURL& url, const QString& keyList)
+{
+ QString filename = url.path();
+
+ if (!fileOpen()) {
+ KMessageBox::error(this, i18n("Tried to access a file when it's not open"));
+ return false;
+ }
+
+#if 0
+ if(KMessageBox::warningContinueCancel(this, i18n(
+ "Since this version of KMyMoney only writes data files in its new "
+ "format, files written with this version cannot be read by KMyMoney version 0.4. "
+ "If you still want to use older versions of KMyMoney with your data files, "
+ "please make sure you keep a backup-file of your finance data. "
+ "If you want to abort this operation, please press Cancel now"),
+ QString::null, KStdGuiItem::cont(), "WarningNewFileVersion0.5") == KMessageBox::Cancel)
+ return false;
+#endif
+
+ emit kmmFilePlugin (preSave);
+ IMyMoneyStorageFormat* pWriter = NULL;
+
+ // If this file ends in ".ANON.XML" then this should be written using the
+ // anonymous writer.
+ bool plaintext = filename.right(4).lower() == ".xml";
+ if (filename.right(9).lower() == ".anon.xml")
+ {
+ pWriter = new MyMoneyStorageANON;
+ }
+ else
+ {
+ // only use XML writer. The binary format will be depreacated after 0.8
+ pWriter = new MyMoneyStorageXML;
+ }
+
+ // actually, url should be the parameter to this function
+ // but for now, this would involve too many changes
+ bool rc = true;
+ try {
+ if(! url.isValid()) {
+ throw new MYMONEYEXCEPTION(i18n("Malformed URL '%1'").arg(url.url()));
+ }
+
+ if(url.isLocalFile()) {
+ filename = url.path();
+ int fmode = 0600;
+ gid_t gid = static_cast<gid_t>(-1); // don't change the group id (see "man 2 chown")
+ QFileInfo fi(filename);
+ if(fi.exists()) {
+ fmode |= fi.permission(QFileInfo::ReadGroup) ? 040 : 0;
+ fmode |= fi.permission(QFileInfo::WriteGroup) ? 020 : 0;
+ fmode |= fi.permission(QFileInfo::ReadOther) ? 004 : 0;
+ fmode |= fi.permission(QFileInfo::WriteOther) ? 002 : 0;
+ if(fi.groupId() != static_cast<uint>(-2))
+ gid = fi.groupId();
+ }
+
+ // create a new basic block here, so that the object qfile gets
+ // deleted, before we reach the chown() call
+ {
+ int mask = umask((~fmode) & 0777);
+ KSaveFile qfile(filename, fmode);
+ umask(mask);
+ if(qfile.status() == 0) {
+ try {
+ saveToLocalFile(qfile.file(), pWriter, plaintext, keyList);
+ } catch (MyMoneyException* e) {
+ qfile.abort();
+ delete e;
+ throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").arg(filename));
+ }
+ } else {
+ throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").arg(filename));
+ }
+ }
+ chown(filename, static_cast<uid_t>(-1), gid);
+ } else {
+ KTempFile tmpfile;
+ saveToLocalFile(tmpfile.file(), pWriter, plaintext, keyList);
+ if(!KIO::NetAccess::upload(tmpfile.name(), url, NULL))
+ throw new MYMONEYEXCEPTION(i18n("Unable to upload to '%1'").arg(url.url()));
+ tmpfile.unlink();
+ }
+ m_fileType = KmmXML;
+ } catch (MyMoneyException *e) {
+ KMessageBox::error(this, e->what());
+ delete e;
+ MyMoneyFile::instance()->setDirty();
+ rc = false;
+ }
+ delete pWriter;
+ emit kmmFilePlugin (postSave);
+ return rc;
+}
+
+bool KMyMoneyView::saveAsDatabase(const KURL& url)
+{
+ bool rc = false;
+ if (!fileOpen()) {
+ KMessageBox::error(this, i18n("Tried to access a file when it's not open"));
+ return (rc);
+ }
+ MyMoneyStorageSql *writer = new MyMoneyStorageSql(dynamic_cast<IMyMoneySerialize*> (MyMoneyFile::instance()->storage()), url);
+ bool canWrite = false;
+ switch (writer->open(url, IO_WriteOnly)) {
+ case 0:
+ canWrite = true;
+ break;
+ case -1: // dbase already has data, see if he wants to clear it out
+ if (KMessageBox::warningContinueCancel (0,
+ i18n("Database contains data which must be removed before using SaveAs.\n"
+ "Do you wish to continue?"), "Database not empty") == KMessageBox::Continue) {
+ if (writer->open(url, IO_WriteOnly, true) == 0) canWrite = true;
+ } else {
+ delete writer;
+ return false;
+ }
+ break;
+ }
+ if (canWrite) {
+ writer->setProgressCallback(&KMyMoneyView::progressCallback);
+ if (!writer->writeFile()) {
+ KMessageBox::detailedError (0,
+ i18n("An unrecoverable error occurred while writing to the database.\n"
+ "It may well be corrupt."),
+ writer->lastError().latin1(),
+ i18n("Database malfunction"));
+ rc = false;
+ }
+ writer->setProgressCallback(0);
+ rc = true;
+ } else {
+ KMessageBox::detailedError (this,
+ i18n("Can't open or create database %1\n"
+ "Retry SaveAsDatabase and click Help"
+ " for further info").arg(url.prettyURL()), writer->lastError());
+ }
+ delete writer;
+ return (rc);
+}
+
+bool KMyMoneyView::dirty(void)
+{
+ if (!fileOpen())
+ return false;
+
+ return MyMoneyFile::instance()->dirty();
+}
+
+bool KMyMoneyView::startReconciliation(const MyMoneyAccount& account, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance)
+{
+ bool ok = true;
+
+ // we cannot reconcile standard accounts
+ if(MyMoneyFile::instance()->isStandardAccount(account.id()))
+ ok = false;
+
+ // check if we can reconcile this account
+ // it makes sense for asset and liability accounts only
+ if(ok == true) {
+ if(account.isAssetLiability()) {
+ showPage(pageIndex(m_ledgerViewFrame));
+ // prepare reconciliation mode
+ emit reconciliationStarts(account, reconciliationDate, endingBalance);
+ } else {
+ ok = false;
+ }
+ }
+
+ return ok;
+}
+
+void KMyMoneyView::finishReconciliation(const MyMoneyAccount& /* account */)
+{
+ emit reconciliationStarts(MyMoneyAccount(), QDate(), MyMoneyMoney());
+}
+
+void KMyMoneyView::newFile(void)
+{
+ closeFile();
+ m_fileType = KmmXML; // assume native type until saved
+ m_fileOpen = true;
+}
+
+void KMyMoneyView::slotSetBaseCurrency(const MyMoneySecurity& baseCurrency)
+{
+ if(!baseCurrency.id().isEmpty()) {
+ if(baseCurrency.id() != MyMoneyFile::instance()->baseCurrency().id()) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->setBaseCurrency(baseCurrency);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ KMessageBox::sorry(this, i18n("Cannot set %1 as base currency: %2").arg(baseCurrency.name()).arg(e->what()), i18n("Set base currency"));
+ delete e;
+ }
+ }
+ }
+}
+
+void KMyMoneyView::selectBaseCurrency(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // check if we have a base currency. If not, we need to select one
+ if(file->baseCurrency().id().isEmpty()) {
+ KCurrencyEditDlg dlg(this, "CurrencyEditDlg");
+ connect(&dlg, SIGNAL(selectBaseCurrency(const MyMoneySecurity&)), this, SLOT(slotSetBaseCurrency(const MyMoneySecurity&)));
+ dlg.exec();
+ }
+
+ if(!file->baseCurrency().id().isEmpty()) {
+ // check that all accounts have a currency
+ QValueList<MyMoneyAccount> list;
+ file->accountList(list);
+ QValueList<MyMoneyAccount>::Iterator it;
+
+ // don't forget those standard accounts
+ list << file->asset();
+ list << file->liability();
+ list << file->income();
+ list << file->expense();
+ list << file->equity();
+
+
+ for(it = list.begin(); it != list.end(); ++it) {
+ if((*it).currencyId().isEmpty() || (*it).currencyId().length() == 0) {
+ (*it).setCurrencyId(file->baseCurrency().id());
+ MyMoneyFileTransaction ft;
+ try {
+ file->modifyAccount(*it);
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ qDebug("Unable to setup base currency in account %s (%s): %s", (*it).name().latin1(), (*it).id().data(), e->what().latin1());
+ delete e;
+ }
+ }
+ }
+ }
+}
+
+void KMyMoneyView::loadDefaultCurrency(const MyMoneySecurity& currency, const bool create)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneySecurity sec;
+ MyMoneyFileTransaction ft;
+ try {
+ sec = file->currency(currency.id());
+ if(sec.name() != currency.name()) {
+ sec.setName(currency.name());
+ file->modifyCurrency(sec);
+ }
+ ft.commit();
+ } catch (MyMoneyException* e) {
+ delete e;
+ try {
+ if(create) {
+ file->addCurrency(currency);
+ }
+ ft.commit();
+ } catch (MyMoneyException* e) {
+ qDebug("Error %s loading default currency", e->what().data());
+ delete e;
+ }
+ }
+}
+
+void KMyMoneyView::loadDefaultCurrencies(void)
+{
+ // more information can be obtained from http://en.wikipedia.org/wiki/Currency_codes
+
+ bool create = MyMoneyFile::instance()->currencyList().count() == 0;
+ loadDefaultCurrency(MyMoneySecurity("AFA", i18n("Afghanistan Afghani")), create);
+ loadDefaultCurrency(MyMoneySecurity("ALL", i18n("Albanian Lek")), create);
+ loadDefaultCurrency(MyMoneySecurity("ANG", i18n("Netherland Antillian Guilder")), create);
+ loadDefaultCurrency(MyMoneySecurity("DZD", i18n("Algerian Dinar")), create);
+ loadDefaultCurrency(MyMoneySecurity("ADF", i18n("Andorran Franc")), create);
+ loadDefaultCurrency(MyMoneySecurity("ADP", i18n("Andorran Peseta")), create);
+ loadDefaultCurrency(MyMoneySecurity("AON", i18n("Angolan New Kwanza")), create);
+ loadDefaultCurrency(MyMoneySecurity("ARS", i18n("Argentine Peso"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("AWG", i18n("Aruban Florin")), create);
+ loadDefaultCurrency(MyMoneySecurity("AUD", i18n("Australian Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("AZM", i18n("Azerbaijani Manat")), create);
+ loadDefaultCurrency(MyMoneySecurity("BSD", i18n("Bahamian Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("BHD", i18n("Bahraini Dinar"), "BHD", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("BDT", i18n("Bangladeshi Taka")), create);
+ loadDefaultCurrency(MyMoneySecurity("BBD", i18n("Barbados Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("BYR", i18n("Belarussian Ruble"), "BYR", 1, 1), create);
+ loadDefaultCurrency(MyMoneySecurity("BZD", i18n("Belize Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("BMD", i18n("Bermudian Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("BTN", i18n("Bhutan Ngultrum")), create);
+ loadDefaultCurrency(MyMoneySecurity("BOB", i18n("Bolivian Boliviano")), create);
+ loadDefaultCurrency(MyMoneySecurity("BAM", i18n("Bosnian Convertible Mark")), create);
+ loadDefaultCurrency(MyMoneySecurity("BWP", i18n("Botswana Pula")), create);
+ loadDefaultCurrency(MyMoneySecurity("BRL", i18n("Brazilian Real"), "R$"), create);
+ loadDefaultCurrency(MyMoneySecurity("GBP", i18n("British Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("BND", i18n("Brunei Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("BGL", i18n("Bulgarian Lev")), create);
+ loadDefaultCurrency(MyMoneySecurity("BIF", i18n("Burundi Franc")), create);
+ loadDefaultCurrency(MyMoneySecurity("XAF", i18n("CFA Franc BEAC")), create);
+ loadDefaultCurrency(MyMoneySecurity("XOF", i18n("CFA Franc BCEAO")), create);
+ loadDefaultCurrency(MyMoneySecurity("XPF", i18n("CFP Franc Pacifique"), "F", 1, 1, 100), create);
+ loadDefaultCurrency(MyMoneySecurity("KHR", i18n("Cambodia Riel")), create);
+ loadDefaultCurrency(MyMoneySecurity("CAD", i18n("Canadian Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("CVE", i18n("Cape Verde Escudo")), create);
+ loadDefaultCurrency(MyMoneySecurity("KYD", i18n("Cayman Islands Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("CLP", i18n("Chilean Peso")), create);
+ loadDefaultCurrency(MyMoneySecurity("CNY", i18n("Chinese Yuan Renminbi")), create);
+ loadDefaultCurrency(MyMoneySecurity("COP", i18n("Colombian Peso")), create);
+ loadDefaultCurrency(MyMoneySecurity("KMF", i18n("Comoros Franc")), create);
+ loadDefaultCurrency(MyMoneySecurity("CRC", i18n("Costa Rican Colon"), QChar(0x20A1)), create);
+ loadDefaultCurrency(MyMoneySecurity("HRK", i18n("Croatian Kuna")), create);
+ loadDefaultCurrency(MyMoneySecurity("CUP", i18n("Cuban Peso")), create);
+ loadDefaultCurrency(MyMoneySecurity("CZK", i18n("Czech Koruna")), create);
+ loadDefaultCurrency(MyMoneySecurity("DKK", i18n("Danish Krone"), "kr"), create);
+ loadDefaultCurrency(MyMoneySecurity("DJF", i18n("Djibouti Franc")), create);
+ loadDefaultCurrency(MyMoneySecurity("DOP", i18n("Dominican Peso")), create);
+ loadDefaultCurrency(MyMoneySecurity("XCD", i18n("East Caribbean Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("EGP", i18n("Egyptian Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("SVC", i18n("El Salvador Colon")), create);
+ loadDefaultCurrency(MyMoneySecurity("ERN", i18n("Eritrean Nakfa")), create);
+ loadDefaultCurrency(MyMoneySecurity("EEK", i18n("Estonian Kroon")), create);
+ loadDefaultCurrency(MyMoneySecurity("ETB", i18n("Ethiopian Birr")), create);
+ loadDefaultCurrency(MyMoneySecurity("EUR", i18n("Euro"), QChar(0x20ac)), true);
+ loadDefaultCurrency(MyMoneySecurity("FKP", i18n("Falkland Islands Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("FJD", i18n("Fiji Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("GMD", i18n("Gambian Dalasi")), create);
+ loadDefaultCurrency(MyMoneySecurity("GEL", i18n("Georgian Lari")), create);
+ loadDefaultCurrency(MyMoneySecurity("GHC", i18n("Ghanaian Cedi")), create);
+ loadDefaultCurrency(MyMoneySecurity("GIP", i18n("Gibraltar Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("GTQ", i18n("Guatemalan Quetzal")), create);
+ loadDefaultCurrency(MyMoneySecurity("GWP", i18n("Guinea-Bissau Peso")), create);
+ loadDefaultCurrency(MyMoneySecurity("GYD", i18n("Guyanan Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("HTG", i18n("Haitian Gourde")), create);
+ loadDefaultCurrency(MyMoneySecurity("HNL", i18n("Honduran Lempira")), create);
+ loadDefaultCurrency(MyMoneySecurity("HKD", i18n("Hong Kong Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("HUF", i18n("Hungarian Forint"), "HUF", 1, 1, 100), create);
+ loadDefaultCurrency(MyMoneySecurity("ISK", i18n("Iceland Krona")), create);
+ loadDefaultCurrency(MyMoneySecurity("INR", i18n("Indian Rupee"), QChar(0x20A8)), create);
+ loadDefaultCurrency(MyMoneySecurity("IDR", i18n("Indonesian Rupiah"), "IDR", 100, 1), create);
+ loadDefaultCurrency(MyMoneySecurity("IRR", i18n("Iranian Rial"), "IRR", 1, 1), create);
+ loadDefaultCurrency(MyMoneySecurity("IQD", i18n("Iraqi Dinar"), "IQD", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("ILS", i18n("Israeli New Shekel"), QChar(0x20AA)), create);
+ loadDefaultCurrency(MyMoneySecurity("JMD", i18n("Jamaican Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("JPY", i18n("Japanese Yen"), QChar(0x00A5), 100, 1), create);
+ loadDefaultCurrency(MyMoneySecurity("JOD", i18n("Jordanian Dinar"), "JOD", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("KZT", i18n("Kazakhstan Tenge")), create);
+ loadDefaultCurrency(MyMoneySecurity("KES", i18n("Kenyan Shilling")), create);
+ loadDefaultCurrency(MyMoneySecurity("KWD", i18n("Kuwaiti Dinar"), "KWD", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("KGS", i18n("Kyrgyzstan Som")), create);
+ loadDefaultCurrency(MyMoneySecurity("LAK", i18n("Laos Kip"), QChar(0x20AD)), create);
+ loadDefaultCurrency(MyMoneySecurity("LVL", i18n("Latvian Lats")), create);
+ loadDefaultCurrency(MyMoneySecurity("LBP", i18n("Lebanese Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("LSL", i18n("Lesotho Loti")), create);
+ loadDefaultCurrency(MyMoneySecurity("LRD", i18n("Liberian Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("LYD", i18n("Libyan Dinar"), "LYD", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("LTL", i18n("Lithuanian Litas")), create);
+ loadDefaultCurrency(MyMoneySecurity("MOP", i18n("Macau Pataca")), create);
+ loadDefaultCurrency(MyMoneySecurity("MKD", i18n("Macedonian Denar")), create);
+ loadDefaultCurrency(MyMoneySecurity("MGF", i18n("Malagasy Franc"), "MGF", 500, 500), create);
+ loadDefaultCurrency(MyMoneySecurity("MWK", i18n("Malawi Kwacha")), create);
+ loadDefaultCurrency(MyMoneySecurity("MYR", i18n("Malaysian Ringgit")), create);
+ loadDefaultCurrency(MyMoneySecurity("MVR", i18n("Maldive Rufiyaa")), create);
+ loadDefaultCurrency(MyMoneySecurity("MLF", i18n("Mali Republic Franc")), create);
+ loadDefaultCurrency(MyMoneySecurity("MRO", i18n("Mauritanian Ouguiya"), "MRO", 5, 5), create);
+ loadDefaultCurrency(MyMoneySecurity("MUR", i18n("Mauritius Rupee")), create);
+ loadDefaultCurrency(MyMoneySecurity("MXN", i18n("Mexican Peso"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("MDL", i18n("Moldavian Leu")), create);
+ loadDefaultCurrency(MyMoneySecurity("MNT", i18n("Mongolian Tugrik"), QChar(0x20AE)), create);
+ loadDefaultCurrency(MyMoneySecurity("MAD", i18n("Moroccan Dirham")), create);
+ loadDefaultCurrency(MyMoneySecurity("MZM", i18n("Mozambique Metical")), create);
+ loadDefaultCurrency(MyMoneySecurity("MMK", i18n("Myanmar Kyat")), create);
+ loadDefaultCurrency(MyMoneySecurity("NAD", i18n("Namibian Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("NPR", i18n("Nepalese Rupee")), create);
+ loadDefaultCurrency(MyMoneySecurity("NZD", i18n("New Zealand Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("NIC", i18n("Nicaraguan Cordoba Oro")), create);
+ loadDefaultCurrency(MyMoneySecurity("NGN", i18n("Nigerian Naira"), QChar(0x20A6)), create);
+ loadDefaultCurrency(MyMoneySecurity("KPW", i18n("North Korean Won"), QChar(0x20A9)), create);
+ loadDefaultCurrency(MyMoneySecurity("NOK", i18n("Norwegian Kroner"), "kr"), create);
+ loadDefaultCurrency(MyMoneySecurity("OMR", i18n("Omani Rial"), "OMR", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("PKR", i18n("Pakistan Rupee")), create);
+ loadDefaultCurrency(MyMoneySecurity("PAB", i18n("Panamanian Balboa")), create);
+ loadDefaultCurrency(MyMoneySecurity("PGK", i18n("Papua New Guinea Kina")), create);
+ loadDefaultCurrency(MyMoneySecurity("PYG", i18n("Paraguay Guarani")), create);
+ loadDefaultCurrency(MyMoneySecurity("PEN", i18n("Peruvian Nuevo Sol")), create);
+ loadDefaultCurrency(MyMoneySecurity("PHP", i18n("Philippine Peso"), QChar(0x20B1)), create);
+ loadDefaultCurrency(MyMoneySecurity("PLN", i18n("Polish Zloty")), create);
+ loadDefaultCurrency(MyMoneySecurity("QAR", i18n("Qatari Rial")), create);
+ loadDefaultCurrency(MyMoneySecurity("RON", i18n("Romanian Leu (new)")), true);
+ loadDefaultCurrency(MyMoneySecurity("RUB", i18n("Russian Ruble")), true);
+ loadDefaultCurrency(MyMoneySecurity("RWF", i18n("Rwanda Franc")), create);
+ loadDefaultCurrency(MyMoneySecurity("WST", i18n("Samoan Tala")), create);
+ loadDefaultCurrency(MyMoneySecurity("STD", i18n("Sao Tome and Principe Dobra")), create);
+ loadDefaultCurrency(MyMoneySecurity("SAR", i18n("Saudi Riyal")), create);
+ loadDefaultCurrency(MyMoneySecurity("SCR", i18n("Seychelles Rupee")), create);
+ loadDefaultCurrency(MyMoneySecurity("SLL", i18n("Sierra Leone Leone")), create);
+ loadDefaultCurrency(MyMoneySecurity("SGD", i18n("Singapore Dollar"), "$"), create);
+ // loadDefaultCurrency(MyMoneySecurity("SKK", i18n("Slovak Koruna")), create);
+ // loadDefaultCurrency(MyMoneySecurity("SIT", i18n("Slovenian Tolar")), create);
+ loadDefaultCurrency(MyMoneySecurity("SBD", i18n("Solomon Islands Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("SOS", i18n("Somali Shilling")), create);
+ loadDefaultCurrency(MyMoneySecurity("ZAR", i18n("South African Rand")), create);
+ loadDefaultCurrency(MyMoneySecurity("KRW", i18n("South Korean Won"), QChar(0x20A9)), create);
+ loadDefaultCurrency(MyMoneySecurity("LKR", i18n("Sri Lanka Rupee")), create);
+ loadDefaultCurrency(MyMoneySecurity("SHP", i18n("St. Helena Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("SDD", i18n("Sudanese Dinar")), create);
+ loadDefaultCurrency(MyMoneySecurity("SRG", i18n("Suriname Guilder")), create);
+ loadDefaultCurrency(MyMoneySecurity("SZL", i18n("Swaziland Lilangeni")), create);
+ loadDefaultCurrency(MyMoneySecurity("SEK", i18n("Swedish Krona")), create);
+ loadDefaultCurrency(MyMoneySecurity("CHF", i18n("Swiss Franc"), "SFr"), create);
+ loadDefaultCurrency(MyMoneySecurity("SYP", i18n("Syrian Pound"), QChar(0x00A3)), create);
+ loadDefaultCurrency(MyMoneySecurity("TWD", i18n("Taiwan Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("TJS", i18n("Tajikistan Somani")), create);
+ loadDefaultCurrency(MyMoneySecurity("TZS", i18n("Tanzanian Shilling")), create);
+ loadDefaultCurrency(MyMoneySecurity("THB", i18n("Thai Baht"), QChar(0x0E3F)), create);
+ loadDefaultCurrency(MyMoneySecurity("TOP", i18n("Tongan Pa'anga")), create);
+ loadDefaultCurrency(MyMoneySecurity("TTD", i18n("Trinidad and Tobago Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("TND", i18n("Tunisian Dinar"), "TND", 1000, 1000), create);
+ loadDefaultCurrency(MyMoneySecurity("TRY", i18n("Turkish Lira (new)"), "YTL"), true);
+ loadDefaultCurrency(MyMoneySecurity("TMM", i18n("Turkmenistan Manat")), create);
+ loadDefaultCurrency(MyMoneySecurity("USD", i18n("US Dollar"), "$"), create);
+ loadDefaultCurrency(MyMoneySecurity("UGX", i18n("Uganda Shilling")), create);
+ loadDefaultCurrency(MyMoneySecurity("UAH", i18n("Ukraine Hryvnia")), create);
+ loadDefaultCurrency(MyMoneySecurity("AED", i18n("United Arab Emirates Dirham")), create);
+ loadDefaultCurrency(MyMoneySecurity("UYU", i18n("Uruguayan Peso")), create);
+ loadDefaultCurrency(MyMoneySecurity("UZS", i18n("Uzbekistani Sum")), create);
+ loadDefaultCurrency(MyMoneySecurity("VUV", i18n("Vanuatu Vatu")), create);
+ loadDefaultCurrency(MyMoneySecurity("VEB", i18n("Venezuelan Bolivar")), create);
+ loadDefaultCurrency(MyMoneySecurity("VND", i18n("Vietnamese Dong"), QChar(0x20AB)), create);
+ loadDefaultCurrency(MyMoneySecurity("YUM", i18n("Yugoslav Dinar")), create);
+ loadDefaultCurrency(MyMoneySecurity("ZMK", i18n("Zambian Kwacha")), create);
+ loadDefaultCurrency(MyMoneySecurity("ZWD", i18n("Zimbabwe Dollar"), "$"), create);
+
+ loadDefaultCurrency(MyMoneySecurity("XAU", i18n("Gold"), "XAU", 1, 1000000), create);
+ loadDefaultCurrency(MyMoneySecurity("XPD", i18n("Palladium"), "XPD", 1, 1000000), create);
+ loadDefaultCurrency(MyMoneySecurity("XPT", i18n("Platinum"), "XPT", 1, 1000000), create);
+ loadDefaultCurrency(MyMoneySecurity("XAG", i18n("Silver"), "XAG", 1, 1000000), create);
+}
+
+void KMyMoneyView::loadAncientCurrency(const QString& id, const QString& name, const QString& sym, const QDate& date, const MyMoneyMoney& rate, const QString& newId, const int partsPerUnit, const int smallestCashFraction, const int smallestAccountFraction)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyPrice price(id, newId, date, rate, "KMyMoney");
+ MyMoneyFileTransaction ft;
+ try {
+ // make sure if entry exists
+ file->currency(id);
+ // make sure we have the right price
+ if(file->price(id, newId, date, true) != price) {
+ file->addPrice(price);
+ }
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ delete e;
+ try {
+ file->addCurrency(MyMoneySecurity(id, name, sym, partsPerUnit, smallestCashFraction, smallestAccountFraction));
+ if(date.isValid()) {
+ file->addPrice(price);
+ }
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ qDebug("Error loading currency: %s", e->what().data());
+ delete e;
+ }
+ }
+}
+
+void KMyMoneyView::loadAncientCurrencies(void)
+{
+ loadAncientCurrency("ATS", i18n("Austrian Schilling"), "ÖS", QDate(1998,12,31), MyMoneyMoney(10000, 137603), "EUR");
+ loadAncientCurrency("DEM", i18n("German Mark"), "DM", QDate(1998,12,31), MyMoneyMoney(100000, 195583), "EUR");
+ loadAncientCurrency("FRF", i18n("French Franc"), "FF", QDate(1998,12,31), MyMoneyMoney(100000, 655957), "EUR");
+ loadAncientCurrency("ITL", i18n("Italian Lira"), QChar(0x20A4), QDate(1998,12,31), MyMoneyMoney(100, 193627), "EUR");
+ loadAncientCurrency("ESP", i18n("Spanish Peseta"), QString(), QDate(1998,12,31), MyMoneyMoney(1000, 166386), "EUR");
+ loadAncientCurrency("NLG", i18n("Dutch Guilder"), QString(), QDate(1998,12,31), MyMoneyMoney(100000, 220371), "EUR");
+ loadAncientCurrency("BEF", i18n("Belgian Franc"), "Fr", QDate(1998,12,31), MyMoneyMoney(10000, 403399), "EUR");
+ loadAncientCurrency("LUF", i18n("Luxembourg Franc"), "Fr", QDate(1998,12,31), MyMoneyMoney(10000, 403399), "EUR");
+ loadAncientCurrency("PTE", i18n("Portuguese Escudo"), QString(), QDate(1998,12,31), MyMoneyMoney(1000, 200482), "EUR");
+ loadAncientCurrency("IEP", i18n("Irish Pound"), QChar(0x00A3), QDate(1998,12,31), MyMoneyMoney(1000000, 787564), "EUR");
+ loadAncientCurrency("FIM", i18n("Finnish Markka"), QString(), QDate(1998,12,31), MyMoneyMoney(100000, 594573), "EUR");
+ loadAncientCurrency("GRD", i18n("Greek Drachma"), QChar(0x20AF), QDate(1998,12,31), MyMoneyMoney(100, 34075), "EUR");
+
+ loadAncientCurrency("ROL", i18n("Romanian Leu"), "ROL", QDate(2005,6,30), MyMoneyMoney(1, 10000), "RON");
+
+ loadAncientCurrency("RUR", i18n("Russian Ruble (old)"), "RUR", QDate(1998, 1, 1), MyMoneyMoney(1, 1000), "RUB");
+
+ loadAncientCurrency("SIT", i18n("Slovenian Tolar"), "SIT", QDate(2006,12,31), MyMoneyMoney(100, 23964), "EUR");
+
+ // Source: http://www.tf-portfoliosolutions.net/products/turkishlira.aspx
+ loadAncientCurrency("TRL", i18n("Turkish Lira"), "TL", QDate(2004,12,31), MyMoneyMoney(1,1000000), "TRY");
+
+ // Source: http://www.focus.de/finanzen/news/malta-und-zypern_aid_66058.html
+ loadAncientCurrency("MTL", i18n("Maltese Lira"), "MTL", QDate(2008,1,1), MyMoneyMoney(429300,1000000), "EUR");
+ loadAncientCurrency("CYP", i18n("Cyprus Pound"), QString("C%1").arg(QChar(0x00A3)), QDate(2008,1,1), MyMoneyMoney(585274,1000000), "EUR");
+
+ // Source: http://www.focus.de/finanzen/news/waehrungszone-slowakei-ist-neuer-euro-staat_aid_359025.html
+ loadAncientCurrency("SKK", i18n("Slovak Koruna"), "SKK", QDate(2008,12,31), MyMoneyMoney(1000,30126), "EUR");
+}
+
+void KMyMoneyView::viewUp(void)
+{
+ if (!fileOpen())
+ return;
+}
+
+void KMyMoneyView::viewAccountList(const QString& /*selectAccount*/)
+{
+ if(pageIndex(m_accountsViewFrame) != activePageIndex())
+ showPage(1);
+
+ m_accountsView->show();
+}
+
+void KMyMoneyView::slotRefreshViews()
+{
+ // turn off sync between ledger and investment view
+ disconnect(m_investmentView, SIGNAL(accountSelected(const MyMoneyObject&)), m_ledgerView, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ disconnect(m_ledgerView, SIGNAL(accountSelected(const MyMoneyObject&)), m_investmentView, SLOT(slotSelectAccount(const MyMoneyObject&)));
+
+ // TODO turn sync between ledger and investment view if selected by user
+ if(KMyMoneyGlobalSettings::syncLedgerInvestment()) {
+ connect(m_investmentView, SIGNAL(accountSelected(const MyMoneyObject&)), m_ledgerView, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ connect(m_ledgerView, SIGNAL(accountSelected(const MyMoneyObject&)), m_investmentView, SLOT(slotSelectAccount(const MyMoneyObject&)));
+ }
+
+ showTitleBar(KMyMoneyGlobalSettings::showTitleBar());
+
+ m_accountsView->slotLoadAccounts();
+ m_institutionsView->slotLoadAccounts();
+ m_categoriesView->slotLoadAccounts();
+ m_payeesView->slotLoadPayees();
+ m_ledgerView->slotLoadView();
+ m_budgetView->slotRefreshView();
+ m_homeView->slotLoadView();
+ m_investmentView->slotLoadView();
+ m_reportsView->slotLoadView();
+ m_forecastView->slotLoadForecast();
+
+ m_scheduledView->slotReloadView();
+}
+
+void KMyMoneyView::slotShowTransactionDetail(bool detailed)
+{
+ KMyMoneyGlobalSettings::setShowRegisterDetailed(detailed);
+ slotRefreshViews();
+}
+
+
+void KMyMoneyView::progressCallback(int current, int total, const QString& msg)
+{
+ kmymoney2->progressCallback(current, total, msg);
+}
+
+void KMyMoneyView::slotRememberPage(QWidget* w)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("LastViewSelected", pageIndex(w));
+ config->sync();
+}
+
+/* DO NOT ADD code to this function or any of it's called ones.
+ Instead, create a new function, fixFile_n, and modify the initializeStorage()
+ logic above to call it */
+
+void KMyMoneyView::fixFile_2(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits( false );
+ QValueList<MyMoneyTransaction> transactionList;
+ file->transactionList(transactionList, filter);
+
+ // scan the transactions and modify transactions with two splits
+ // which reference an account and a category to have the memo text
+ // of the account.
+ QValueList<MyMoneyTransaction>::Iterator it_t;
+ int count = 0;
+ for(it_t = transactionList.begin(); it_t != transactionList.end(); ++it_t) {
+ if((*it_t).splitCount() == 2) {
+ QString accountId;
+ QString categoryId;
+ QString accountMemo;
+ QString categoryMemo;
+ const QValueList<MyMoneySplit>& splits = (*it_t).splits();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ if(acc.isIncomeExpense()) {
+ categoryId = (*it_s).id();
+ categoryMemo = (*it_s).memo();
+ } else {
+ accountId = (*it_s).id();
+ accountMemo = (*it_s).memo();
+ }
+ }
+
+ if(!accountId.isEmpty() && !categoryId.isEmpty()
+ && accountMemo != categoryMemo) {
+ MyMoneyTransaction t(*it_t);
+ MyMoneySplit s(t.splitById(categoryId));
+ s.setMemo(accountMemo);
+ t.modifySplit(s);
+ file->modifyTransaction(t);
+ ++count;
+ }
+ }
+ }
+ qDebug("%d transactions fixed in fixFile_2", count);
+}
+
+void KMyMoneyView::fixFile_1(void)
+{
+ // we need to fix reports. If the account filter list contains
+ // investment accounts, we need to add the stock accounts to the list
+ // as well if we don't have the expert mode enabled
+ if(!KMyMoneyGlobalSettings::expertMode()) {
+ try {
+ QValueList<MyMoneyReport> reports = MyMoneyFile::instance()->reportList();
+ QValueList<MyMoneyReport>::iterator it_r;
+ for(it_r = reports.begin(); it_r != reports.end(); ++it_r) {
+ QStringList list;
+ (*it_r).accounts(list);
+ QStringList missing;
+ QStringList::const_iterator it_a, it_b;
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
+ if(!list.contains(*it_b)) {
+ missing.append(*it_b);
+ }
+ }
+ }
+ }
+ if(!missing.isEmpty()) {
+ (*it_r).addAccount(missing);
+ MyMoneyFile::instance()->modifyReport(*it_r);
+ }
+ }
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+ }
+}
+
+#if 0
+ if(!m_accountsView->allItemsSelected()) {
+ // retrieve a list of selected accounts
+ QStringList list;
+ m_accountsView->selectedItems(list);
+
+ // if we're not in expert mode, we need to make sure
+ // that all stock accounts for the selected investment
+ // account are also selected
+ if(!KMyMoneyGlobalSettings::expertMode()) {
+ QStringList missing;
+ QStringList::const_iterator it_a, it_b;
+ for(it_a = list.begin(); it_a != list.end(); ++it_a) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
+ if(!list.contains(*it_b)) {
+ missing.append(*it_b);
+ }
+ }
+ }
+ }
+ list += missing;
+ }
+
+ m_filter.addAccount(list);
+ }
+
+#endif
+
+
+
+
+
+void KMyMoneyView::fixFile_0(void)
+{
+ /* (Ace) I am on a crusade against file fixups. Whenever we have to fix the
+ * file, it is really a warning. So I'm going to print a debug warning, and
+ * then go track them down when I see them to figure out how they got saved
+ * out needing fixing anyway.
+ */
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneyAccount> accountList;
+ file->accountList(accountList);
+ ::timetrace("Have account list");
+ QValueList<MyMoneyAccount>::Iterator it_a;
+ QValueList<MyMoneySchedule> scheduleList = file->scheduleList();
+ ::timetrace("Have schedule list");
+ QValueList<MyMoneySchedule>::Iterator it_s;
+
+ MyMoneyAccount equity = file->equity();
+ MyMoneyAccount asset = file->asset();
+ bool equityListEmpty = equity.accountList().count() == 0;
+
+ ::timetrace("Fix accounts start");
+ for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
+ if((*it_a).accountType() == MyMoneyAccount::Loan
+ || (*it_a).accountType() == MyMoneyAccount::AssetLoan) {
+ fixLoanAccount_0(*it_a);
+ }
+ // until early before 0.8 release, the equity account was not saved to
+ // the file. If we have an equity account with no sub-accounts but
+ // find and equity account that has equity() as it's parent, we reparent
+ // this account. Need to move it to asset() first, because otherwise
+ // MyMoneyFile::reparent would act as NOP.
+ if(equityListEmpty && (*it_a).accountType() == MyMoneyAccount::Equity) {
+ if((*it_a).parentAccountId() == equity.id()) {
+ MyMoneyAccount acc = *it_a;
+ // tricky, force parent account to be empty so that we really
+ // can re-parent it
+ acc.setParentAccountId(QString());
+ file->reparentAccount(acc, equity);
+ kdDebug(2) << __func__ << " fixed account " << acc.id() << " reparented to " << equity.id() << endl;
+ }
+ }
+ }
+
+ ::timetrace("Fix schedules start");
+ for(it_s = scheduleList.begin(); it_s != scheduleList.end(); ++it_s) {
+ fixSchedule_0(*it_s);
+ }
+
+ ::timetrace("Fix transactions start");
+ fixTransactions_0();
+ ::timetrace("Fix transactions done");
+}
+
+void KMyMoneyView::fixSchedule_0(MyMoneySchedule sched)
+{
+ MyMoneyTransaction t = sched.transaction();
+ QValueList<MyMoneySplit> splitList = t.splits();
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ bool updated = false;
+
+ try {
+ // Check if the splits contain valid data and set it to
+ // be valid.
+ for(it_s = splitList.begin(); it_s != splitList.end(); ++it_s) {
+ // the first split is always the account on which this transaction operates
+ // and if the transaction commodity is not set, we take this
+ if(it_s == splitList.begin() && t.commodity().isEmpty()) {
+ kdDebug(2) << __func__ << " " << t.id() << " has no commodity" << endl;
+ try {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ t.setCommodity(acc.currencyId());
+ updated = true;
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+ }
+ // make sure the account exists. If not, remove the split
+ try {
+ MyMoneyFile::instance()->account((*it_s).accountId());
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << __func__ << " " << sched.id() << " " << (*it_s).id() << " removed, because account '" << (*it_s).accountId() << "' does not exist." << endl;
+ t.removeSplit(*it_s);
+ updated = true;
+ delete e;
+ }
+ if((*it_s).reconcileFlag() != MyMoneySplit::NotReconciled) {
+ kdDebug(2) << __func__ << " " << sched.id() << " " << (*it_s).id() << " should be 'not reconciled'" << endl;
+ MyMoneySplit split = *it_s;
+ split.setReconcileDate(QDate());
+ split.setReconcileFlag(MyMoneySplit::NotReconciled);
+ t.modifySplit(split);
+ updated = true;
+ }
+ // the schedule logic used to operate only on the value field.
+ // This is now obsolete.
+ if((*it_s).shares().isZero() && !(*it_s).value().isZero()) {
+ MyMoneySplit split = *it_s;
+ split.setShares(split.value());
+ t.modifySplit(split);
+ updated = true;
+ }
+ }
+
+ // If there have been changes, update the schedule and
+ // the engine data.
+ if(updated) {
+ sched.setTransaction(t);
+ MyMoneyFile::instance()->modifySchedule(sched);
+ }
+ } catch(MyMoneyException *e) {
+ qWarning("Unable to update broken schedule: %s", e->what().latin1());
+ delete e;
+ }
+}
+
+void KMyMoneyView::fixLoanAccount_0(MyMoneyAccount acc)
+{
+ if(acc.value("final-payment").isEmpty()
+ || acc.value("term").isEmpty()
+ || acc.value("periodic-payment").isEmpty()
+ || acc.value("loan-amount").isEmpty()
+ || acc.value("interest-calculation").isEmpty()
+ || acc.value("schedule").isEmpty()
+ || acc.value("fixed-interest").isEmpty()) {
+ KMessageBox::information(this,
+ i18n("The account \"%1\" was previously created as loan account but some information "
+ "is missing. The new loan wizard will be started to collect all relevant "
+ "information. Please use a KMyMoney version >= 0.8.7 and < 0.9 to correct the problem."
+ ).arg(acc.name()),
+ i18n("Account problem"));
+
+ throw new MYMONEYEXCEPTION("Fix LoanAccount0 not supported anymore");
+ }
+}
+
+void KMyMoneyView::createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount)
+{
+ // Add the schedule only if one exists
+ //
+ // Remember to modify the first split to reference the newly created account
+ if (!newSchedule.name().isEmpty())
+ {
+ MyMoneyFileTransaction ft;
+ try
+ {
+ // We assume at least 2 splits in the transaction
+ MyMoneyTransaction t = newSchedule.transaction();
+ if(t.splitCount() < 2) {
+ throw new MYMONEYEXCEPTION("Transaction for schedule has less than 2 splits!");
+ }
+ // now search the split that does not have an account reference
+ // and set it up to be the one of the account we just added
+ // to the account pool. Note: the schedule code used to leave
+ // this always the first split, but the loan code leaves it as
+ // the second one. So I thought, searching is a good alternative ....
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if((*it_s).accountId().isEmpty()) {
+ MyMoneySplit s = (*it_s);
+ s.setAccountId(newAccount.id());
+ t.modifySplit(s);
+ break;
+ }
+ }
+ newSchedule.setTransaction(t);
+
+ MyMoneyFile::instance()->addSchedule(newSchedule);
+
+ // in case of a loan account, we keep a reference to this
+ // schedule in the account
+ if(newAccount.isLoan()) {
+ newAccount.setValue("schedule", newSchedule.id());
+ MyMoneyFile::instance()->modifyAccount(newAccount);
+ }
+ ft.commit();
+ }
+ catch (MyMoneyException *e)
+ {
+ KMessageBox::information(this, i18n("Unable to add schedule: "), e->what());
+ delete e;
+ }
+ }
+}
+
+void KMyMoneyView::fixTransactions_0(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+#if 0
+ ::timetrace("Start alloc memory");
+ int * p = new int [10000];
+ delete p;
+ ::timetrace("Done alloc memory");
+#endif
+
+ ::timetrace("fixTransactions: get schedule list");
+ QValueList<MyMoneySchedule> scheduleList = file->scheduleList();
+ ::timetrace("fixTransactions: get transaction list");
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits( false );
+ QValueList<MyMoneyTransaction> transactionList;
+ file->transactionList(transactionList, filter);
+ ::timetrace("fixTransactions: have list");
+
+ QValueList<MyMoneySchedule>::Iterator it_x;
+ QStringList interestAccounts;
+
+ KMSTATUS(i18n("Fix transactions"));
+ kmymoney2->slotStatusProgressBar(0, scheduleList.count() + transactionList.count());
+
+ int cnt = 0;
+ // scan the schedules to find interest accounts
+ for(it_x = scheduleList.begin(); it_x != scheduleList.end(); ++it_x) {
+ MyMoneyTransaction t = (*it_x).transaction();
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ QStringList accounts;
+ bool hasDuplicateAccounts = false;
+
+ for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
+ if(accounts.contains((*it_s).accountId())) {
+ hasDuplicateAccounts = true;
+ kdDebug(2) << __func__ << " " << t.id() << " has multiple splits with account " << (*it_s).accountId() << endl;
+ } else {
+ accounts << (*it_s).accountId();
+ }
+
+ if((*it_s).action() == MyMoneySplit::ActionInterest) {
+ if(interestAccounts.contains((*it_s).accountId()) == 0) {
+ interestAccounts << (*it_s).accountId();
+ }
+ }
+ }
+ if(hasDuplicateAccounts) {
+ fixDuplicateAccounts_0(t);
+ }
+ ++cnt;
+ if(!(cnt % 10))
+ kmymoney2->slotStatusProgressBar(cnt);
+ }
+
+ ::timetrace("fixTransactions: start loop");
+ // scan the transactions and modify loan transactions
+ QValueList<MyMoneyTransaction>::Iterator it_t;
+ for(it_t = transactionList.begin(); it_t != transactionList.end(); ++it_t) {
+ const char *defaultAction = 0;
+ QValueList<MyMoneySplit> splits = (*it_t).splits();
+ QValueList<MyMoneySplit>::Iterator it_s;
+ QStringList accounts;
+
+ // check if base commodity is set. if not, set baseCurrency
+ if((*it_t).commodity().isEmpty()) {
+ kdDebug(2) << __func__ << " " << (*it_t).id() << " has no base currency" << endl;
+ (*it_t).setCommodity(file->baseCurrency().id());
+ file->modifyTransaction(*it_t);
+ }
+
+ bool isLoan = false;
+ // Determine default action
+ if((*it_t).splitCount() == 2) {
+ // check for transfer
+ int accountCount = 0;
+ MyMoneyMoney val;
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ if(acc.accountGroup() == MyMoneyAccount::Asset
+ || acc.accountGroup() == MyMoneyAccount::Liability) {
+ val = (*it_s).value();
+ accountCount++;
+ if(acc.accountType() == MyMoneyAccount::Loan
+ || acc.accountType() == MyMoneyAccount::AssetLoan)
+ isLoan = true;
+ } else
+ break;
+ }
+ if(accountCount == 2) {
+ if(isLoan)
+ defaultAction = MyMoneySplit::ActionAmortization;
+ else
+ defaultAction = MyMoneySplit::ActionTransfer;
+ } else {
+ if(val.isNegative())
+ defaultAction = MyMoneySplit::ActionWithdrawal;
+ else
+ defaultAction = MyMoneySplit::ActionDeposit;
+ }
+ }
+
+ isLoan = false;
+ for(it_s = splits.begin(); defaultAction == 0 && it_s != splits.end(); ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ MyMoneyMoney val = (*it_s).value();
+ if(acc.accountGroup() == MyMoneyAccount::Asset
+ || acc.accountGroup() == MyMoneyAccount::Liability) {
+ if(!val.isPositive())
+ defaultAction = MyMoneySplit::ActionWithdrawal;
+ else
+ defaultAction = MyMoneySplit::ActionDeposit;
+ }
+ }
+
+#if 0
+ // Check for correct actions in transactions referencing credit cards
+ bool needModify = false;
+ // The action fields are actually not used anymore in the ledger view logic
+ // so we might as well skip this whole thing here!
+ for(it_s = splits.begin(); needModify == false && it_s != splits.end(); ++it_s) {
+ MyMoneyAccount acc = file->account((*it_s).accountId());
+ MyMoneyMoney val = (*it_s).value();
+ if(acc.accountType() == MyMoneyAccount::CreditCard) {
+ if(val < 0 && (*it_s).action() != MyMoneySplit::ActionWithdrawal && (*it_s).action() != MyMoneySplit::ActionTransfer )
+ needModify = true;
+ if(val >= 0 && (*it_s).action() != MyMoneySplit::ActionDeposit && (*it_s).action() != MyMoneySplit::ActionTransfer)
+ needModify = true;
+ }
+ }
+
+ // (Ace) Extended the #endif down to cover this conditional, because as-written
+ // it will ALWAYS be skipped.
+
+ if(needModify == true) {
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ (*it_s).setAction(defaultAction);
+ (*it_t).modifySplit(*it_s);
+ file->modifyTransaction(*it_t);
+ }
+ splits = (*it_t).splits(); // update local copy
+ qDebug("Fixed credit card assignment in %s", (*it_t).id().data());
+ }
+#endif
+
+ bool hasDuplicateAccounts = false;
+ // Check for correct assignment of ActionInterest in all splits
+ // and check if there are any duplicates in this transactions
+ for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
+ MyMoneyAccount splitAccount = file->account((*it_s).accountId());
+ if(accounts.contains((*it_s).accountId())) {
+ hasDuplicateAccounts = true;
+ } else {
+ accounts << (*it_s).accountId();
+ }
+ // if this split references an interest account, the action
+ // must be of type ActionInterest
+ if(interestAccounts.contains((*it_s).accountId())) {
+ if((*it_s).action() != MyMoneySplit::ActionInterest) {
+ kdDebug(2) << __func__ << " " << (*it_t).id() << " contains an interest account (" << (*it_s).accountId() << ") but does not have ActionInterest" << endl;
+ (*it_s).setAction(MyMoneySplit::ActionInterest);
+ (*it_t).modifySplit(*it_s);
+ file->modifyTransaction(*it_t);
+ qDebug("Fixed interest action in %s", (*it_t).id().data());
+ }
+ // if it does not reference an interest account, it must not be
+ // of type ActionInterest
+ } else {
+ if((*it_s).action() == MyMoneySplit::ActionInterest) {
+ kdDebug(2) << __func__ << " " << (*it_t).id() << " does not contain an interest account so it should not have ActionInterest" << endl;
+ (*it_s).setAction(defaultAction);
+ (*it_t).modifySplit(*it_s);
+ file->modifyTransaction(*it_t);
+ qDebug("Fixed interest action in %s", (*it_t).id().data());
+ }
+ }
+
+ // check that for splits referencing an account that has
+ // the same currency as the transactions commodity the value
+ // and shares field are the same.
+ if((*it_t).commodity() == splitAccount.currencyId()
+ && (*it_s).value() != (*it_s).shares()) {
+ kdDebug(2) << __func__ << " " << (*it_t).id() << " " << (*it_s).id() << " uses the transaction currency, but shares != value" << endl;
+ (*it_s).setShares((*it_s).value());
+ (*it_t).modifySplit(*it_s);
+ file->modifyTransaction(*it_t);
+ }
+
+ // fix the shares and values to have the correct fraction
+ if(!splitAccount.isInvest()) {
+ try {
+ int fract = splitAccount.fraction();
+ if((*it_s).shares() != (*it_s).shares().convert(fract)) {
+ qDebug("adjusting fraction in %s,%s", (*it_t).id().data(), (*it_s).id().data());
+ (*it_s).setShares((*it_s).shares().convert(fract));
+ (*it_s).setValue((*it_s).value().convert(fract));
+ (*it_t).modifySplit(*it_s);
+ file->modifyTransaction(*it_t);
+ }
+ } catch(MyMoneyException* e) {
+ qDebug("Missing security '%s', split not altered", splitAccount.currencyId().data());
+ delete e;
+ }
+ }
+ }
+
+/*
+ // if there are at least two splits referencing the same account,
+ // we need to combine them into one and get rid of the others
+ if(hasDuplicateAccounts) {
+ fixDuplicateAccounts(*it_t);
+ }
+*/
+ ++cnt;
+ if(!(cnt % 10))
+ kmymoney2->slotStatusProgressBar(cnt);
+ }
+
+ kmymoney2->slotStatusProgressBar(-1, -1);
+}
+
+void KMyMoneyView::fixDuplicateAccounts_0(MyMoneyTransaction& t)
+{
+ qDebug("Duplicate account in transaction %s", t.id().data());
+}
+
+void KMyMoneyView::slotPrintView(void)
+{
+ if(pageIndex(m_reportsViewFrame) == activePageIndex())
+ m_reportsView->slotPrintView();
+ else if(pageIndex(m_homeViewFrame) == activePageIndex())
+ m_homeView->slotPrintView();
+}
+
+KMyMoneyViewBase* KMyMoneyView::addPage(const QString& title, const QString& icon)
+{
+ const int iconSize = (KMyMoneyGlobalSettings::iconSize()+1)*16;
+ QFrame* frm = KJanusWidget::addVBoxPage(title, title, DesktopIcon(icon, iconSize));
+ return new KMyMoneyViewBase(frm, title.latin1(), title);
+}
+
+/* ------------------------------------------------------------------------ */
+/* KMyMoneyViewBase */
+/* ------------------------------------------------------------------------ */
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qvbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../widgets/kmymoneytitlelabel.h"
+
+class KMyMoneyViewBase::Private {
+ public:
+ QFrame* m_titleLine;
+ KMyMoneyTitleLabel* m_titleLabel;
+ QVBoxLayout* m_viewLayout;
+};
+
+KMyMoneyViewBase::KMyMoneyViewBase(QWidget* parent, const char* name, const QString& title) :
+ QWidget(parent, name),
+ d(new Private)
+{
+ d->m_viewLayout = new QVBoxLayout(this);
+ d->m_viewLayout->setSpacing( 6 );
+ d->m_viewLayout->setMargin( 0 );
+
+ d->m_titleLabel = new KMyMoneyTitleLabel( this, "titleLabel" );
+ d->m_titleLabel->setMinimumSize( QSize( 100, 30 ) );
+ d->m_titleLabel->setRightImageFile("pics/titlelabel_background.png" );
+ d->m_titleLabel->setText(title);
+ d->m_viewLayout->addWidget( d->m_titleLabel );
+
+#if 0
+ d->m_titleLine = new QFrame( this, "titleLine" );
+ d->m_titleLine->setFrameShape( QFrame::HLine );
+ d->m_titleLine->setFrameShadow( QFrame::Sunken );
+ d->m_titleLine->setFrameShape( QFrame::HLine );
+ d->m_viewLayout->addWidget( d->m_titleLine );
+#endif
+}
+
+KMyMoneyViewBase::~KMyMoneyViewBase()
+{
+ delete d;
+}
+
+void KMyMoneyViewBase::addWidget(QWidget* w)
+{
+ d->m_viewLayout->addWidget(w);
+}
+
+QVBoxLayout* KMyMoneyViewBase::layout(void) const
+{
+ return d->m_viewLayout;
+}
+
+#include "kmymoneyview.moc"
diff --git a/kmymoney2/views/kmymoneyview.h b/kmymoney2/views/kmymoneyview.h
new file mode 100644
index 0000000..13e3d76
--- /dev/null
+++ b/kmymoney2/views/kmymoneyview.h
@@ -0,0 +1,625 @@
+/***************************************************************************
+ kmymoneyview.h
+ -------------------
+ copyright : (C) 2000-2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef KMYMONEYVIEW_H
+#define KMYMONEYVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+class QVBox;
+class QFile;
+class QVBoxLayout;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpopupmenu.h>
+#include <kjanuswidget.h>
+
+#include <kurl.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/selectedtransaction.h>
+
+class KHomeView;
+class KAccountsView;
+class KCategoriesView;
+class KInstitutionsView;
+class KPayeesView;
+class KBudgetView;
+class KScheduledView;
+class KGlobalLedgerView;
+class IMyMoneyStorageFormat;
+class MyMoneyTransaction;
+class KInvestmentView;
+class KReportsView;
+class KMyMoneyViewBase;
+class MyMoneyReport;
+class TransactionEditor;
+class KForecastView;
+
+/**
+ * This class represents the view of the MyMoneyFile which contains
+ * Banks/Accounts/Transactions, Recurring transactions (or Bills & Deposits)
+ * and scripts (yet to be implemented). Each different aspect of the file
+ * is represented by a tab within the view.
+ *
+ * @author Michael Edwardes 2001 Copyright 2000-2001
+ *
+ * @short Handles the view of the MyMoneyFile.
+ */
+class KMyMoneyView : public KJanusWidget
+{
+ Q_OBJECT
+
+public:
+ enum viewID {
+ HomeView = 0,
+ AccountsView,
+ InstitutionsView,
+ SchedulesView,
+ CategoriesView,
+ PayeesView,
+ LedgersView,
+ InvestmentsView,
+ ReportsView,
+ BudgetView,
+ ForecastView
+ };
+ // file actions for plugin
+ enum fileActions {
+ preOpen, postOpen, preSave, postSave, preClose, postClose
+ };
+
+private:
+ enum menuID {
+ AccountNew = 1,
+ AccountOpen,
+ AccountReconcile,
+ AccountEdit,
+ AccountDelete,
+ AccountOnlineMap,
+ AccountOnlineUpdate,
+ AccountOfxConnect,
+ CategoryNew
+ };
+
+ typedef enum storageTypeE { // not used but keep for future implementation
+ Memory = 0,
+ Database
+ } _storageType;
+
+ KHomeView *m_homeView;
+ KAccountsView *m_accountsView;
+ KInstitutionsView *m_institutionsView;
+ KCategoriesView *m_categoriesView;
+ KPayeesView *m_payeesView;
+ KBudgetView *m_budgetView;
+ KScheduledView *m_scheduledView;
+ KGlobalLedgerView *m_ledgerView;
+ KInvestmentView *m_investmentView;
+ KReportsView* m_reportsView;
+ KForecastView* m_forecastView;
+
+ QVBox* m_homeViewFrame;
+ QVBox* m_accountsViewFrame;
+ QVBox* m_institutionsViewFrame;
+ QVBox* m_categoriesViewFrame;
+ QVBox* m_payeesViewFrame;
+ QVBox* m_budgetViewFrame;
+ QVBox* m_scheduleViewFrame;
+ QVBox* m_ledgerViewFrame;
+ QVBox* m_investmentViewFrame;
+ QVBox* m_reportsViewFrame;
+ QVBox* m_forecastViewFrame;
+
+ bool m_inConstructor;
+
+ bool m_fileOpen;
+
+ int m_fmode;
+
+ // bool m_bankRightClick;
+ // MyMoneyInstitution m_accountsInstitution;
+
+ // Keep a note of the file type
+ typedef enum _fileTypeE {
+ KmmBinary = 0, // native, binary
+ KmmXML, // native, XML
+ KmmDb, // SQL database
+ /* insert new native file types above this line */
+ MaxNativeFileType,
+ /* and non-native types below */
+ GncXML // Gnucash XML
+ }fileTypeE;
+ fileTypeE m_fileType;
+
+private:
+ void addTitleBar(QWidget* parent, const QString& title);
+
+ void ungetString(QIODevice *qfile, char * buf, int len);
+
+ /**
+ * This method creates the currency @p curr if it does not exist and
+ * @p create is @p true. If the currency already exists, it checks
+ * if the name is equal. If it is not, the name of the object in the
+ * engine is updated to the name passed with @p curr.
+ *
+ * @param curr MyMoneySecurity to be checked
+ * @param create If true and currency does not exist it will be created
+ If false currency will not be created even if it does not exist
+ */
+ void loadDefaultCurrency(const MyMoneySecurity& curr, const bool create);
+
+ /**
+ *
+ */
+ void loadAncientCurrency(const QString& id, const QString& name, const QString& sym, const QDate& date, const MyMoneyMoney& rate, const QString& newId, const int partsPerUnit = 100, const int smallestCashFraction = 100, const int smallestAccountFraction = 0);
+
+ /**
+ * if no base currency is defined, start the dialog and force it to be set
+ */
+ void selectBaseCurrency(void);
+
+ /**
+ * This method attaches an empty storage object to the MyMoneyFile
+ * object. It calls removeStorage() to remove a possibly attached
+ * storage object.
+ */
+ void newStorage(storageTypeE = Memory);
+
+ /**
+ * This method removes an attached storage from the MyMoneyFile
+ * object.
+ */
+ void removeStorage(void);
+
+ void viewAccountList(const QString& selectAccount); // Show the accounts view
+
+ static void progressCallback(int current, int total, const QString&);
+
+ /**
+ */
+ void fixFile_0(void);
+ void fixFile_1(void);
+ void fixFile_2(void);
+
+ /**
+ */
+ void fixLoanAccount_0(MyMoneyAccount acc);
+
+ /**
+ */
+ void fixTransactions_0(void);
+ void fixSchedule_0(MyMoneySchedule sched);
+ void fixDuplicateAccounts_0(MyMoneyTransaction& t);
+
+ void createSchedule(MyMoneySchedule s, MyMoneyAccount& a);
+
+ void checkAccountName(const MyMoneyAccount& acc, const QString& name) const;
+
+public:
+ /**
+ * The constructor for KMyMoneyView. Just creates all the tabs for the
+ * different aspects of the MyMoneyFile.
+ */
+ KMyMoneyView(QWidget *parent=0, const char *name=0);
+
+ /**
+ * Destructor
+ */
+ ~KMyMoneyView();
+
+ /**
+ * Makes sure that a MyMoneyFile is open and has been created succesfully.
+ *
+ * @return Whether the file is open and initialised
+ */
+ bool fileOpen(void);
+
+ /**
+ * Closes the open MyMoneyFile and frees all the allocated memory, I hope !
+ */
+ void closeFile(void);
+
+
+ /**
+ * Calls MyMoneyFile::readAllData which reads a MyMoneyFile into appropriate
+ * data structures in memory. The return result is examined to make sure no
+ * errors occured whilst parsing.
+ *
+ * @param url The URL to read from.
+ * If no protocol is specified, file:// is assumed.
+ *
+ * @return Whether the read was successfull.
+ */
+ bool readFile(const KURL& url);
+
+ /**
+ * Saves the data into permanent storage using the XML format.
+ *
+ * @param url The URL to save into.
+ * If no protocol is specified, file:// is assumed.
+ * @param keyList QString containing a comma separated list of keys
+ * to be used for encryption. If @p keyList is empty,
+ * the file will be saved unencrypted (the default)
+ *
+ * @retval false save operation failed
+ * @retval true save operation was successful
+ */
+ bool saveFile(const KURL& url, const QString& keyList = QString());
+ /**
+ * Saves the data into permanent storage on a new or empty SQL database.
+ *
+ * @param url The pseudo of tyhe database
+ *
+ * @retval false save operation failed
+ * @retval true save operation was successful
+ */
+ //const bool saveDatabase(const KURL& url); This no longer relevant
+ /**
+ * Saves the data into permanent storage on a new or empty SQL database.
+ *
+ * @param url The pseudo URL of the database
+ *
+ * @retval false save operation failed
+ * @retval true save operation was successful
+ */
+ bool saveAsDatabase(const KURL& url);
+
+ /**
+ * Call this to find out if the currently open file is native KMM
+ *
+ * @retval true file is native
+ * @retval false file is foreign
+ */
+ bool isNativeFile() { return (m_fileOpen && (m_fileType < MaxNativeFileType)); }
+
+ /**
+ * Call this to find out if the currently open file is a sql database
+ *
+ * @retval true file is database
+ * @retval false file is serial
+ */
+ bool isDatabase()
+ { return (m_fileOpen && ((m_fileType == KmmDb))); }
+
+ /**
+ * Call this to see if the MyMoneyFile contains any unsaved data.
+ *
+ * @retval true if any data has been modified but not saved
+ * @retval false otherwise
+ */
+ bool dirty(void);
+
+ /**
+ * Close the currently opened file and create an empty new file.
+ *
+ * @see MyMoneyFile
+ */
+ void newFile(void);
+
+ /**
+ * Moves the view up from transaction to Bank/Account view.
+ */
+ void viewUp(void);
+
+ /**
+ * This method allows to set the enable state of all views (except home view)
+ * The argument @p state controls the availability.
+ *
+ * @param state Controls whether views are disabled @p (0), enabled @p (1) or
+ * enabled/disabled according to an open file @p (-1). The latter
+ * is the default.
+ */
+ void enableViews(int state = -1);
+
+ KMyMoneyViewBase* addPage(const QString& title, const QString& icon = QString());
+
+ void addWidget(QWidget* w);
+
+ virtual bool showPage(int index);
+
+ /**
+ * check if the current view allows to create a transaction
+ *
+ * @param list list of selected transactions
+ * @param tooltip reference to string receiving the tooltip text
+ * which explains why the modify function is not available (in case
+ * of returning @c false)
+ *
+ * @retval true Yes, view allows to create a transaction (tooltip is not changed)
+ * @retval false No, view cannot to create a transaction (tooltip is updated with message)
+ */
+ bool canCreateTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ /**
+ * check if the current view allows to modify (edit/delete) the selected transactions
+ *
+ * @param list list of selected transactions
+ * @param tooltip reference to string receiving the tooltip text
+ * which explains why the modify function is not available (in case
+ * of returning @c false)
+ *
+ * @retval true Yes, view allows to edit/delete transactions (tooltip is not changed)
+ * @retval false No, view cannot edit/delete transactions (tooltip is updated with message)
+ */
+ bool canModifyTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ bool canDuplicateTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ /**
+ * check if the current view allows to edit the selected transactions
+ *
+ * @param list list of selected transactions
+ * @param tooltip reference to string receiving the tooltip text
+ * which explains why the edit function is not available (in case
+ * of returning @c false)
+ *
+ * @retval true Yes, view allows to enter/edit transactions
+ * @retval false No, view cannot enter/edit transactions
+ */
+ bool canEditTransactions(const KMyMoneyRegister::SelectedTransactions& list, QString& tooltip) const;
+
+ /**
+ * check if the current view allows to print something
+ *
+ * @retval true Yes, view allows to print
+ * @retval false No, view cannot print
+ */
+ bool canPrint(void);
+
+ TransactionEditor* startEdit(const KMyMoneyRegister::SelectedTransactions&);
+
+ bool createNewTransaction(void);
+
+ /**
+ * Used to start reconciliation of account @a account. It switches the
+ * ledger view into reconciliation mode and updates the view.
+ *
+ * @param account account which should be reconciled
+ * @param reconciliationDate the statement date
+ * @param endingBalance the ending balance entered for this account
+ *
+ * @retval true Reconciliation started
+ * @retval false Account cannot be reconciled
+ */
+ bool startReconciliation(const MyMoneyAccount& account, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance);
+
+ /**
+ * Used to finish reconciliation of account @a account. It switches the
+ * ledger view to normal mode and updates the view.
+ *
+ * @param account account which should be reconciled
+ */
+ void finishReconciliation(const MyMoneyAccount& account);
+
+ /**
+ * This method preloads all known currencies into the engine.
+ */
+ void loadDefaultCurrencies(void);
+
+ void loadAncientCurrencies(void);
+
+ void showTitleBar(bool show);
+
+public slots:
+ /**
+ * This slot writes information about the page passed as argument @p widget
+ * in the kmymoney2.rc file so that in can be selected automatically when
+ * the application is started again.
+ *
+ * @param widget pointer to page widget
+ */
+ void slotRememberPage(QWidget* widget);
+
+ /**
+ * Brings up a dialog to change the list(s) settings and saves them into the
+ * class KMyMoneySettings (a singleton).
+ *
+ * @see KListSettingsDlg
+ * Refreshs all views. Used e.g. after settings have been changed or
+ * data has been loaded from external sources (QIF import).
+ **/
+ void slotRefreshViews();
+
+ /**
+ * Called, whenever the ledger view should pop up and a specific
+ * transaction in an account should be shown. If @p transaction
+ * is empty, the last transaction should be selected
+ *
+ * @param acc The ID of the account to be shown
+ * @param transaction The ID of the transaction to be selected
+ */
+ void slotLedgerSelected(const QString& acc, const QString& transaction = QString());
+
+ /**
+ * Called, whenever the payees view should pop up and a specific
+ * transaction in an account should be shown.
+ *
+ * @param payeeId The ID of the payee to be shown
+ * @param accountId The ID of the account to be shown
+ * @param transactionId The ID of the transaction to be selected
+ */
+ void slotPayeeSelected(const QString& payeeId, const QString& accountId, const QString& transactionId);
+
+ /**
+ * Called, whenever the schedule view should pop up and a specific
+ * schedule should be shown.
+ *
+ * @param schedule The ID of the schedule to be shown
+ */
+ void slotScheduleSelected(const QString& schedule);
+
+ /**
+ * Called, whenever the report view should pop up and a specific
+ * report should be shown.
+ *
+ * @param reportid The ID of the report to be shown
+ */
+ void slotShowReport(const QString& reportid);
+
+ /**
+ * Same as the above, but the caller passes in an actual report
+ * definition to be shown.
+ *
+ * @param report The report to be shown
+ */
+ void slotShowReport(const MyMoneyReport& report);
+
+ /**
+ * This slot prints the current view.
+ */
+ void slotPrintView(void);
+
+ /**
+ * This slot switches the view to present the home page
+ */
+ void slotShowHomePage(void) { showPage(0); }
+
+protected slots:
+ /**
+ * Called when the user changes the detail
+ * setting of the transaction register
+ *
+ * @param detailed if true, the register is shown with all details
+ */
+ void slotShowTransactionDetail(bool detailed);
+
+ /**
+ * eventually replace this with KMyMoney2App::slotCurrencySetBase(void).
+ * it contains the same code
+ *
+ * @deprecated
+ */
+ void slotSetBaseCurrency(const MyMoneySecurity& baseCurrency);
+
+private:
+ /**
+ * This method is called from readFile to open a database file which
+ * is to be processed in 'proper' database mode, i.e. in-place updates
+ *
+ * @param dbaseURL pseudo-KURL representation of database
+ *
+ * @retval true Database opened successfully
+ * @retval false Could not open or read database
+ */
+ bool openDatabase (const KURL& dbaseURL);
+ /**
+ * This method is used after a file or database has been
+ * read into storage, and performs various initialization tasks
+ *
+ * @retval true all went okay
+ * @retval false an exception occurred during this process
+ */
+ bool initializeStorage();
+ /**
+ * This method is used by saveFile() to store the data
+ * either directly in the destination file if it is on
+ * the local file system or in a temporary file when
+ * the final destination is reached over a network
+ * protocol (e.g. FTP)
+ *
+ * @param qf pointer to QFile representing the opened file
+ * @param writer pointer to the formatter
+ * @param plaintext whether to override any compression & encryption settings
+ * @param keyList QString containing a comma separated list of keys to be used for encryption
+ * If @p keyList is empty, the file will be saved unencrypted
+ *
+ * @note This method will close the file when it is written.
+ */
+ void saveToLocalFile(QFile* qf, IMyMoneyStorageFormat* writer, bool plaintext=false, const QString& keyList = QString());
+
+ /**
+ * Internal method used by slotAccountNew() and slotAccountCategory().
+ */
+ void accountNew(const bool createCategory);
+
+signals:
+ /**
+ * This signal is emitted whenever a view is selected.
+ * The parameter @p view is identified as one of KMyMoneyView::viewID.
+ */
+ void viewActivated(int view);
+
+ void accountSelectedForContextMenu(const MyMoneyAccount& acc);
+
+ void viewStateChanged(bool enabled);
+ /**
+ * This signal is emitted to inform the kmmFile plugin when various file actions
+ * occur. The Action parameter distinguishes between them.
+ */
+ void kmmFilePlugin (unsigned int action);
+
+ /**
+ * Signal is emitted when reconciliation starts or ends. In case of end,
+ * @a account is MyMoneyAccount()
+ *
+ * @param account account for which reconciliation starts or MyMoneyAccount()
+ * if reconciliation ends.
+ * @param reconciliationDate the statement date
+ * @param endingBalance collected ending balance when reconciliation starts
+ * 0 otherwise
+ */
+ void reconciliationStarts(const MyMoneyAccount& account, const QDate& reconciliationDate, const MyMoneyMoney& endingBalance);
+
+};
+
+/**
+ * This class is an abstract base class that all specific views
+ * should be based on.
+ */
+class KMyMoneyViewBase : public QWidget
+{
+ Q_OBJECT
+public:
+ KMyMoneyViewBase(QWidget* parent, const char *name, const QString& title);
+ virtual ~KMyMoneyViewBase();
+
+ void setTitle(const QString& title);
+ QVBoxLayout* layout(void) const;
+ void addWidget(QWidget* w);
+
+ /**
+ * This method is used to edit the currently selected transactions
+ * The default implementation returns @p false which signals to the caller, that
+ * the view was not capable to edit the transactions.
+ *
+ * @retval false view was not capable to edit transactions
+ * @retval true view was capable to edit the transactions and did so
+ */
+ bool editTransactions(const QValueList<MyMoneyTransaction>& transactions) const { Q_UNUSED(transactions) return false; }
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+};
+#endif
diff --git a/kmymoney2/views/kpayeesview.cpp b/kmymoney2/views/kpayeesview.cpp
new file mode 100644
index 0000000..ad17ff4
--- /dev/null
+++ b/kmymoney2/views/kpayeesview.cpp
@@ -0,0 +1,1108 @@
+/***************************************************************************
+ kpayeesview.cpp
+ ---------------
+ begin : Thu Jan 24 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Andreas Nicolai <Andreas.Nicolai@gmx.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qmultilineedit.h>
+#include <qpixmap.h>
+#include <qtabwidget.h>
+#include <qcursor.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qpainter.h>
+#include <qheader.h>
+#include <qbuttongroup.h>
+#include <qsplitter.h>
+#include <qmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <keditlistbox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include "../widgets/klistviewsearchline.h"
+
+#include "kpayeesview.h"
+
+/* -------------------------------------------------------------------------------*/
+/* KTransactionPtrVector */
+/* -------------------------------------------------------------------------------*/
+
+int KTransactionPtrVector::compareItems(const QString& s1, const QString& s2) const
+{
+ if(s1 == s2)
+ return 0;
+ if(s1 < s2)
+ return -1;
+ return 1;
+}
+
+int KTransactionPtrVector::compareItems(KTransactionPtrVector::Item d1, KTransactionPtrVector::Item d2)
+{
+ int rc = 0;
+ MyMoneyTransaction* t1 = static_cast<MyMoneyTransaction*>(d1);
+ MyMoneyTransaction* t2 = static_cast<MyMoneyTransaction*>(d2);
+ MyMoneyMoney tmp;
+
+ try {
+ MyMoneySplit s1;
+ MyMoneySplit s2;
+ switch(m_idMode) {
+ case AccountMode:
+ s1 = t1->splitByAccount(m_id);
+ s2 = t2->splitByAccount(m_id);
+ break;
+ case PayeeMode:
+ s1 = t1->splitByPayee(m_id);
+ s2 = t2->splitByPayee(m_id);
+ break;
+ }
+ QString p1, p2;
+
+ switch(m_sortType) {
+ case SortValue:
+ rc = 1;
+ tmp = s2.value() - s1.value();
+ if(tmp.isZero()) {
+ // same value? Sort by date
+ rc = t2->postDate().daysTo(t1->postDate());
+ if(rc == 0) {
+ // same date? Sort by id
+ rc = compareItems(t1->id(), t2->id());
+ }
+ } else if(tmp.isNegative()) {
+ rc = -1;
+ }
+ break;
+
+ case SortEntryDate:
+ rc = t2->entryDate().daysTo(t1->entryDate());
+ if(rc == 0) {
+ // on same day, lower check numbers show up first
+ rc = compareItems(s1.number(), s2.number());
+ if(rc == 0) {
+ // same number (e.g. empty)? larger amounts show up first
+ rc = 1;
+ tmp = s2.value() - s1.value();
+ if(tmp.isZero()) {
+ // same value? Sort by id
+ rc = compareItems(t1->id(), t2->id());
+ } else if(tmp.isNegative()) {
+ rc = -1;
+ }
+ }
+ }
+ break;
+
+ case SortEntryOrder:
+ // sort by id
+ rc = compareItems(t1->id(), t2->id());
+ break;
+
+ case SortTypeNr:
+ rc = compareItems(s1.action(), s2.action());
+
+ if(rc == 0) {
+ // same action? Sort by nr
+ rc = compareItems(s1.number(), s2.number());
+ if(rc == 0) {
+ // same number? Sort by date
+ rc = t2->postDate().daysTo(t1->postDate());
+ if(rc == 0) {
+ // same date? Sort by value
+ rc = 1;
+ tmp = s2.value() - s1.value();
+ if(tmp.isZero()) {
+ // same value? sort by id
+ rc = compareItems(t1->id(), t2->id());
+ } else if(tmp.isNegative()) {
+ rc = -1;
+ }
+ }
+ }
+ }
+ break;
+
+ case SortReceiver:
+ if(!s2.payeeId().isEmpty()) {
+ p2 = MyMoneyFile::instance()->payee(s2.payeeId()).name();
+ }
+ if(!s1.payeeId().isEmpty()) {
+ p1 = MyMoneyFile::instance()->payee(s1.payeeId()).name();
+ }
+
+ rc = compareItems(p1, p2);
+
+ if(rc == 0) {
+ // same payee? Sort by date
+ rc = t2->postDate().daysTo(t1->postDate());
+ if(rc == 0) {
+ // same date? Sort by value
+ rc = 1;
+ tmp = s2.value() - s1.value();
+ if(tmp.isZero()) {
+ // same value? sort by id
+ rc = compareItems(t1->id(), t2->id());
+ } else if(tmp.isNegative()) {
+ rc = -1;
+ }
+ }
+ }
+ break;
+
+ case SortNr:
+ rc = compareItems(s1.number(), s2.number());
+ if(rc == 0) {
+ // same number? Sort by date
+ rc = t2->postDate().daysTo(t1->postDate());
+ if(rc == 0) {
+ // same date? Sort by value
+ rc = 1;
+ tmp = s2.value() - s1.value();
+ if(tmp.isZero()) {
+ // same value? sort by id
+ rc = compareItems(t1->id(), t2->id());
+ } else if(tmp.isNegative()) {
+ rc = -1;
+ }
+ }
+ }
+ break;
+
+ case SortPostDate:
+ // tricky fall through here!
+ default:
+ // sort by post date
+ rc = t2->postDate().daysTo(t1->postDate());
+ if(rc == 0) {
+ // on same day, lower check numbers show up first
+ rc = compareItems(s1.number(), s2.number());
+ if(rc == 0) {
+ // same number (e.g. empty)? larger amounts show up first
+ rc = 1;
+ tmp = s2.value() - s1.value();
+ if(tmp.isZero()) {
+ // same value? Sort by id
+ rc = compareItems(t1->id(), t2->id());
+ } else if(tmp.isNegative()) {
+ rc = -1;
+ }
+ }
+ }
+ break;
+ }
+ } catch (MyMoneyException *e) {
+ delete e;
+ }
+ return rc;
+}
+
+void KTransactionPtrVector::setSortType(const TransactionSortE type)
+{
+ m_sortType = type;
+ sort();
+}
+
+void KTransactionPtrVector::setAccountId(const QString& id)
+{
+ m_id = id;
+ m_idMode = AccountMode;
+}
+
+void KTransactionPtrVector::setPayeeId(const QString& id)
+{
+ m_id = id;
+ m_idMode = PayeeMode;
+}
+
+
+// *** KPayeeListItem Implementation ***
+
+KPayeeListItem::KPayeeListItem(KListView *parent, const MyMoneyPayee& payee) :
+ KListViewItem(parent),
+ m_payee(payee)
+{
+ setText(0, payee.name());
+ // allow in column rename
+ setRenameEnabled(0, true);
+}
+
+KPayeeListItem::~KPayeeListItem()
+{
+}
+
+void KPayeeListItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align)
+{
+ QColorGroup cg2(cg);
+
+ if(isAlternate())
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+
+ p->setFont(KMyMoneyGlobalSettings::listCellFont());
+
+ QListViewItem::paintCell(p, cg2, column, width, align);
+}
+
+KTransactionListItem::KTransactionListItem(KListView* view, KTransactionListItem* parent, const QString& accountId, const QString& transactionId) :
+ KListViewItem(view, parent)
+{
+ m_accountId = accountId;
+ m_transactionId = transactionId;
+}
+
+KTransactionListItem::~KTransactionListItem()
+{
+}
+
+void KTransactionListItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
+{
+ QColorGroup _cg = cg;
+ _cg.setColor(QColorGroup::Base, backgroundColor());
+ QListViewItem::paintCell(p, _cg, column, width, alignment);
+}
+
+const QColor KTransactionListItem::backgroundColor(void)
+{
+ return isAlternate() ? KMyMoneyGlobalSettings::listBGColor() : KMyMoneyGlobalSettings::listColor();
+}
+
+
+
+
+// *** KPayeesView Implementation ***
+
+KPayeesView::KPayeesView(QWidget *parent, const char *name ) :
+ KPayeesViewDecl(parent,name),
+ m_needReload(false),
+ m_needConnection(true),
+ m_updatesQueued(0),
+ m_inSelection(false)
+{
+ // create the searchline widget
+ // and insert it into the existing layout
+ m_searchWidget = new KListViewSearchLineWidget(m_payeesList, this);
+ m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
+ KPayeesViewDeclLayout->insertWidget(0, m_searchWidget);
+
+ m_splitter = new QSplitter(this);
+ m_payeesList->reparent(m_splitter, QPoint(0,0), true);
+ m_tabWidget->reparent(m_splitter, QPoint(0, 0), true);
+ m_splitter->setResizeMode(m_tabWidget, QSplitter::Stretch);
+ m_splitter->setOpaqueResize();
+ layout10->addWidget(m_splitter);
+
+ // use the size settings of the last run (if any)
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ QValueList<int> sizes = config->readIntListEntry("KPayeesViewSplitterSize");
+ if(sizes.size() == 2) {
+ if(!sizes[0] || !sizes[1]) {
+ sizes[0] = 1;
+ sizes[1] = 2;
+ }
+ m_splitter->setSizes(sizes);
+ }
+
+ m_transactionView->setSorting(-1);
+ m_transactionView->setColumnWidthMode(2, QListView::Manual);
+ m_transactionView->setColumnAlignment(3, Qt::AlignRight);
+ // never show horizontal scroll bars
+ m_transactionView->setHScrollBarMode(QScrollView::AlwaysOff);
+
+ m_payeesList->addColumn(i18n("Name"));
+
+ m_updateButton->setEnabled(false);
+ radioNoMatch->setChecked(true);
+
+ checkMatchIgnoreCase->setEnabled(false);
+
+ checkEnableDefaultAccount->setChecked(false);
+ labelDefaultAccount->setEnabled(false);
+ comboDefaultAccount->setEnabled(false);
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem updateButtenItem( i18n("Update"),
+ QIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Accepts the entered data and stores it"),
+ i18n("Use this to accept the modified data."));
+ m_updateButton->setGuiItem(updateButtenItem);
+
+ connect(m_payeesList, SIGNAL(selectionChanged()), this, SLOT(slotSelectPayee()));
+ connect(m_payeesList, SIGNAL(itemRenamed(QListViewItem*,int,const QString&)), this, SLOT(slotRenamePayee(QListViewItem*,int,const QString&)));
+
+ connect(addressEdit, SIGNAL(textChanged()), this, SLOT(slotPayeeDataChanged()));
+ connect(postcodeEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotPayeeDataChanged()));
+ connect(telephoneEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotPayeeDataChanged()));
+ connect(emailEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotPayeeDataChanged()));
+ connect(notesEdit, SIGNAL(textChanged()), this, SLOT(slotPayeeDataChanged()));
+ connect(matchKeyEditList, SIGNAL(changed()), this, SLOT(slotKeyListChanged()));
+
+ connect(radioNoMatch, SIGNAL(toggled(bool)), this, SLOT(slotPayeeDataChanged()));
+ connect(radioNameMatch, SIGNAL(toggled(bool)), this, SLOT(slotPayeeDataChanged()));
+ connect(radioKeyMatch, SIGNAL(toggled(bool)), this, SLOT(slotPayeeDataChanged()));
+ connect(checkMatchIgnoreCase, SIGNAL(toggled(bool)), this, SLOT(slotPayeeDataChanged()));
+
+ connect(checkEnableDefaultAccount, SIGNAL(toggled(bool)), this, SLOT(slotPayeeDataChanged()));
+ connect(comboDefaultAccount, SIGNAL(accountSelected(const QString&)), this, SLOT(slotPayeeDataChanged()));
+ connect(buttonSelectMyAccount, SIGNAL(clicked()), this, SLOT(slotChooseDefaultAccount()));
+
+ connect(m_updateButton, SIGNAL(clicked()), this, SLOT(slotUpdatePayee()));
+ connect(m_helpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
+
+ connect(m_payeesList, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), this, SLOT(slotOpenContextMenu(KListView*, QListViewItem*, const QPoint&)));
+
+// connect(m_payeesList, SIGNAL(rightButtonClicked(QListViewItem* , const QPoint&, int)),
+// this, SLOT(slotOpenContextMenu(QListViewItem*)));
+
+ connect(m_transactionView, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(slotTransactionDoubleClicked(QListViewItem*)));
+
+ connect(m_tabWidget, SIGNAL(currentChanged(QWidget*)), this, SLOT(rearrange(void)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadPayees()));
+}
+
+KPayeesView::~KPayeesView()
+{
+ // remember the splitter settings for startup
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("KPayeesViewSplitterSize", m_splitter->sizes());
+}
+
+void KPayeesView::slotQueueUpdate(void)
+{
+ m_updatesQueued++;
+ // The KListViewSearchLineWidget has an internal timer for update purposes
+ // of 200 ms, so we should be safe with 250 ms here
+ QTimer::singleShot(250, this, SLOT(slotActivateUpdate()));
+}
+
+void KPayeesView::slotActivateUpdate(void)
+{
+ --m_updatesQueued;
+ if(m_updatesQueued == 0)
+ slotSelectPayee();
+}
+
+void KPayeesView::slotChooseDefaultAccount(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QMap<QString,int> account_count;
+
+ for (int i = 0; i < m_transactionPtrVector.size(); ++i) {
+ KMyMoneyTransaction* t = m_transactionPtrVector[i];
+ MyMoneySplit s = t->splitById(t->splitId());
+ const MyMoneyAccount& acc = file->account(s.accountId());
+
+ QString txt;
+ if (s.action() != MyMoneySplit::ActionAmortization
+ && acc.accountType() != MyMoneyAccount::AssetLoan
+ && !file->isTransfer(*t)
+ && t->splitCount() == 2) {
+ MyMoneySplit s0 = t->splitByAccount(s.accountId(), false);
+ if (account_count.contains(s0.accountId())) {
+ account_count[s0.accountId()]++;
+ }
+ else {
+ account_count[s0.accountId()] = 1;
+ }
+ }
+ }
+
+ QMapIterator<QString,int> most_frequent, iter;
+ most_frequent = account_count.end();
+ for (iter = account_count.begin(); iter != account_count.end(); iter++) {
+ if (iter.data() > most_frequent.data()) {
+ most_frequent = iter;
+ }
+ }
+
+ if (most_frequent != account_count.end()) {
+ checkEnableDefaultAccount->setChecked(true);
+ comboDefaultAccount->setSelected(most_frequent.key());
+ }
+}
+
+void KPayeesView::slotStartRename(void)
+{
+ QListViewItemIterator it_l(m_payeesList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ if((it_v = it_l.current()) != 0) {
+ it_v->startRename(0);
+ }
+}
+
+// This variant is only called when a single payee is selected and renamed.
+void KPayeesView::slotRenamePayee(QListViewItem* p , int /* col */, const QString& txt)
+{
+ //kdDebug() << "[KPayeesView::slotRenamePayee]" << endl;
+ // create a copy of the new name without appended whitespaces
+ QString new_name = txt.stripWhiteSpace();
+ if (m_payee.name() != new_name) {
+ MyMoneyFileTransaction ft;
+ try {
+ // check if we already have a payee with the new name
+ try {
+ // this function call will throw an exception, if the payee
+ // hasn't been found.
+ MyMoneyFile::instance()->payeeByName(new_name);
+ // the name already exists, ask the user whether he's sure to keep the name
+ if (KMessageBox::questionYesNo(this,
+ i18n("A payee with the name '%1' already exists. It is not advisable to have "
+ "multiple payees with the same identification name. Are you sure you would like "
+ "to rename the payee?").arg(new_name)) != KMessageBox::Yes)
+ {
+ p->setText(0,m_payee.name());
+ return;
+ }
+ } catch(MyMoneyException *e) {
+ // all ok, the name is unique
+ delete e;
+ }
+
+ m_payee.setName(new_name);
+ m_newName = new_name;
+ MyMoneyFile::instance()->modifyPayee(m_payee);
+
+ // the above call to modifyPayee will reload the view so
+ // all references and pointers to the view have to be
+ // re-established.
+
+ // make sure, that the record is visible even if it moved
+ // out of sight due to the rename operation
+ ensurePayeeVisible(m_payee.id());
+
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to modify payee"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+ }
+ else {
+ p->setText(0, new_name);
+ }
+}
+
+void KPayeesView::ensurePayeeVisible(const QString& id)
+{
+ for (QListViewItem * item = m_payeesList->firstChild(); item; item = item->itemBelow()) {
+ KPayeeListItem* p = dynamic_cast<KPayeeListItem*>(item);
+ if(p && p->payee().id() == id) {
+ if(p->itemAbove())
+ m_payeesList->ensureItemVisible(p->itemAbove());
+ if(p->itemBelow())
+ m_payeesList->ensureItemVisible(p->itemBelow());
+
+ m_payeesList->setCurrentItem(p); // active item and deselect all others
+ m_payeesList->setSelected(p, true); // and select it
+ m_payeesList->ensureItemVisible(p);
+ break;
+ }
+ }
+}
+
+void KPayeesView::selectedPayees(QValueList<MyMoneyPayee>& payeesList) const
+{
+ QListViewItemIterator it_l(m_payeesList, QListViewItemIterator::Selected | QListViewItemIterator::Visible);
+ QListViewItem* it_v;
+ while((it_v = it_l.current()) != 0) {
+ KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(it_v);
+ if(item)
+ payeesList << item->payee();
+ ++it_l;
+ }
+}
+
+void KPayeesView::slotSelectPayee(void)
+{
+ // check if the content of a currently selected payee was modified
+ // and ask to store the data
+ if (m_updateButton->isEnabled()) {
+ if (KMessageBox::questionYesNo(this, QString("<qt>%1</qt>").arg(
+ i18n("Do you want to save the changes for <b>%1</b>?").arg(m_newName)),
+ i18n("Save changes")) == KMessageBox::Yes) {
+ m_inSelection = true;
+ slotUpdatePayee();
+ m_inSelection = false;
+ }
+ }
+
+ // loop over all payees and count the number of payees, also
+ // optain last selected payee
+ QValueList<MyMoneyPayee> payeesList;
+ selectedPayees(payeesList);
+
+ emit selectObjects(payeesList);
+
+ if (payeesList.count() == 0) {
+ m_tabWidget->setEnabled(false); // disable tab widget
+ clearItemData();
+ m_payee = MyMoneyPayee();
+ return; // make sure we don't access an undefined payee
+ }
+
+ // if we have multiple payees selected, clear and disable the payee informations
+ if (payeesList.count() > 1) {
+ m_tabWidget->setEnabled(false); // disable tab widget
+ clearItemData();
+ // disable renaming in all listviewitem
+ for (QListViewItem * i = m_payeesList->firstChild(); i; i = i->itemBelow())
+ i->setRenameEnabled(0, false);
+ return;
+ }
+ // otherwise we have just one selected, enable payee information widget
+ m_tabWidget->setEnabled(true);
+ // enable renaming in all listviewitem
+ for (QListViewItem * i = m_payeesList->firstChild(); i; i = i->itemBelow())
+ i->setRenameEnabled(0, true);
+
+ // as of now we are updating only the last selected payee, and until
+ // selection mode of the QListView has been changed to Extended, this
+ // will also be the only selection and behave exactly as before - Andreas
+ try {
+ m_payee = payeesList[0];
+ m_newName = m_payee.name();
+
+ addressEdit->setEnabled(true);
+ addressEdit->setText(m_payee.address());
+ postcodeEdit->setEnabled(true);
+ postcodeEdit->setText(m_payee.postcode());
+ telephoneEdit->setEnabled(true);
+ telephoneEdit->setText(m_payee.telephone());
+ emailEdit->setEnabled(true);
+ emailEdit->setText(m_payee.email());
+ notesEdit->setText(m_payee.notes());
+
+ QStringList keys;
+ bool ignorecase = false;
+ MyMoneyPayee::payeeMatchType type = m_payee.matchData(ignorecase, keys);
+
+ m_matchType->setButton(static_cast<int>(type));
+ matchKeyEditList->clear();
+ matchKeyEditList->insertStringList(keys);
+ checkMatchIgnoreCase->setChecked(ignorecase);
+
+ checkEnableDefaultAccount->setChecked(m_payee.defaultAccountEnabled());
+ comboDefaultAccount->setSelected(m_payee.defaultAccountId());
+
+ slotPayeeDataChanged();
+
+ showTransactions();
+
+ } catch(MyMoneyException *e) {
+ qDebug("exception during display of payee: %s at %s:%ld", e->what().latin1(), e->file().latin1(), e->line());
+ m_transactionView->clear();
+ m_payee = MyMoneyPayee();
+ delete e;
+ }
+}
+
+void KPayeesView::clearItemData(void)
+{
+ addressEdit->setText(QString());
+ postcodeEdit->setText(QString());
+ telephoneEdit->setText(QString());
+ emailEdit->setText(QString());
+ notesEdit->setText(QString());
+ showTransactions();
+}
+
+void KPayeesView::showTransactions(void)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyMoney balance(0);
+ unsigned int i;
+
+ // clear the current transaction listview
+ m_transactionView->clear();
+
+ if(m_payee.id().isEmpty() || !m_tabWidget->isEnabled()) {
+ m_balanceLabel->setText(i18n("Balance: %1").arg(balance.formatMoney(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction())));
+ return;
+ }
+
+ // setup the list and the pointer vector
+ MyMoneyTransactionFilter filter;
+ filter.addPayee(m_payee.id());
+ filter.setDateFilter(KMyMoneyGlobalSettings::startDate().date(), QDate());
+
+ QValueList<MyMoneyTransaction> list = file->transactionList(filter);
+ m_transactionList.clear();
+
+ m_transactionPtrVector.clear();
+ m_transactionPtrVector.resize(list.size());
+ m_transactionPtrVector.setPayeeId(m_payee.id());
+ m_transactionPtrVector.setSortType(KTransactionPtrVector::SortPostDate);
+
+ QValueList<MyMoneyTransaction>::ConstIterator it_t;
+ QString lastId;
+ int ofs = 0;
+
+ for(i = 0, it_t = list.begin(); it_t != list.end(); ++it_t) {
+ KMyMoneyTransaction k(*it_t);
+
+ filter.match(*it_t);
+ if(lastId != (*it_t).id()) {
+ ofs = 0;
+ lastId = (*it_t).id();
+ } else
+ ofs++;
+
+ k.setSplitId(filter.matchingSplits()[ofs].id());
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(filter.matchingSplits()[ofs].accountId());
+ if(acc.accountGroup() == MyMoneyAccount::Asset
+ || acc.accountGroup() == MyMoneyAccount::Liability) {
+ QValueList<KMyMoneyTransaction>::ConstIterator it_k;
+ it_k = m_transactionList.append(k);
+ balance += k.splitById(k.splitId()).value();
+ m_transactionPtrVector.insert(i, &(*it_k));
+ ++i;
+ }
+ }
+ m_transactionPtrVector.resize(i);
+
+ // sort the transactions
+ m_transactionPtrVector.sort();
+
+ // and fill the m_transactionView
+ KTransactionListItem *item = 0;
+
+ for(i = 0; i < m_transactionPtrVector.size(); ++i) {
+ KMyMoneyTransaction* t = m_transactionPtrVector[i];
+ MyMoneySplit s = t->splitById(t->splitId());
+ const MyMoneyAccount& acc = file->account(s.accountId());
+
+ item = new KTransactionListItem(m_transactionView, item, s.accountId(), t->id());
+ item->setText(0, s.number());
+ item->setText(1, KGlobal::locale()->formatDate(t->postDate(), true));
+
+ QString txt;
+ if(s.action() == MyMoneySplit::ActionAmortization) {
+ if(acc.accountType() == MyMoneyAccount::Loan) {
+ if(s.value().isPositive()) {
+ txt = i18n("Amortization of %1").arg(acc.name());
+ } else {
+ txt = i18n("Payment to %1").arg(acc.name());
+ }
+ } else if(acc.accountType() == MyMoneyAccount::AssetLoan) {
+ if(s.value().isNegative()) {
+ txt = i18n("Amortization of %1").arg(acc.name());
+ } else {
+ txt = i18n("Payment to %1").arg(acc.name());
+ }
+ } else {
+ txt = i18n("Loan payment from %1").arg(acc.name());
+ }
+ } else if (file->isTransfer(*t)) {
+ if(!s.value().isNegative()) {
+ txt = i18n("Transfer to %1").arg(acc.name());
+ } else {
+ txt = i18n("Transfer from %1").arg(acc.name());
+ }
+ } else if(t->splitCount() > 2) {
+ txt = i18n("Split transaction (category replacement)", "Split transaction");
+ } else if(t->splitCount() == 2) {
+ MyMoneySplit s0 = t->splitByAccount(s.accountId(), false);
+ txt = MyMoneyFile::instance()->accountToCategory(s0.accountId());
+ }
+ item->setText(2, txt);
+ item->setText(3, s.value().formatMoney(acc.fraction()));
+ }
+ m_balanceLabel->setText(i18n("Balance: %1").arg(balance.formatMoney(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction())));
+
+ // Trick: it seems, that the initial sizing of the view does
+ // not work correctly. At least, the columns do not get displayed
+ // correct. Reason: the return value of m_transactionView->visibleWidth()
+ // is incorrect. If the widget is visible, resizing works correctly.
+ // So, we let the dialog show up and resize it then. It's not really
+ // clean, but the only way I got the damned thing working.
+ QTimer::singleShot(50, this, SLOT(rearrange()));
+}
+
+void KPayeesView::slotKeyListChanged(void)
+{
+ bool rc = false;
+ bool ignorecase = false;
+ QStringList keys;
+ // J.Rodehueser: delete unused variable 'type'
+ // orig: MyMoneyPayee::payeeMatchType type = m_payee.matchData(ignorecase, keys);
+ m_payee.matchData(ignorecase, keys);
+ if(m_matchType->selectedId() == MyMoneyPayee::matchKey) {
+ rc |= (keys != matchKeyEditList->items());
+ }
+ m_updateButton->setEnabled(rc);
+}
+
+void KPayeesView::slotPayeeDataChanged(void)
+{
+ kdDebug(2) << "KPayeesView::slotPayeeDataChanged(void)" << endl;
+
+ bool rc = false;
+
+ if(m_tabWidget->isEnabled()) {
+ rc |= ((m_payee.email().isEmpty() != emailEdit->text().isEmpty())
+ || (!emailEdit->text().isEmpty() && m_payee.email() != emailEdit->text()));
+ rc |= ((m_payee.address().isEmpty() != addressEdit->text().isEmpty())
+ || (!addressEdit->text().isEmpty() && m_payee.address() != addressEdit->text()));
+ rc |= ((m_payee.postcode().isEmpty() != postcodeEdit->text().isEmpty())
+ || (!postcodeEdit->text().isEmpty() && m_payee.postcode() != postcodeEdit->text()));
+ rc |= ((m_payee.telephone().isEmpty() != telephoneEdit->text().isEmpty())
+ || (!telephoneEdit->text().isEmpty() && m_payee.telephone() != telephoneEdit->text()));
+ rc |= ((m_payee.name().isEmpty() != m_newName.isEmpty())
+ || (!m_newName.isEmpty() && m_payee.name() != m_newName));
+ rc |= ((m_payee.notes().isEmpty() != notesEdit->text().isEmpty())
+ || (!notesEdit->text().isEmpty() && m_payee.notes() != notesEdit->text()));
+
+ bool ignorecase = false;
+ QStringList keys;
+
+ MyMoneyPayee::payeeMatchType type = m_payee.matchData(ignorecase, keys);
+ rc |= (static_cast<int>(type) != m_matchType->selectedId());
+
+ checkMatchIgnoreCase->setEnabled(false);
+ matchKeyEditList->setEnabled(false);
+
+ if(m_matchType->selectedId() != MyMoneyPayee::matchDisabled) {
+ checkMatchIgnoreCase->setEnabled(true);
+ // if we turn matching on, we default to 'ignore case'
+ // TODO maybe make the default a user option
+ if(type == MyMoneyPayee::matchDisabled && m_matchType->selectedId() != MyMoneyPayee::matchDisabled)
+ checkMatchIgnoreCase->setChecked(true);
+ rc |= (ignorecase != checkMatchIgnoreCase->isChecked());
+ if(m_matchType->selectedId() == MyMoneyPayee::matchKey) {
+ matchKeyEditList->setEnabled(true);
+ rc |= (keys != matchKeyEditList->items());
+ }
+ }
+
+ rc |= (checkEnableDefaultAccount->isChecked() != m_payee.defaultAccountEnabled());
+ if (checkEnableDefaultAccount->isChecked()) {
+ comboDefaultAccount->setEnabled(true);
+ labelDefaultAccount->setEnabled(true);
+ // this is only going to understand the first in the list of selected accounts
+ if (comboDefaultAccount->selectedAccounts().empty()) {
+ rc |= !m_payee.defaultAccountId().isEmpty();
+ }
+ else {
+ QString temp = comboDefaultAccount->selectedAccounts().front();
+ rc |= ( temp.isEmpty() != m_payee.defaultAccountId().isEmpty())
+ || (!m_payee.defaultAccountId().isEmpty() && temp != m_payee.defaultAccountId());
+ }
+ }
+ else {
+ comboDefaultAccount->setEnabled(false);
+ labelDefaultAccount->setEnabled(false);
+ }
+ }
+ m_updateButton->setEnabled(rc);
+}
+
+void KPayeesView::slotUpdatePayee(void)
+{
+ if(m_updateButton->isEnabled()) {
+ MyMoneyFileTransaction ft;
+ m_updateButton->setEnabled(false);
+ try {
+ m_payee.setName(m_newName);
+ m_payee.setAddress(addressEdit->text());
+ m_payee.setPostcode(postcodeEdit->text());
+ m_payee.setTelephone(telephoneEdit->text());
+ m_payee.setEmail(emailEdit->text());
+ m_payee.setNotes(notesEdit->text());
+ m_payee.setMatchData(static_cast<MyMoneyPayee::payeeMatchType>(m_matchType->selectedId()), checkMatchIgnoreCase->isChecked(), matchKeyEditList->items());
+ m_payee.setDefaultAccountId();
+
+ if (checkEnableDefaultAccount->isChecked()) {
+ QString temp;
+ if (!comboDefaultAccount->selectedAccounts().empty()) {
+ temp = comboDefaultAccount->selectedAccounts().front();
+ m_payee.setDefaultAccountId(temp);
+ }
+ }
+
+ MyMoneyFile::instance()->modifyPayee(m_payee);
+ ft.commit();
+
+ } catch(MyMoneyException *e) {
+ KMessageBox::detailedSorry(0, i18n("Unable to modify payee"),
+ (e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
+ delete e;
+ }
+ }
+}
+
+void KPayeesView::readConfig(void)
+{
+ m_transactionView->setFont(KMyMoneyGlobalSettings::listCellFont());
+
+ QFontMetrics fm( KMyMoneyGlobalSettings::listHeaderFont() );
+ int height = fm.lineSpacing()+6;
+
+ m_transactionView->header()->setMinimumHeight(height);
+ m_transactionView->header()->setMaximumHeight(height);
+ m_transactionView->header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
+
+ m_payeesList->setDefaultRenameAction(
+ KMyMoneyGlobalSettings::focusChangeIsEnter() ? QListView::Accept : QListView::Reject);
+
+ //initialize the account list?
+ comboDefaultAccount->loadList((KMyMoneyUtils::categoryTypeE)(KMyMoneyUtils::asset | KMyMoneyUtils::liability | MyMoneyAccount::Income | MyMoneyAccount::Expense));
+
+}
+
+void KPayeesView::show(void)
+{
+ // since we could not construct the connection in our own ctor,
+ // we set it up now. The widgets of the KListViewSearchLineWidget must exist by now.
+ // If you want to learn about the details, see the source of KListViewSearchLineWidget's
+ // constructor
+ if(m_needConnection) {
+ connect(m_searchWidget->searchLine(), SIGNAL(textChanged(const QString&)), this, SLOT(slotQueueUpdate(void)));
+ m_needConnection = false;
+ }
+
+ if(m_needReload) {
+ loadPayees();
+ m_needReload = false;
+ }
+
+ // fixup the layout
+ QTimer::singleShot(0, this, SLOT(rearrange()));
+
+ // don't forget base class implementation
+ KPayeesViewDecl::show();
+
+ QValueList<MyMoneyPayee> list;
+ selectedPayees(list);
+ emit selectObjects(list);
+}
+
+void KPayeesView::slotLoadPayees(void)
+{
+ if(isVisible()) {
+ if(m_inSelection)
+ QTimer::singleShot(0, this, SLOT(slotLoadPayees()));
+ else
+ loadPayees();
+ } else {
+ m_needReload = true;
+ }
+}
+
+void KPayeesView::loadPayees(void)
+{
+ if(m_inSelection)
+ return;
+
+ QMap<QString, bool> isSelected;
+ QString id;
+
+ ::timetrace("Start KPayeesView::loadPayees");
+ readConfig();
+
+ // remember which items are selected in the list
+ QListViewItemIterator it_l(m_payeesList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ while((it_v = it_l.current()) != 0) {
+ KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(it_v);
+ if(item)
+ isSelected[item->payee().id()] = true;
+ ++it_l;
+ }
+
+ // keep current selected item
+ KPayeeListItem *currentItem = static_cast<KPayeeListItem *>(m_payeesList->currentItem());
+ if(currentItem)
+ id = currentItem->payee().id();
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_payeesList->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_payeesList->setUpdatesEnabled(false);
+
+ // clear the list
+ m_payeesList->clear();
+ m_transactionView->clear();
+ currentItem = 0;
+
+ QValueList<MyMoneyPayee>list = MyMoneyFile::instance()->payeeList();
+ QValueList<MyMoneyPayee>::ConstIterator it;
+
+ for (it = list.begin(); it != list.end(); ++it) {
+ KPayeeListItem* item = new KPayeeListItem(m_payeesList, *it);
+ if(item->payee().id() == id)
+ currentItem = item;
+ if(isSelected[item->payee().id()])
+ item->setSelected(true);
+ }
+
+ if (currentItem) {
+ m_payeesList->setCurrentItem(currentItem);
+ }
+
+ // reposition viewport
+ m_payeesList->setContentsPos(startPoint.x(), startPoint.y());
+
+ m_searchWidget->searchLine()->updateSearch(QString::null);
+
+ // turn updates back on
+ m_payeesList->setUpdatesEnabled(true);
+ m_payeesList->repaintContents();
+
+ slotSelectPayee();
+
+ ::timetrace("End KPayeesView::loadPayees");
+}
+
+void KPayeesView::rearrange(void)
+{
+ resizeEvent(0);
+}
+
+void KPayeesView::resizeEvent(QResizeEvent* ev)
+{
+ // resize the register
+ int w = m_transactionView->visibleWidth();
+ w -= m_transactionView->columnWidth(0);
+ w -= m_transactionView->columnWidth(1);
+ w -= m_transactionView->columnWidth(3);
+ m_transactionView->setColumnWidth(2, w);
+ m_transactionView->resizeContents(
+ m_transactionView->visibleWidth(),
+ m_transactionView->contentsHeight());
+
+ m_payeesList->setColumnWidth(0, m_payeesList->visibleWidth());
+ KPayeesViewDecl::resizeEvent(ev);
+}
+
+void KPayeesView::slotTransactionDoubleClicked(QListViewItem* i)
+{
+ KTransactionListItem* item = static_cast<KTransactionListItem *>(i);
+ if (item)
+ emit transactionSelected(item->accountId(), item->transactionId());
+}
+
+void KPayeesView::slotSelectPayeeAndTransaction(const QString& payeeId, const QString& accountId, const QString& transactionId)
+{
+ if(!isVisible())
+ return;
+
+ try {
+ // clear filter
+ m_searchWidget->searchLine()->clear();
+ m_searchWidget->searchLine()->updateSearch();
+
+ // deselect all other selected items
+ QListViewItemIterator it_l(m_payeesList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ while((it_v = it_l.current()) != 0) {
+ KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(it_v);
+ if(item)
+ item->setSelected(false);
+ ++it_l;
+ }
+
+ // find the payee in the list
+ QListViewItem* it;
+ for(it = m_payeesList->firstChild(); it; it = it->itemBelow()) {
+ KPayeeListItem* item = dynamic_cast<KPayeeListItem *>(it);
+ if(item && item->payee().id() == payeeId) {
+ if(it->itemAbove())
+ m_payeesList->ensureItemVisible(it->itemAbove());
+ if(it->itemBelow())
+ m_payeesList->ensureItemVisible(it->itemBelow());
+
+ m_payeesList->setCurrentItem(it); // active item and deselect all others
+ m_payeesList->setSelected(it,true); // and select it
+ m_payeesList->ensureItemVisible(it);
+
+ KTransactionListItem* item = dynamic_cast<KTransactionListItem*> (m_transactionView->firstChild());
+ while(item != 0) {
+ if(item->accountId() == accountId && item->transactionId() == transactionId)
+ break;
+ item = dynamic_cast<KTransactionListItem*> (item->nextSibling());
+ }
+ if(!item) {
+ item = dynamic_cast<KTransactionListItem*> (m_transactionView->firstChild());
+ }
+ if(item) {
+ m_transactionView->setSelected(item, true);
+ m_transactionView->ensureItemVisible(item);
+ }
+ // quit out of for() loop
+ break;
+ }
+ }
+
+ } catch(MyMoneyException *e) {
+ qWarning("Unexpected exception in KPayeesView::slotSelectPayeeAndTransaction");
+ delete e;
+ }
+}
+
+void KPayeesView::slotOpenContextMenu(KListView* lv, QListViewItem* i, const QPoint& p)
+{
+ Q_UNUSED(p);
+ if(lv == m_payeesList) {
+ KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(i);
+ if(item) {
+ emit openContextMenu(item->payee());
+ }
+ }
+}
+
+void KPayeesView::slotHelp(void)
+{
+ kapp->invokeHelp("details.payees.personalinformation");
+}
+
+#include "kpayeesview.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/views/kpayeesview.h b/kmymoney2/views/kpayeesview.h
new file mode 100644
index 0000000..92f98fd
--- /dev/null
+++ b/kmymoney2/views/kpayeesview.h
@@ -0,0 +1,325 @@
+/***************************************************************************
+ kpayeesview.h
+ -------------
+ begin : Thu Jan 24 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ 2005 by Andrea Nicolai
+ 2006 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Andreas Nicolai <Andreas.Nicolai@gmx.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KPAYEESVIEW_H
+#define KPAYEESVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+class QSplitter;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+#include <kpopupmenu.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kpayeesviewdecl.h"
+#include "kmymoneytransaction.h"
+#include <kmymoney/mymoneypayee.h>
+
+class KListViewSearchLineWidget;
+
+/**
+ * @author Michael Edwardes, Thomas Baumgart
+ */
+
+/**
+ * This class is used to store a sorted vector of pointers to
+ * the transactions that are visible in a ledger view. When the
+ * vector is created, the sort method is set to SortPostDate.
+ * The sort type can be changed using the method setSortType().
+ */
+class KTransactionPtrVector : public QPtrVector<KMyMoneyTransaction> {
+public:
+ /**
+ * This enumerator defines the possible sort methods.
+ * Possible values are:
+ *
+ */
+ enum TransactionSortE {
+ SortEntryDate = 0, /**< Sort the vector so that the transactions appear sorted
+ * according to their entry date
+ */
+ SortPostDate, /**< Sort the vector so that the transactions appear sorted
+ * according to their post date
+ */
+ SortTypeNr, /**< Sort the vector so that the transactions appear sorted
+ * according to their action and nr
+ */
+ SortReceiver, /**< Sort the vector so that the transactions appear sorted
+ * according to their receiver
+ */
+ SortValue, /**< Sort the vector so that the transactions appear sorted
+ * according to their value
+ */
+ SortNr, /**< Sort the vector so that the transactions appear sorted
+ * according to nr field contents
+ */
+ SortEntryOrder /**< Sort the vector so that the transactions appear sorted
+ * according to order of entry
+ */
+ };
+
+ KTransactionPtrVector() { m_sortType = SortPostDate; };
+ ~KTransactionPtrVector() {}
+
+ /**
+ * This method is used to set a different sort type.
+ * The vector is resorted. See KTransactionPtrVector::TransactionSortE
+ * for possible values.
+ */
+ void setSortType(const TransactionSortE type);
+
+ /**
+ * This method returns the current sort type.
+ *
+ * @return transactionSortE value of sort order. See
+ * KTransactionPtrVector::TransactionSortE for possible values.
+ */
+ TransactionSortE sortType(void) const { return m_sortType; };
+
+ /**
+ * This method is used to set the account id to have a chance to
+ * get information about the split referencing the current account
+ * during the sort phase.
+ */
+ void setAccountId(const QString& id);
+
+ /**
+ * This method is used to set the payee id to have a chance to
+ * get information about the split referencing the current payee
+ * during the sort phase.
+ */
+ void setPayeeId(const QString& id);
+
+protected:
+ int compareItems(KTransactionPtrVector::Item d1, KTransactionPtrVector::Item d2);
+
+private:
+ int compareItems(const QString& s1, const QString& s2) const;
+
+private:
+ enum {
+ AccountMode = 0,
+ PayeeMode
+ };
+ short m_idMode;
+ QString m_id;
+ TransactionSortE m_sortType;
+};
+
+
+
+/**
+ * This class represents an item in the payees list view.
+ */
+class KPayeeListItem : public KListViewItem
+{
+public:
+ /**
+ * Constructor to be used to construct a payee entry object.
+ *
+ * @param parent pointer to the KListView object this entry should be
+ * added to.
+ * @param payee const reference to MyMoneyPayee for which
+ * the KListView entry is constructed
+ */
+ KPayeeListItem(KListView *parent, const MyMoneyPayee& payee);
+ ~KPayeeListItem();
+
+ /**
+ * This method is re-implemented from QListViewItem::paintCell().
+ * Besides the standard implementation, the QPainter is set
+ * according to the applications settings.
+ */
+ void paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align);
+
+ const MyMoneyPayee& payee(void) const { return m_payee; };
+
+private:
+ MyMoneyPayee m_payee;
+};
+
+/**
+ * This class represents an item in the transaction list view. It is used
+ * by the KPayeesView to select between transactions.
+ */
+class KTransactionListItem : public KListViewItem
+{
+public:
+ KTransactionListItem(KListView* view, KTransactionListItem* parent, const QString& accountId, const QString& transaction);
+ ~KTransactionListItem();
+
+ const QString& transactionId(void) const { return m_transactionId; };
+
+ const QString& accountId(void) const { return m_accountId; };
+
+ /**
+ * use my own paint method
+ */
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment);
+
+ /**
+ * use my own backgroundColor method
+ */
+ const QColor backgroundColor();
+
+private:
+ QString m_transactionId;
+ QString m_accountId;
+};
+
+class KPayeesView : public KPayeesViewDecl
+{
+ Q_OBJECT
+
+public:
+ KPayeesView(QWidget *parent=0, const char *name=0);
+ ~KPayeesView();
+ void show(void);
+
+public slots:
+ void slotSelectPayeeAndTransaction(const QString& payeeId, const QString& accountId = QString(), const QString& transactionId = QString());
+ void slotLoadPayees(void);
+ void slotStartRename(void);
+ void slotHelp(void);
+
+protected:
+ void resizeEvent(QResizeEvent*);
+ void loadPayees(void);
+ void selectedPayees(QValueList<MyMoneyPayee>& payeesList) const;
+ void ensurePayeeVisible(const QString& id);
+ void clearItemData(void);
+
+protected slots:
+ /**
+ * This method loads the m_transactionList, clears
+ * the m_TransactionPtrVector and rebuilds and sorts
+ * it according to the current settings. Then it
+ * loads the m_transactionView with the transaction data.
+ */
+ void showTransactions(void);
+
+ /**
+ * This slot is called whenever the selection in m_payeesList
+ * has been changed.
+ */
+ void slotSelectPayee(void);
+
+ /**
+ * This slot marks the current selected payee as modified (dirty).
+ */
+ void slotPayeeDataChanged(void);
+ void slotKeyListChanged(void);
+
+ /**
+ * This slot is called when the name of a payee is changed inside
+ * the payee list view and only a single payee is selected.
+ */
+ void slotRenamePayee(QListViewItem *p, int col, const QString& txt);
+
+ /**
+ * Updates the payee data in m_payee from the information in the
+ * payee information widget.
+ */
+ void slotUpdatePayee(void);
+
+ void slotTransactionDoubleClicked(QListViewItem *);
+
+private slots:
+ void rearrange(void);
+
+ /**
+ * This slot receives the signal from the listview control that an item was right-clicked,
+ * If @p item points to a real payee item, emits openContextMenu().
+ *
+ * @param lv pointer to the listview sending the signal
+ * @param item the item on which the cursor resides
+ * @param p position of the pointer device
+ */
+ void slotOpenContextMenu(KListView* lv, QListViewItem* item, const QPoint& p);
+
+ void slotQueueUpdate(void);
+
+ void slotActivateUpdate(void);
+
+ void slotChooseDefaultAccount(void);
+
+private:
+ void readConfig(void);
+
+signals:
+ void transactionSelected(const QString& accountId, const QString& transactionId);
+ void openContextMenu(const MyMoneyObject& obj);
+ void selectObjects(const QValueList<MyMoneyPayee>& payees);
+
+private:
+ MyMoneyPayee m_payee;
+ QString m_newName;
+
+ QSplitter* m_splitter;
+
+ /**
+ * This member holds a list of all transactions
+ */
+ QValueList<KMyMoneyTransaction> m_transactionList;
+
+ /**
+ * This member keeps a vector of pointers to all visible (filtered)
+ * transaction in m_transactionList in sorted order. Sorting is done
+ * in KTransactionPtrVector::compareItems
+ */
+ KTransactionPtrVector m_transactionPtrVector;
+
+ /**
+ * This member holds the state of the toggle switch used
+ * to suppress updates due to MyMoney engine data changes
+ */
+ bool m_needReload;
+
+ /**
+ * Search widget for the list
+ */
+ KListViewSearchLineWidget* m_searchWidget;
+ bool m_needConnection;
+
+ /**
+ * Counting semaphore to collect updates
+ */
+ int m_updatesQueued;
+
+ /**
+ * Semaphore to suppress loading during selection
+ */
+ bool m_inSelection;
+};
+
+#endif
diff --git a/kmymoney2/views/kpayeesviewdecl.ui b/kmymoney2/views/kpayeesviewdecl.ui
new file mode 100644
index 0000000..3584e6f
--- /dev/null
+++ b/kmymoney2/views/kpayeesviewdecl.ui
@@ -0,0 +1,666 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KPayeesViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KPayeesViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>689</width>
+ <height>540</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>m_payeesList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>Extended</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="showSortIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_tabWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>2</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Transactions</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>transactionGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Transactions</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>No.</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Category</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Amount</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_transactionView</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_balanceLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Balance: </string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Address</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>detailsGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Payee Information</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>E-Mail:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Postal Code:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Telephone/Fax:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Notes</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignLeft</set>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>postcodeEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>telephoneEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>emailEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QMultiLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>addressEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QMultiLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>notesEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Address:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignLeft</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Matching</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Transaction Matching</string>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_matchType</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>25</y>
+ <width>403</width>
+ <height>87</height>
+ </rect>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNoMatch</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>1</x>
+ <y>1</y>
+ <width>401</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>No matching</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNameMatch</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>1</x>
+ <y>31</y>
+ <width>401</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Match on Payee name</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioKeyMatch</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>2</x>
+ <y>62</y>
+ <width>399</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Match on a name listed below</string>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="KEditListBox">
+ <property name="name">
+ <cstring>matchKeyEditList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>List of matching names</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This list contains the names that will match this payee if a transaction is imported from an external source. Keep in mind, that you can specify regular expressions here.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkMatchIgnoreCase</cstring>
+ </property>
+ <property name="text">
+ <string>Ignore Case</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage2</cstring>
+ </property>
+ <attribute name="title">
+ <string>Default Account</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkEnableDefaultAccount</cstring>
+ </property>
+ <property name="text">
+ <string>Use the default account for
+new transactions with this payee</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelDefaultAccount</cstring>
+ </property>
+ <property name="text">
+ <string>Default category:</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyAccountCombo" row="0" column="1">
+ <property name="name">
+ <cstring>comboDefaultAccount</cstring>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>buttonSelectMyAccount</cstring>
+ </property>
+ <property name="text">
+ <string>Suggest a category</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_helpButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>260</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_updateButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="local" impldecl="in declaration">../widgets/kmymoneyaccountcombo.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/views/kreportsview.cpp b/kmymoney2/views/kreportsview.cpp
new file mode 100755
index 0000000..6c7da52
--- /dev/null
+++ b/kmymoney2/views/kreportsview.cpp
@@ -0,0 +1,1510 @@
+/***************************************************************************
+ kreportsview.cpp - description
+ -------------------
+ begin : Sat Mar 27 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <ace.j@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdragobject.h>
+#include <qclipboard.h>
+#include <qapplication.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qfile.h>
+#include <qtimer.h>
+#include <qiconset.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qcheckbox.h>
+#include <qvbox.h>
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <khtmlview.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <klistview.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyreport.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "kreportsview.h"
+#include "../reports/querytable.h"
+#include "../reports/objectinfotable.h"
+#include "../dialogs/kreportconfigurationfilterdlg.h"
+#include "../kmymoneyutils.h"
+
+using namespace reports;
+
+#define VIEW_LEDGER "ledger"
+#define VIEW_SCHEDULE "schedule"
+#define VIEW_WELCOME "welcome"
+#define VIEW_HOME "home"
+#define VIEW_REPORTS "reports"
+
+/**
+ * KReportsView::KReportTab Implementation
+ */
+
+KReportsView::KReportTab::KReportTab(KTabWidget* parent, const MyMoneyReport& report ):
+ QWidget( parent, "reporttab" ),
+ m_part( new KHTMLPart( this, "reporttabpart" ) ),
+ m_chartView( new KReportChartView( this, "reportchart" ) ),
+ m_control( new kMyMoneyReportControlDecl( this, "reportcontrol" ) ),
+ m_layout( new QVBoxLayout( this, 11, 6, "reporttablayout" ) ),
+ m_report( report ),
+ m_deleteMe( false ),
+ m_showingChart( false ),
+ m_needReload( true ),
+ m_table(0)
+{
+ m_part->setZoomFactor( KMyMoneyGlobalSettings::fontSizePercentage() );
+
+ if ( ! KReportChartView::implemented() || m_report.reportType() != MyMoneyReport::ePivotTable )
+ {
+ m_control->buttonChart->hide();
+ }
+
+ m_chartView->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
+ m_chartView->hide();
+ m_layout->addWidget( m_control ); //, 0, Qt::AlignTop );
+ m_layout->addWidget( m_part->view() );
+ m_layout->addWidget( m_chartView );
+
+ // I like this icon...
+ QString icon = KGlobal::dirs()->findResource("icon", "default.kde/16x16/mimetypes/spreadsheet.png");
+ // but if it's not there, we'll use ye ol' standard icon
+ if ( icon == QString::null )
+ icon = KGlobal::dirs()->findResource("icon", "hicolor/16x16/apps/kmymoney2.png");
+
+ parent->insertTab( this, QIconSet(QPixmap(icon)), report.name() );
+ parent->setTabEnabled( this, true );
+
+#ifdef HAVE_KDCHART
+ if ( m_report.isChartByDefault() )
+ toggleChart();
+#endif
+}
+
+KReportsView::KReportTab::~KReportTab()
+{
+ delete m_table;
+}
+
+void KReportsView::KReportTab::print(void)
+{
+ if(m_part && m_part->view())
+ m_part->view()->print();
+}
+
+void KReportsView::KReportTab::copyToClipboard(void)
+{
+ QTextDrag* pdrag = new QTextDrag( createTable() );
+ pdrag->setSubtype("html");
+ QApplication::clipboard()->setData(pdrag);
+}
+
+void KReportsView::KReportTab::saveAs( const QString& filename, bool includeCSS )
+{
+ QFile file( filename );
+ if ( file.open( IO_WriteOnly ) )
+ {
+ if ( QFileInfo(filename).extension(false).lower() == "csv")
+ {
+ QTextStream(&file) << m_table->renderCSV();
+ }
+ else {
+ QTextStream stream(&file);
+
+ QRegExp exp(QString("(.*)(<link.*css\" href=)\"(.*)\">(<meta.*%1\" />)(.*)").arg(KGlobal::locale()->encoding()));
+ QString table = createTable();
+ if(exp.search(table) != -1 && includeCSS) {
+ QFile cssFile(exp.cap(3));
+ if(cssFile.open(IO_ReadOnly)) {
+ QTextStream cssStream(&cssFile);
+ stream << exp.cap(1);
+ stream << exp.cap(4);
+ stream << endl << "<style type=\"text/css\">" << endl << "<!--" << endl;
+ stream << cssStream.read();
+ stream << "-->" << endl << "</style>" << endl;
+ stream << exp.cap(5);
+ cssFile.close();
+ } else {
+ stream << table;
+ }
+ } else {
+ stream << table;
+ }
+ }
+ file.close();
+ }
+}
+
+void KReportsView::KReportTab::loadTab(void)
+{
+ m_needReload = true;
+ if(isVisible()) {
+ m_needReload = false;
+ updateReport();
+ }
+}
+
+void KReportsView::KReportTab::show(void)
+{
+ if(m_needReload) {
+ m_needReload = false;
+ updateReport();
+ }
+ QWidget::show();
+}
+
+void KReportsView::KReportTab::updateReport(void)
+{
+ // reload the report from the engine. It might have
+ // been changed by the user
+
+ try {
+ // Don't try to reload default reports from the engine
+ if(!m_report.id().isEmpty())
+ m_report = MyMoneyFile::instance()->report(m_report.id());
+ } catch(MyMoneyException* e) {
+ delete e;
+ }
+
+ delete m_table;
+ m_table = 0;
+
+ if ( m_report.reportType() == MyMoneyReport::ePivotTable ) {
+ m_table = new PivotTable(m_report);
+ } else if ( m_report.reportType() == MyMoneyReport::eQueryTable ) {
+ m_table = new QueryTable(m_report);
+ } else if ( m_report.reportType() == MyMoneyReport::eInfoTable ) {
+ m_table = new ObjectInfoTable(m_report);
+ }
+
+ m_part->begin();
+ m_part->write(createTable());
+ m_part->end();
+
+ m_table->drawChart( *m_chartView );
+ m_chartView->update();
+}
+
+QString KReportsView::KReportTab::createTable(const QString& links)
+{
+ QString filename;
+ if(!MyMoneyFile::instance()->value("reportstylesheet").isEmpty())
+ filename = KGlobal::dirs()->findResource("appdata", QString("html/%1").arg(MyMoneyFile::instance()->value("reportstylesheet")));
+ if(filename.isEmpty())
+ filename = KGlobal::dirs()->findResource("appdata", "html/kmymoney2.css");
+ QString header = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n") +
+ QString("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"%1\">").arg(filename);
+
+ header += QString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\" />").arg(KGlobal::locale()->encoding());
+ header += KMyMoneyUtils::variableCSS();
+
+ header += "</head><body>\n";
+
+ QString footer = "</body></html>\n";
+
+ QString html;
+ try {
+ html += header;
+ html += links;
+
+ html += m_table->renderHTML();
+
+ html += footer;
+ }
+ catch(MyMoneyException *e)
+ {
+ kdDebug(2) << "KReportsView::KReportTab::createTable(): ERROR " << e->what() << endl;
+
+ QString error = QString(i18n("There was an error creating your report: \"%1\".\nPlease report this error to the developer's list: kmymoney2-developer@lists.sourceforge.net")).arg(e->what());
+
+ KMessageBox::error(this, error, i18n("Critical Error"));
+
+ html += header;
+ html += links;
+ html += "<h1>"+i18n("Unable to generate report")+"</h1><p>"+error+"</p>";
+ html += footer;
+
+ delete e;
+ }
+ return html;
+
+}
+
+void KReportsView::KReportTab::toggleChart(void)
+{
+ // for now it will just SHOW the chart. In the future it actually has to toggle it.
+
+ if ( m_showingChart )
+ {
+ m_part->show();
+ m_chartView->hide();
+
+ m_control->buttonChart->setText( i18n( "Chart" ) );
+ QToolTip::add( m_control->buttonChart, i18n( "Show the chart version of this report" ) );
+ }
+ else
+ {
+ m_part->hide();
+ m_chartView->show();
+
+ m_control->buttonChart->setText( i18n( "Report" ) );
+ QToolTip::add( m_control->buttonChart, i18n( "Show the report version of this chart" ) );
+ }
+ m_showingChart = ! m_showingChart;
+}
+
+/**
+ * KReportsView Implementation
+ */
+
+class KReportsView::Private
+{
+public:
+ Private() :
+ includeCSS(0) {}
+
+ QCheckBox* includeCSS;
+};
+
+KReportsView::KReportsView(QWidget *parent, const char *name ) :
+ KMyMoneyViewBase(parent, name, i18n("Reports")),
+ d(new Private),
+ m_needReload(false)
+{
+ m_reportTabWidget = new KTabWidget( this, "m_reportTabWidget" );
+ addWidget( m_reportTabWidget );
+ m_reportTabWidget->setHoverCloseButton( true );
+
+ m_listTab = (new QWidget( m_reportTabWidget, "indextab" ));
+ m_listTabLayout = ( new QVBoxLayout( m_listTab, 11, 6, "indextabLayout") );
+ m_reportListView = new KListView( m_listTab, "m_reportListView" );
+ m_listTabLayout->addWidget( m_reportListView );
+ m_reportTabWidget->insertTab( m_listTab, i18n("Reports") );
+
+ m_reportListView->addColumn(i18n("Report"));
+ m_reportListView->addColumn(i18n("Comment"));
+ m_reportListView->setResizeMode(QListView::AllColumns);
+ m_reportListView->setAllColumnsShowFocus(true);
+ m_reportListView->setRootIsDecorated(true);
+ m_reportListView->setShadeSortColumn(false);
+
+ connect( m_reportTabWidget, SIGNAL(closeRequest(QWidget*)),
+ this, SLOT(slotClose(QWidget*)) );
+ connect(m_reportListView, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(slotOpenReport(QListViewItem*)));
+ connect(m_reportListView, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(slotOpenReport(QListViewItem*)));
+ connect( m_reportListView, SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint &)),
+ this, SLOT(slotListContextMenu(KListView*,QListViewItem*,const QPoint &)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadView()));
+}
+
+KReportsView::~KReportsView()
+{
+ delete d;
+}
+
+void KReportsView::show()
+{
+ if(m_needReload) {
+ loadView();
+ m_needReload = false;
+ }
+
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+ if(tab)
+ emit reportSelected(tab->report());
+ else
+ emit reportSelected(MyMoneyReport());
+
+ // don't forget base class implementation
+ KMyMoneyViewBase::show();
+}
+
+void KReportsView::slotLoadView(void)
+{
+ m_needReload = true;
+ if(isVisible()) {
+ loadView();
+ m_needReload = false;
+ }
+}
+
+QString KReportsView::KReportGroupListItem::key ( int column, bool ascending ) const
+{
+ if (column == 0)
+ return QString::number(m_nr).rightJustify(3,'0');
+ else
+ return KListViewItem::key(column,ascending);
+}
+
+KReportsView::KReportGroupListItem::KReportGroupListItem(KListView* parent, const int nr, QString name) :
+ KListViewItem(parent),
+ m_name(name)
+{
+ setNr(nr);
+}
+
+void KReportsView::KReportGroupListItem::setNr(const int nr)
+{
+ m_nr = nr;
+ setText(0, QString("%1. %2").arg(nr).arg(m_name));
+}
+
+void KReportsView::loadView(void)
+{
+ ::timetrace("Start KReportsView::loadView");
+
+ // remember the id of the current selected item and the
+ // items that are shown 'expanded'
+ QMap<QString, bool> isOpen;
+ QListViewItem *item = m_reportListView->selectedItem();
+ QString selectedPage = (item) ? item->text(0) : QString();
+
+ // keep a map of all 'expanded' accounts
+ QListViewItemIterator it_lvi(m_reportListView);
+ while(it_lvi.current()) {
+ item = it_lvi.current();
+ if(item && item->isOpen()) {
+ isOpen[item->text(0)] = true;
+ }
+ ++it_lvi;
+ }
+
+ // remember the upper left corner of the viewport
+ QPoint startPoint = m_reportListView->viewportToContents(QPoint(0, 0));
+
+ // turn off updates to avoid flickering during reload
+ m_reportListView->setUpdatesEnabled(false);
+
+ //
+ // Rebuild the list page
+ //
+ m_reportListView->clear();
+ unsigned pagenumber = 1;
+
+ // Default Reports
+ KReportGroupListItem* chartnode = new KReportGroupListItem(m_reportListView, 10, i18n("Charts"));
+
+ QMap<QString,KReportGroupListItem*> groupitems;
+ QValueList<ReportGroup> defaultreports;
+ defaultReports(defaultreports);
+ QValueList<ReportGroup>::const_iterator it_group = defaultreports.begin();
+ while ( it_group != defaultreports.end() )
+ {
+ QString groupname = (*it_group).name();
+ KReportGroupListItem* curnode = new KReportGroupListItem(m_reportListView, pagenumber++, (*it_group).title());
+ curnode->setOpen(isOpen.find(curnode->text(0)) != isOpen.end());
+ groupitems[groupname] = curnode;
+
+ QValueList<MyMoneyReport>::const_iterator it_report = (*it_group).begin();
+ while( it_report != (*it_group).end() )
+ {
+ MyMoneyReport report = *it_report;
+ report.setGroup(groupname);
+ KReportListItem* r = new KReportListItem( curnode, report );
+ if(report.name() == selectedPage)
+ m_reportListView->setSelected(r, true);
+
+ // ALSO place it into the Charts list if it's displayed as a chart by default
+ if ( (*it_report).isChartByDefault() )
+ new KReportListItem( chartnode, *it_report );
+
+ ++it_report;
+ }
+
+ ++it_group;
+ }
+
+ // Rename the charts item to place it at this point in the list.
+ chartnode->setNr(pagenumber++);
+ chartnode->setOpen(isOpen.find(chartnode->text(0)) != isOpen.end());
+
+ // Custom reports
+
+ KReportGroupListItem* favoritenode = new KReportGroupListItem(m_reportListView,pagenumber++, i18n("Favorite Reports"));
+ favoritenode->setOpen(isOpen.find(favoritenode->text(0)) != isOpen.end());
+ KReportGroupListItem* orphannode = NULL;
+
+ QValueList<MyMoneyReport> customreports = MyMoneyFile::instance()->reportList();
+ QValueList<MyMoneyReport>::const_iterator it_report = customreports.begin();
+ while( it_report != customreports.end() )
+ {
+ // If this report is in a known group, place it there
+ KReportGroupListItem* groupnode = groupitems[(*it_report).group()];
+ if ( groupnode )
+ new KReportListItem( groupnode, *it_report );
+ else
+ // otherwise, place it in the orphanage
+ {
+ if ( ! orphannode )
+ orphannode = new KReportGroupListItem(m_reportListView, pagenumber++, i18n("Old Customized Reports"));
+ new KReportListItem( orphannode, *it_report );
+ }
+
+ // ALSO place it into the Favorites list if it's a favorite
+ if ( (*it_report).isFavorite() )
+ new KReportListItem( favoritenode, *it_report );
+
+ // ALSO place it into the Charts list if it's displayed as a chart by default
+ if ( (*it_report).isChartByDefault() )
+ new KReportListItem( chartnode, *it_report );
+
+ ++it_report;
+ }
+
+ // reposition viewport
+ m_reportListView->setContentsPos(startPoint.x(), startPoint.y());
+
+ // turn updates back on
+ m_reportListView->setUpdatesEnabled(true);
+ m_reportListView->repaintContents();
+
+ //
+ // Go through the tabs to set their update flag or delete them if needed
+ //
+
+ int index = 1;
+ while ( index < m_reportTabWidget->count() )
+ {
+ // TODO: Find some way of detecting the file is closed and kill these tabs!!
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->page(index));
+ if ( tab->isReadyToDelete() /* || ! reports.count() */ )
+ {
+ delete tab;
+ --index;
+ }
+ else
+ tab->loadTab();
+ ++index;
+ }
+ ::timetrace("Done KReportsView::loadView");
+}
+
+void KReportsView::slotOpenURL(const KURL &url, const KParts::URLArgs& /* args */)
+{
+ QString view = url.fileName(false);
+ QString command = url.queryItem("command").data();
+
+ if(view == VIEW_REPORTS) {
+
+ if ( command.isEmpty() ) {
+ // slotRefreshView();
+ } else if ( command == "print" )
+ slotPrintView();
+ else if ( command == "copy" )
+ slotCopyView();
+ else if ( command == "save" )
+ slotSaveView();
+ else if ( command == "configure" )
+ slotConfigure();
+ else if ( command == "duplicate" )
+ slotDuplicate();
+ else if ( command == "close" )
+ slotCloseCurrent();
+ else if ( command == "delete" )
+ slotDelete();
+ else
+ qDebug("Unknown command '%s' in KReportsView::slotOpenURL()", static_cast<const char*>(command));
+
+ } else {
+ qDebug("Unknown view '%s' in KReportsView::slotOpenURL()", view.latin1());
+ }
+}
+
+void KReportsView::slotPrintView(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+ if(tab)
+ tab->print();
+}
+
+void KReportsView::slotCopyView(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+ if(tab)
+ tab->copyToClipboard();
+}
+
+void KReportsView::slotSaveView(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+ if(tab) {
+ QVBox* vbox = new QVBox();
+ d->includeCSS = new QCheckBox(i18n("Include Stylesheet"), vbox);
+
+ // the following code is copied from KFileDialog::getSaveFileName,
+ // adjust to our local needs (filetypes etc.) and
+ // enhanced to show the m_saveEncrypted combo box
+ KFileDialog dlg( ":kmymoney-export",
+ QString("%1|%2\n").arg("*.csv").arg(i18n("CSV (Filefilter)", "CSV files")) +
+ QString("%1|%2\n").arg("*.html").arg(i18n("HTML (Filefilter)", "HTML files")),
+ this, "filedialog", true, vbox);
+ connect(&dlg, SIGNAL(filterChanged(const QString&)), this, SLOT(slotSaveFilterChanged(const QString&)));
+
+ dlg.setOperationMode( KFileDialog::Saving );
+ dlg.setCaption(i18n("Export as"));
+ slotSaveFilterChanged("*.csv"); // init gui
+
+ if(dlg.exec() == QDialog::Accepted) {
+ KURL newURL = dlg.selectedURL();
+ if (!newURL.isEmpty()) {
+ QString newName = newURL.prettyURL(0, KURL::StripFileProtocol);
+
+ if(newName.findRev('.') == -1)
+ newName.append(".html");
+
+ tab->saveAs( newName, d->includeCSS->isEnabled() && d->includeCSS->isChecked() );
+ }
+ }
+ }
+}
+
+void KReportsView::slotSaveFilterChanged(const QString& filter)
+{
+ d->includeCSS->setEnabled(filter == "*.html");
+}
+
+void KReportsView::slotConfigure(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+
+ if(tab) {
+ MyMoneyReport report = tab->report();
+ if ( report.comment() == i18n("Default Report") || report.comment() == i18n("Generated Report") )
+ {
+ report.setComment( i18n("Custom Report") );
+ report.setName( report.name() + i18n(" (Customized)") );
+ }
+
+ KReportConfigurationFilterDlg dlg(report);
+
+ if (dlg.exec())
+ {
+ MyMoneyReport newreport = dlg.getConfig();
+
+ // If this report has an ID, then MODIFY it, otherwise ADD it
+ MyMoneyFileTransaction ft;
+ if ( ! newreport.id().isEmpty() )
+ {
+ MyMoneyFile::instance()->modifyReport(newreport);
+ ft.commit();
+ tab->modifyReport(newreport);
+
+ m_reportTabWidget->changeTab( tab, newreport.name() );
+ m_reportTabWidget->showPage(tab);
+ }
+ else
+ {
+ MyMoneyFile::instance()->addReport(newreport);
+ ft.commit();
+ new KReportListItem( m_reportListView, newreport );
+ addReportTab(newreport);
+ }
+ }
+ }
+}
+
+void KReportsView::slotDuplicate(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+
+ if(tab) {
+ MyMoneyReport dupe = tab->report();
+ dupe.setName( QString(i18n("Copy of %1")).arg(dupe.name()) );
+ if ( dupe.comment() == i18n("Default Report") )
+ dupe.setComment( i18n("Custom Report") );
+ dupe.clearId();
+
+ KReportConfigurationFilterDlg dlg(dupe);
+ if (dlg.exec())
+ {
+ dupe = dlg.getConfig();
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->addReport(dupe);
+ ft.commit();
+ new KReportListItem( m_reportListView, dupe );
+ addReportTab(dupe);
+ } catch(MyMoneyException* e) {
+ qDebug("Cannot add report");
+ delete e;
+ }
+ }
+ }
+}
+
+void KReportsView::slotDelete(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+
+ if(tab) {
+ MyMoneyReport report = tab->report();
+ if ( ! report.id().isEmpty() )
+ {
+ if ( KMessageBox::Continue == KMessageBox::warningContinueCancel(this, QString("<qt>")+i18n("Are you sure you want to delete report <b>%1</b>? There is no way to recover it!").arg(report.name())+QString("</qt>"), i18n("Delete Report?")))
+ {
+ // close the tab and then remove the report so that it is not
+ // generated again during the following loadView() call
+ slotClose(tab);
+
+ MyMoneyFileTransaction ft;
+ MyMoneyFile::instance()->removeReport(report);
+ ft.commit();
+ }
+ }
+ else
+ KMessageBox::information(this, QString("<qt>")+i18n("Sorry, <b>%1</b> is a default report. You may not delete it.").arg(report.name())+QString("</qt>"), i18n("Delete Report?"));
+ }
+}
+
+void KReportsView::slotOpenReport(const QString& id)
+{
+ if ( ! id.isEmpty() )
+ {
+ KReportTab* page = NULL;
+ int index = 1;
+ while ( index < m_reportTabWidget->count() )
+ {
+ KReportTab* current = dynamic_cast<KReportTab*>(m_reportTabWidget->page(index));
+
+ if ( current->report().id() == id )
+ {
+ page = current;
+ break;
+ }
+
+ ++index;
+ }
+
+ // Show the tab, or create a new one, as needed
+ if ( page )
+ m_reportTabWidget->showPage( page );
+ else
+ addReportTab(MyMoneyFile::instance()->report(id));
+ }
+}
+
+void KReportsView::slotOpenReport(QListViewItem* item)
+{
+ KReportListItem *reportItem = dynamic_cast<KReportListItem*> (item);
+
+ if ( reportItem )
+ {
+ KReportTab* page = NULL;
+
+ // Find the tab which contains the report indicated by this list item
+ int index = 1;
+ while ( index < m_reportTabWidget->count() )
+ {
+ KReportTab* current = dynamic_cast<KReportTab*>(m_reportTabWidget->page(index));
+
+ // If this report has an ID, we'll use the ID to match
+ if ( ! reportItem->report().id().isEmpty() )
+ {
+ if ( current->report().id() == reportItem->report().id() )
+ {
+ page = current;
+ break;
+ }
+ }
+ // Otherwise, use the name to match. THIS ASSUMES that no 2 default reports
+ // have the same name...but that would be pretty a boneheaded thing to do.
+ else
+ {
+ if ( current->report().name() == reportItem->report().name() )
+ {
+ page = current;
+ break;
+ }
+ }
+
+ ++index;
+ }
+
+ // Show the tab, or create a new one, as needed
+ if ( page )
+ m_reportTabWidget->showPage( page );
+ else
+ addReportTab(reportItem->report());
+ }
+ else if (item)
+ {
+ // this is not a KReportListItem, so it's a regular QListViewItem, which
+ // means its a header.
+ //
+ // double-click on a header means toggle the expand/collapse state
+
+ item->setOpen( ! item->isOpen() );
+ }
+}
+
+void KReportsView::slotOpenReport(const MyMoneyReport& report)
+{
+ kdDebug(2) << __func__ << " " << report.name() << endl;
+ KReportTab* page = NULL;
+
+ // Find the tab which contains the report indicated by this list item
+ int index = 1;
+ while ( index < m_reportTabWidget->count() )
+ {
+ KReportTab* current = dynamic_cast<KReportTab*>(m_reportTabWidget->page(index));
+
+ if ( current->report().name() == report.name() )
+ {
+ page = current;
+ break;
+ }
+
+ ++index;
+ }
+
+ // Show the tab, or create a new one, as needed
+ if ( page )
+ m_reportTabWidget->showPage( page );
+ else
+ addReportTab(report);
+}
+
+void KReportsView::slotToggleChart(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->currentPage());
+ if(tab)
+ tab->toggleChart();
+}
+
+void KReportsView::slotCloseCurrent(void)
+{
+ if(m_reportTabWidget->currentPage())
+ slotClose(m_reportTabWidget->currentPage());
+}
+
+void KReportsView::slotClose(QWidget* w)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(w);
+ if(tab) {
+ m_reportTabWidget->removePage(tab);
+ tab->setReadyToDelete(true);
+ }
+}
+
+void KReportsView::slotCloseAll(void)
+{
+ KReportTab* tab = dynamic_cast<KReportTab*>(m_reportTabWidget->page(1));
+ while (tab)
+ {
+ m_reportTabWidget->removePage(tab);
+ tab->setReadyToDelete(true);
+
+ tab = dynamic_cast<KReportTab*>(m_reportTabWidget->page(1));
+ }
+}
+
+void KReportsView::addReportTab(const MyMoneyReport& report)
+{
+ KReportTab* tab = new KReportTab(m_reportTabWidget,report);
+
+ connect( tab->control()->buttonChart, SIGNAL(clicked()),
+ this, SLOT(slotToggleChart(void )));
+ connect( tab->control()->buttonConfigure, SIGNAL(clicked()),
+ this, SLOT(slotConfigure(void )));
+ connect( tab->control()->buttonNew, SIGNAL(clicked()),
+ this, SLOT(slotDuplicate(void )));
+ connect( tab->control()->buttonCopy, SIGNAL(clicked()),
+ this, SLOT(slotCopyView(void )));
+ connect( tab->control()->buttonExport, SIGNAL(clicked()),
+ this, SLOT(slotSaveView(void )));
+ connect( tab->control()->buttonDelete, SIGNAL(clicked()),
+ this, SLOT(slotDelete(void )));
+ connect( tab->control()->buttonClose, SIGNAL(clicked()),
+ this, SLOT(slotCloseCurrent(void )));
+
+ // if this is a default report, then you can't delete it!
+ if ( report.id().isEmpty() )
+ tab->control()->buttonDelete->setEnabled(false);
+
+ // slotRefreshView();
+
+ m_reportTabWidget->showPage(tab);
+
+}
+
+void KReportsView::slotListContextMenu(KListView* lv,QListViewItem* item,const QPoint & p)
+{
+ if ( lv == m_reportListView && item )
+ {
+ QPopupMenu* contextmenu = new QPopupMenu(this);
+ contextmenu->insertItem( i18n("&Open"), this, SLOT(slotOpenFromList()) );
+ contextmenu->insertItem( i18n("&Configure"), this, SLOT(slotConfigureFromList()) );
+ contextmenu->insertItem( i18n("&New report"), this, SLOT(slotNewFromList()) );
+ contextmenu->insertItem( i18n("&Delete"), this, SLOT(slotDeleteFromList()) );
+
+ contextmenu->popup(p);
+ }
+}
+
+void KReportsView::slotOpenFromList(void)
+{
+ KReportListItem *reportItem = dynamic_cast<KReportListItem*> (m_reportListView->selectedItem());
+
+ if ( reportItem )
+ slotOpenReport(reportItem);
+}
+
+void KReportsView::slotConfigureFromList(void)
+{
+ KReportListItem *reportItem = dynamic_cast<KReportListItem*> (m_reportListView->selectedItem());
+
+ if ( reportItem )
+ {
+ slotOpenReport(reportItem);
+ slotConfigure();
+ }
+}
+void KReportsView::slotNewFromList(void)
+{
+ KReportListItem *reportItem = dynamic_cast<KReportListItem*> (m_reportListView->selectedItem());
+
+ if ( reportItem )
+ {
+ slotOpenReport(reportItem);
+ slotDuplicate();
+ }
+}
+
+void KReportsView::slotDeleteFromList(void)
+{
+ KReportListItem *reportItem = dynamic_cast<KReportListItem*> (m_reportListView->selectedItem());
+
+ if ( reportItem )
+ {
+ slotOpenReport(reportItem);
+ slotDelete();
+ }
+}
+
+void KReportsView::defaultReports(QValueList<ReportGroup>& groups)
+{
+ {
+ ReportGroup list("Income and Expenses", i18n("Income and Expenses"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eExpenseIncome,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentMonth,
+ MyMoneyReport::eDetailAll,
+ i18n("Income and Expenses This Month"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eExpenseIncome,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Income and Expenses This Year"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eExpenseIncome,
+ MyMoneyReport::eYears,
+ MyMoneyTransactionFilter::allDates,
+ MyMoneyReport::eDetailAll,
+ i18n("Income and Expenses By Year"),
+ i18n("Default Report")
+ ));
+
+#ifdef HAVE_KDCHART
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eExpenseIncome,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ i18n("Income and Expenses Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+ list.back().setChartDataLabels(false);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eExpenseIncome,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailGroup,
+ i18n("Income and Expenses Pie Chart"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartType(MyMoneyReport::eChartPie);
+ list.back().setShowingRowTotals(false);
+#endif
+
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Net Worth", i18n("Net Worth"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ i18n("Net Worth By Month"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::today,
+ MyMoneyReport::eDetailTop,
+ i18n("Net Worth Today"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eYears,
+ MyMoneyTransactionFilter::allDates,
+ MyMoneyReport::eDetailTop,
+ i18n("Net Worth By Year"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::next7Days,
+ MyMoneyReport::eDetailTop,
+ i18n("7-day Cash Flow Forecast"),
+ i18n("Default Report")
+ ));
+ list.back().setIncludingSchedules( true );
+ list.back().setColumnsAreDays( true );
+
+#ifdef HAVE_KDCHART
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::last12Months,
+ MyMoneyReport::eDetailTotal,
+ i18n("Net Worth Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eInstitution,
+ MyMoneyReport::eQCnone,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ i18n("Account Balances by Institution"),
+ i18n("Default Report")
+ ));
+#endif
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccountType,
+ MyMoneyReport::eQCnone,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailTop,
+ i18n("Account Balances by Type"),
+ i18n("Default Report")
+ ));
+
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Transactions", i18n("Transactions"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccount,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCcategory|MyMoneyReport::eQCbalance,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Transactions by Account"),
+ i18n("Default Report")
+ ));
+ //list.back().setConvertCurrency(false);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eCategory,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCaccount,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Transactions by Category"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::ePayee,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCcategory,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Transactions by Payee"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eMonth,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCcategory,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Transactions by Month"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eWeek,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCcategory,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Transactions by Week"),
+ i18n("Default Report")
+ ));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccount,
+ MyMoneyReport::eQCloan,
+ MyMoneyTransactionFilter::allDates,
+ MyMoneyReport::eDetailAll,
+ i18n("Loan Transactions"),
+ i18n("Default Report")
+ ));
+ list.back().setLoansOnly(true);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccountReconcile,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCcategory|MyMoneyReport::eQCbalance,
+ MyMoneyTransactionFilter::last3Months,
+ MyMoneyReport::eDetailAll,
+ i18n("Transactions by Reconciliation Status"),
+ i18n("Default Report")
+ ));
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("CashFlow", i18n("Cash Flow"));
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eCashFlow,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCaccount,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Cash Flow Transactions This Month"),
+ i18n("Default Report")
+ ));
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Investments", i18n("Investments"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eTopAccount,
+ MyMoneyReport::eQCaction|MyMoneyReport::eQCshares|MyMoneyReport::eQCprice,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Transactions"),
+ i18n("Default Report")
+ ));
+ list.back().setInvestmentsOnly(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccountByTopAccount,
+ MyMoneyReport::eQCshares|MyMoneyReport::eQCprice,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Holdings by Account"),
+ i18n("Default Report")
+ ));
+ list.back().setInvestmentsOnly(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eEquityType,
+ MyMoneyReport::eQCshares|MyMoneyReport::eQCprice,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Holdings by Type"),
+ i18n("Default Report")
+ ));
+ list.back().setInvestmentsOnly(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccountByTopAccount,
+ MyMoneyReport::eQCperformance,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Performance by Account"),
+ i18n("Default Report")
+ ));
+ list.back().setInvestmentsOnly(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eEquityType,
+ MyMoneyReport::eQCperformance,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Performance by Type"),
+ i18n("Default Report")
+ ));
+ list.back().setInvestmentsOnly(true);
+#ifdef HAVE_KDCHART
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::today,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Holdings Pie"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartPie);
+ list.back().setInvestmentsOnly(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::last12Months,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Worth Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+ list.back().setColumnsAreDays( true );
+ list.back().setInvestmentsOnly(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::last12Months,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Price Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+ list.back().setColumnsAreDays( true );
+ list.back().setInvestmentsOnly(true);
+ list.back().setIncludingBudgetActuals(false);
+ list.back().setIncludingPrice(true);
+ list.back().setConvertCurrency(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::last12Months,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Moving Average Price Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+ list.back().setColumnsAreDays( true );
+ list.back().setInvestmentsOnly(true);
+ list.back().setIncludingBudgetActuals(false);
+ list.back().setIncludingAveragePrice(true);
+ list.back().setMovingAverageDays(10);
+ list.back().setConvertCurrency(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::last30Days,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Moving Average"),
+ i18n("Default Report")
+ ));
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+ list.back().setColumnsAreDays( true );
+ list.back().setInvestmentsOnly(true);
+ list.back().setIncludingBudgetActuals(false);
+ list.back().setIncludingMovingAverage(true);
+ list.back().setMovingAverageDays(10);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::last30Days,
+ MyMoneyReport::eDetailAll,
+ i18n("Investment Moving Average vs Actual"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+ list.back().setColumnsAreDays( true );
+ list.back().setInvestmentsOnly(true);
+ list.back().setIncludingBudgetActuals(true);
+ list.back().setIncludingMovingAverage(true);
+ list.back().setMovingAverageDays(10);
+#endif
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Taxes", i18n("Taxes"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eCategory,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCaccount,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Tax Transactions by Category"),
+ i18n("Default Report")
+ ));
+ list.back().setTax(true);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::ePayee,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCcategory|MyMoneyReport::eQCaccount,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Tax Transactions by Payee"),
+ i18n("Default Report")
+ ));
+ list.back().setTax(true);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eCategory,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCpayee|MyMoneyReport::eQCaccount,
+ MyMoneyTransactionFilter::lastFiscalYear,
+ MyMoneyReport::eDetailAll,
+ i18n("Tax Transactions by Category Last Fiscal Year"),
+ i18n("Default Report")
+ ));
+ list.back().setTax(true);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::ePayee,
+ MyMoneyReport::eQCnumber|MyMoneyReport::eQCcategory|MyMoneyReport::eQCaccount,
+ MyMoneyTransactionFilter::lastFiscalYear,
+ MyMoneyReport::eDetailAll,
+ i18n("Tax Transactions by Payee Last Fiscal Year"),
+ i18n("Default Report")
+ ));
+ list.back().setTax(true);
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Budgeting", i18n("Budgeting"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToDate,
+ MyMoneyReport::eDetailAll,
+ i18n("Budgeted vs. Actual This Year"),
+ i18n("Default Report")
+ ));
+ list.back().setShowingRowTotals(true);
+ list.back().setBudget("Any",true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::yearToMonth,
+ MyMoneyReport::eDetailAll,
+ i18n("Budgeted vs. Actual This Year (YTM)"),
+ i18n("Default Report")
+ ));
+ list.back().setShowingRowTotals(true);
+ list.back().setBudget("Any",true);
+ // in case we're in January, we show the last year
+ if(QDate::currentDate().month() == 1) {
+ list.back().setDateFilter(MyMoneyTransactionFilter::lastYear);
+ }
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentMonth,
+ MyMoneyReport::eDetailAll,
+ i18n("Monthly Budgeted vs. Actual"),
+ i18n("Default Report")
+ ));
+ list.back().setBudget("Any",true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentYear,
+ MyMoneyReport::eDetailAll,
+ i18n("Yearly Budgeted vs. Actual"),
+ i18n("Default Report")
+ ));
+ list.back().setBudget("Any",true);
+ list.back().setShowingRowTotals(true);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudget,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentMonth,
+ MyMoneyReport::eDetailAll,
+ i18n("Monthly Budget"),
+ i18n("Default Report")
+ ));
+ list.back().setBudget("Any",false);
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudget,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentYear,
+ MyMoneyReport::eDetailAll,
+ i18n("Yearly Budget"),
+ i18n("Default Report")
+ ));
+ list.back().setBudget("Any",false);
+ list.back().setShowingRowTotals(true);
+#ifdef HAVE_KDCHART
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eBudgetActual,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::currentYear,
+ MyMoneyReport::eDetailGroup,
+ i18n("Yearly Budgeted vs Actual Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setBudget("Any",true);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+#endif
+
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Forecast", i18n("Forecast"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::next12Months,
+ MyMoneyReport::eDetailTop,
+ i18n("Forecast By Month"),
+ i18n("Default Report")
+ ));
+ list.back().setIncludingForecast( true );
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::nextQuarter,
+ MyMoneyReport::eDetailTop,
+ i18n("Forecast Next Quarter"),
+ i18n("Default Report")
+ ));
+ list.back().setColumnsAreDays( true );
+ list.back().setIncludingForecast( true );
+
+#ifdef HAVE_KDCHART
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAssetLiability,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::next3Months,
+ MyMoneyReport::eDetailTotal,
+ i18n("Net Worth Forecast Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setColumnsAreDays( true );
+ list.back().setIncludingForecast( true );
+ list.back().setChartByDefault(true);
+ list.back().setChartGridLines(false);
+ list.back().setChartType(MyMoneyReport::eChartLine);
+#endif
+ groups.push_back(list);
+ }
+ {
+ ReportGroup list("Information", i18n("General Information"));
+
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eSchedule,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::next12Months,
+ MyMoneyReport::eDetailAll,
+ i18n("Schedule Information"),
+ i18n("Default Report")
+ ));
+ list.back().setDetailLevel(MyMoneyReport::eDetailAll);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eSchedule,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::next12Months,
+ MyMoneyReport::eDetailAll,
+ i18n("Schedule Summary Information"),
+ i18n("Default Report")
+ ));
+ list.back().setDetailLevel(MyMoneyReport::eDetailTop);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccountInfo,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::today,
+ MyMoneyReport::eDetailAll,
+ i18n("Account Information"),
+ i18n("Default Report")
+ ));
+ list.back().setConvertCurrency(false);
+ list.push_back(MyMoneyReport(
+ MyMoneyReport::eAccountLoanInfo,
+ MyMoneyReport::eMonths,
+ MyMoneyTransactionFilter::today,
+ MyMoneyReport::eDetailAll,
+ i18n("Loan Information"),
+ i18n("Default Report")
+ ));
+ list.back().setConvertCurrency(false);
+ groups.push_back(list);
+ }
+}
+
+// Make sure, that these definitions are only used within this file
+// this does not seem to be necessary, but when building RPMs the
+// build option 'final' is used and all CPP files are concatenated.
+// So it could well be, that in another CPP file these definitions
+// are also used.
+#undef VIEW_LEDGER
+#undef VIEW_SCHEDULE
+#undef VIEW_WELCOME
+#undef VIEW_HOME
+#undef VIEW_REPORTS
+
+#include "kreportsview.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/views/kreportsview.h b/kmymoney2/views/kreportsview.h
new file mode 100755
index 0000000..eaa8c7c
--- /dev/null
+++ b/kmymoney2/views/kreportsview.h
@@ -0,0 +1,262 @@
+/***************************************************************************
+ kreportsview.h - description
+ -------------------
+ begin : Sat Mar 27 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Ace Jones <ace.jones@hotpop.com>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KREPORTSVIEW_H
+#define KREPORTSVIEW_H
+
+#include "kdecompat.h"
+
+// Some STL headers in GCC4.3 contain operator new. Memory checker mangles these
+#ifdef _CHECK_MEMORY
+ #undef new
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qvaluevector.h>
+#include <qwidget.h>
+
+class QVBoxLayout;
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <khtml_part.h>
+#include <klistview.h>
+#include <ktabwidget.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#ifdef _CHECK_MEMORY
+ #include <kmymoney/mymoneyutils.h>
+#endif
+
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyreport.h>
+#include "../reports/pivottable.h"
+#include "../reports/querytable.h"
+#include "../widgets/kmymoneyreportcontroldecl.h"
+#include "../reports/kreportchartview.h"
+#include "../views/kmymoneyview.h"
+
+class MyMoneyReport;
+
+namespace KReportView {
+};
+
+
+/**
+ * Displays a page where reports can be placed.
+ *
+ * @author Ace Jones
+ *
+ * @short A view for reports.
+**/
+class KReportsView : public KMyMoneyViewBase
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Helper class for KReportView.
+ *
+ * This is the widget which displays a single report in the TabWidget that comprises this view.
+ *
+ * @author Ace Jones
+ */
+
+ class KReportTab: public QWidget
+ {
+ private:
+ KHTMLPart* m_part;
+ reports::KReportChartView* m_chartView;
+ kMyMoneyReportControlDecl* m_control;
+ QVBoxLayout* m_layout;
+ MyMoneyReport m_report;
+ bool m_deleteMe;
+ bool m_showingChart;
+ bool m_needReload;
+ reports::ReportTable* m_table;
+
+ public:
+ KReportTab(KTabWidget* parent, const MyMoneyReport& report );
+ ~KReportTab();
+ const MyMoneyReport& report(void) const { return m_report; }
+ void print(void);
+ void toggleChart(void);
+ void copyToClipboard(void);
+ void saveAs( const QString& filename, bool includeCSS = false );
+ void updateReport(void);
+ QString createTable(const QString& links=QString());
+ const kMyMoneyReportControlDecl* control(void) const { return m_control; }
+ bool isReadyToDelete(void) const { return m_deleteMe; }
+ void setReadyToDelete(bool f) { m_deleteMe = f; }
+ void modifyReport( const MyMoneyReport& report ) { m_report = report; }
+ void show(void);
+ void loadTab(void);
+ };
+
+ /**
+ * Helper class for KReportView.
+ *
+ * Associates a report id with a list view item.
+ *
+ * @author Ace Jones
+ */
+
+ class KReportListItem: public KListViewItem
+ {
+ private:
+ QString m_id;
+ MyMoneyReport m_report;
+
+ public:
+ KReportListItem( KListView* parent, const MyMoneyReport& report ):
+ KListViewItem( parent, report.name(), report.comment() ),
+ m_id( report.id() ),
+ m_report( report )
+ {}
+ KReportListItem( KListViewItem* parent, const MyMoneyReport& report ):
+ KListViewItem( parent, report.name(), report.comment() ),
+ m_id( report.id() ),
+ m_report( report )
+ {}
+ //const QString& id(void) const { return m_id; }
+ const MyMoneyReport& report(void) const { return m_report; }
+ };
+
+ class KReportGroupListItem: public KListViewItem
+ {
+ private:
+ int m_nr;
+ QString m_name;
+
+ public:
+ KReportGroupListItem( KListView* parent,const int nr,const QString name);
+ virtual QString key ( int column, bool ascending ) const;
+ void setNr(const int nr);
+ };
+
+ /**
+ * Helper class for KReportView.
+ *
+ * This is a named list of reports, which will be one section
+ * in the list of default reports
+ *
+ * @author Ace Jones
+ */
+ class ReportGroup: public QValueList<MyMoneyReport>
+ {
+ private:
+ QString m_name; ///< the title of the group in non-translated form
+ QString m_title; ///< the title of the group in i18n-ed form
+ public:
+ ReportGroup( void ) {}
+ ReportGroup( const QString& name, const QString& title ): m_name( name ), m_title(title) {}
+ const QString& name( void ) const { return m_name; }
+ const QString& title(void) const { return m_title; }
+ };
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+ KTabWidget* m_reportTabWidget;
+ KListView* m_reportListView;
+ QWidget* m_listTab;
+ QVBoxLayout* m_listTabLayout;
+ bool m_needReload;
+
+public:
+ /**
+ * Standard constructor.
+ *
+ * @param parent The QWidget this is used in.
+ * @param name The QT name.
+ *
+ * @return An object of type KReportsView
+ *
+ * @see ~KReportsView
+ */
+ KReportsView(QWidget *parent=0, const char *name=0);
+
+ /**
+ * Standard destructor.
+ *
+ * @return Nothing.
+ *
+ * @see KReportsView
+ */
+ ~KReportsView();
+
+ /**
+ * Overridden so we can reload the view if necessary.
+ *
+ * @return Nothing.
+ */
+ void show();
+
+protected:
+ void addReportTab(const MyMoneyReport&);
+ void loadView(void);
+ static void defaultReports(QValueList<ReportGroup>&);
+
+public slots:
+ void slotOpenURL(const KURL &url, const KParts::URLArgs& args);
+
+ void slotLoadView(void);
+ void slotPrintView(void);
+ void slotCopyView(void);
+ void slotSaveView(void);
+ void slotConfigure(void);
+ void slotDuplicate(void);
+ void slotToggleChart(void);
+ void slotOpenReport(QListViewItem*);
+ void slotOpenReport(const QString&);
+ void slotOpenReport(const MyMoneyReport&);
+ void slotCloseCurrent(void);
+ void slotClose(QWidget*);
+ void slotCloseAll(void);
+ void slotDelete(void);
+ void slotListContextMenu(KListView*,QListViewItem*,const QPoint &);
+ void slotOpenFromList(void);
+ void slotConfigureFromList(void);
+ void slotNewFromList(void);
+ void slotDeleteFromList(void);
+
+protected slots:
+ void slotSaveFilterChanged(const QString&);
+
+signals:
+ /**
+ * This signal is emitted whenever a report is selected
+ */
+ void reportSelected(const MyMoneyReport&);
+
+
+};
+
+#endif
diff --git a/kmymoney2/views/kscheduledlistitem.cpp b/kmymoney2/views/kscheduledlistitem.cpp
new file mode 100644
index 0000000..6ba0b56
--- /dev/null
+++ b/kmymoney2/views/kscheduledlistitem.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+ kscheduledlistitem.cpp - description
+ -------------------
+ begin : Sun Jan 27 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpainter.h>
+#include <qstyle.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kconfig.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kscheduledlistitem.h"
+#include "../mymoney/mymoneyfile.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../kmymoneyutils.h"
+
+KScheduledListItem::KScheduledListItem(KListView *parent, const QString& name, const QPixmap& pixmap, const QString& sortKey) :
+ KListViewItem(parent, name),
+ m_sortKey(sortKey)
+{
+ setPixmap(0, pixmap);
+ if(m_sortKey.isEmpty())
+ m_sortKey = name;
+}
+
+KScheduledListItem::KScheduledListItem(KScheduledListItem *parent, const MyMoneySchedule& schedule/*, bool even*/)
+ : KListViewItem(parent)
+{
+ m_schedule = schedule;
+ m_sortKey = schedule.name();
+ setPixmap(0, KMyMoneyUtils::scheduleIcon(KIcon::Small));
+
+ try
+ {
+ MyMoneyTransaction transaction = schedule.transaction();
+ MyMoneySplit s1 = transaction.splits()[0];
+ MyMoneySplit s2 = transaction.splits()[1];
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ MyMoneySplit split;
+ MyMoneyAccount acc;
+
+ switch(schedule.type()) {
+ case MyMoneySchedule::TYPE_DEPOSIT:
+ if (s1.value().isNegative())
+ split = s2;
+ else
+ split = s1;
+ break;
+
+ case MyMoneySchedule::TYPE_LOANPAYMENT:
+ for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
+ acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.accountGroup() == MyMoneyAccount::Asset
+ || acc.accountGroup() == MyMoneyAccount::Liability) {
+ if(acc.accountType() != MyMoneyAccount::Loan
+ && acc.accountType() != MyMoneyAccount::AssetLoan) {
+ split = *it_s;
+ break;
+ }
+ }
+ }
+ if(it_s == transaction.splits().end()) {
+ qFatal("Split for payment account not found in %s:%d.", __FILE__, __LINE__);
+ }
+ break;
+
+ default:
+ if (!s1.value().isPositive())
+ split = s1;
+ else
+ split = s2;
+ break;
+ }
+ acc = MyMoneyFile::instance()->account(split.accountId());
+
+/*
+ if (schedule.type() == MyMoneySchedule::TYPE_DEPOSIT)
+ {
+ if (s1.value() >= 0)
+ split = s1;
+ else
+ split = s2;
+ }
+ else if(schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT)
+ {
+
+ }
+ else
+ {
+ if (s1.value() < 0)
+ split = s1;
+ else
+ split = s2;
+ }
+*/
+ setText(0, schedule.name());
+ MyMoneySecurity currency = MyMoneyFile::instance()->currency(acc.currencyId());
+
+ setText(1, acc.name());
+ if(!s1.payeeId().isEmpty())
+ setText(2, MyMoneyFile::instance()->payee(s1.payeeId()).name());
+ else
+ setText(2, "---");
+ m_amount = split.shares().abs();
+ setText(3, QString("%1 ").arg(m_amount.formatMoney(acc, currency)));
+ // Do the real next payment like ms-money etc
+ if (schedule.isFinished())
+ {
+ setText(4, i18n("Finished"));
+ }
+ else
+ setText(4, KGlobal::locale()->formatDate(schedule.adjustedNextDueDate(), true));
+
+ setText(5, i18n(schedule.occurenceToString()));
+ setText(6, KMyMoneyUtils::paymentMethodToString(schedule.paymentType()));
+ }
+ catch (MyMoneyException *e)
+ {
+ setText(0, "Error:");
+ setText(1, e->what());
+ delete e;
+ }
+}
+
+KScheduledListItem::~KScheduledListItem()
+{
+}
+
+void KScheduledListItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+ QColorGroup cg2(cg);
+
+ QColor textColour = KGlobalSettings::textColor();
+ QFont cellFont = KMyMoneyGlobalSettings::listCellFont();
+
+ // avoid colorizing lines that do not contain a schedule
+ if(!m_schedule.id().isEmpty()) {
+ if (m_schedule.isFinished())
+ textColour = Qt::darkGreen;
+ else if (m_schedule.isOverdue())
+ textColour = Qt::red;
+ }
+
+ cg2.setColor(QColorGroup::Text, textColour);
+
+ // display group items in bold
+ if (!parent())
+ cellFont.setBold(true);
+
+ p->setFont(cellFont);
+
+ if (isAlternate())
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+
+ QListViewItem::paintCell(p, cg2, column, width, align);
+}
+
+int KScheduledListItem::compare(QListViewItem* i, int col, bool ascending) const
+{
+ KScheduledListItem* item = dynamic_cast<KScheduledListItem*>(i);
+ int rc;
+ // do special sorting only if
+ // a) date
+ // b) amount
+ // c) name/group
+ // d) occurence
+ // in all other cases use the standard sorting
+ MyMoneyMoney diff;
+ switch(col) {
+ case 0: // type and name
+ rc = m_sortKey.compare(item->m_sortKey);
+ break;
+
+ case 3: // amount
+ diff = m_amount - item->m_amount;
+ if(diff.isZero())
+ rc = 0;
+ else if(diff.isPositive())
+ rc = 1;
+ else
+ rc = -1;
+ break;
+
+ case 4: // date
+ rc = item->m_schedule.adjustedNextDueDate().daysTo(m_schedule.adjustedNextDueDate());
+ break;
+
+ case 5: // occurence
+ rc = (m_schedule.occurence() - item->m_schedule.occurence());
+ break;
+
+ default:
+ rc = KListViewItem::compare(i, col, ascending);
+ break;
+ }
+ // adjust to [-1..1]
+ if(rc != 0) {
+ rc = (rc > 0) ? 1 : -1;
+ }
+ return rc;
+}
diff --git a/kmymoney2/views/kscheduledlistitem.h b/kmymoney2/views/kscheduledlistitem.h
new file mode 100644
index 0000000..c5e4728
--- /dev/null
+++ b/kmymoney2/views/kscheduledlistitem.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ kscheduledlistitem.h - description
+ -------------------
+ begin : Sun Jan 27 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSCHEDULEDLISTITEM_H
+#define KSCHEDULEDLISTITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyscheduled.h>
+
+/**
+ * The list view item that describes a scheduled transaction.
+ *
+ * @author Michael Edwardes
+ */
+class KScheduledListItem : public KListViewItem
+{
+public:
+ /**
+ * This constructor is used to create a child of the main list view widget.
+ *
+ * The child should be a descriptor for the schedule type and one of
+ * Bill,
+ * Deposit or
+ * Transfer.
+ *
+ * Other types may be added in the future.
+ *
+ * @param parent The list view to be a child of.
+ * @param description The (translated) description.
+ * @param pixmap A pixmap for the entry
+ * @param sortKey a sortkey, if empty, @c description will be used.
+ *
+ * @see MyMoneySchedule
+ */
+ KScheduledListItem(KListView *parent, const QString& description, const QPixmap& pixmap = QPixmap(), const QString& sortKey = QString());
+
+ /**
+ * This constructor is used to create a child of one of the children
+ * created by the above method.
+ *
+ * This child describes a schedule and represents the data in schedule.
+ *
+ * @param parent The list view item to be a child of.
+ * @param schedule The schedule to be represented.
+ *
+ * @see MyMoneySchedule
+ */
+ KScheduledListItem(KScheduledListItem *parent, const MyMoneySchedule& schedule/*, bool even*/);
+
+ /**
+ * Standard destructor.
+ */
+ ~KScheduledListItem();
+
+ /**
+ * Returns the schedule id for the instance being represented. To be used
+ * selection slots by the view.
+ *
+ * Returns an empty string for the top level items.
+ *
+ * @return The schedule id.
+ */
+ const QString& scheduleId(void) const { return m_schedule.id(); }
+
+ int compare(QListViewItem* i, int col, bool ascending) const;
+
+protected:
+ void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+private:
+ MyMoneySchedule m_schedule;
+ QString m_sortKey;
+ MyMoneyMoney m_amount;
+};
+
+#endif
diff --git a/kmymoney2/views/kscheduledview.cpp b/kmymoney2/views/kscheduledview.cpp
new file mode 100644
index 0000000..42c09db
--- /dev/null
+++ b/kmymoney2/views/kscheduledview.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+ kscheduledview.cpp - description
+ -------------------
+ begin : Sun Jan 27 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qheader.h>
+#include <qtoolbutton.h>
+#include <qcombobox.h>
+#include <qtabwidget.h>
+#include <qlayout.h>
+#include <qtimer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <klistview.h>
+#include <kpushbutton.h>
+#include <klistviewsearchline.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kscheduledview.h"
+#include "kscheduledlistitem.h"
+#include "../widgets/kmymoneyscheduleddatetbl.h"
+// #include "../dialogs/kenterscheduledialog.h"
+#include <kmymoney/kmymoneyutils.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "../kmymoney2.h"
+
+KScheduledView::KScheduledView(QWidget *parent, const char *name ) :
+ KScheduledViewDecl(parent,name, false),
+ m_openBills(true),
+ m_openDeposits(true),
+ m_openTransfers(true),
+ m_openLoans(true)
+{
+ // create the searchline widget
+ // and insert it into the existing layout
+ m_searchWidget = new KListViewSearchLineWidget(m_qlistviewScheduled, m_listTab);
+ m_listTabLayout->insertWidget(0, m_searchWidget);
+
+ m_qlistviewScheduled->addColumn(i18n("Type/Name"));
+ m_qlistviewScheduled->addColumn(i18n("Account"));
+ m_qlistviewScheduled->addColumn(i18n("Payee"));
+ m_qlistviewScheduled->addColumn(i18n("Amount"));
+ m_qlistviewScheduled->addColumn(i18n("Next Due Date"));
+ m_qlistviewScheduled->addColumn(i18n("Frequency"));
+ m_qlistviewScheduled->addColumn(i18n("Payment Method"));
+ m_qlistviewScheduled->setColumnAlignment(3, Qt::AlignRight);
+
+ readConfig();
+
+ m_qlistviewScheduled->setMultiSelection(false);
+ m_qlistviewScheduled->header()->setResizeEnabled(true);
+ if(m_qlistviewScheduled->sortColumn() == -1)
+ m_qlistviewScheduled->setSorting(0);
+
+ connect(m_qbuttonNew, SIGNAL(clicked()), kmymoney2->action("schedule_new"), SLOT(activate()));
+
+ // attach popup to 'Filter...' button
+ m_kaccPopup = new KPopupMenu(this);
+ m_kaccPopup->setCheckable(true);
+ m_accountsCombo->setPopup(m_kaccPopup);
+ connect(m_kaccPopup, SIGNAL(activated(int)), this, SLOT(slotAccountActivated(int)));
+
+ m_qbuttonNew->setGuiItem(KMyMoneyUtils::scheduleNewGuiItem());
+ m_accountsCombo->setGuiItem(KMyMoneyUtils::accountsFilterGuiItem());
+
+ KIconLoader *il = KGlobal::iconLoader();
+ m_tabWidget->setTabIconSet(m_listTab, QIconSet(il->loadIcon("contents", KIcon::Small, KIcon::SizeSmall)));
+ m_tabWidget->setTabIconSet(m_calendarTab, QIconSet(il->loadIcon("calendartab", KIcon::User, KIcon::SizeSmall)));
+
+ connect(m_qlistviewScheduled, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT(slotListViewContextMenu(KListView*, QListViewItem*, const QPoint&)));
+ connect(m_qlistviewScheduled, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotSetSelectedItem(QListViewItem*)));
+
+ connect(m_qlistviewScheduled, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotListItemExecuted(QListViewItem*, const QPoint&, int)));
+ connect(m_qlistviewScheduled, SIGNAL(expanded(QListViewItem*)),
+ this, SLOT(slotListViewExpanded(QListViewItem*)));
+ connect(m_qlistviewScheduled, SIGNAL(collapsed(QListViewItem*)),
+ this, SLOT(slotListViewCollapsed(QListViewItem*)));
+
+ connect(m_calendar, SIGNAL(enterClicked(const MyMoneySchedule&, const QDate&)), this, SLOT(slotBriefEnterClicked(const MyMoneySchedule&, const QDate&)));
+ connect(m_calendar, SIGNAL(skipClicked(const MyMoneySchedule&, const QDate&)), this, SLOT(slotBriefSkipClicked(const MyMoneySchedule&, const QDate&)));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadView()));
+}
+
+KScheduledView::~KScheduledView()
+{
+ writeConfig();
+}
+
+void KScheduledView::refresh(bool full, const QString& schedId)
+{
+ m_qlistviewScheduled->header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
+
+ QPoint startPoint = QPoint(m_qlistviewScheduled->contentsX(), m_qlistviewScheduled->contentsY());
+
+ m_qlistviewScheduled->clear();
+
+ try
+ {
+ if (full)
+ {
+ try
+ {
+ int accountCount=0;
+
+ m_kaccPopup->clear();
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount acc;
+ QStringList::ConstIterator it_s;
+
+ acc = file->asset();
+ for(it_s = acc.accountList().begin(); it_s != acc.accountList().end(); ++it_s)
+ {
+ MyMoneyAccount a = file->account(*it_s);
+ m_kaccPopup->insertItem(a.name(), accountCount);
+ m_kaccPopup->setItemChecked(accountCount, true);
+ accountCount++;
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ KMessageBox::detailedError(this, i18n("Unable to load accounts: "), e->what());
+ delete e;
+ }
+ }
+
+ // Refresh the calendar view first
+ m_calendar->refresh();
+
+ MyMoneyFile *file = MyMoneyFile::instance();
+ QValueList<MyMoneySchedule> scheduledItems = file->scheduleList();
+
+ if (scheduledItems.count() == 0)
+ return;
+
+ KScheduledListItem *itemBills = new KScheduledListItem(m_qlistviewScheduled, i18n("Bills"), KMyMoneyUtils::billScheduleIcon(KIcon::Small), "0");
+ KScheduledListItem *itemDeposits = new KScheduledListItem(m_qlistviewScheduled, i18n("Deposits"), KMyMoneyUtils::depositScheduleIcon(KIcon::Small), "1");
+ KScheduledListItem *itemLoans = new KScheduledListItem(m_qlistviewScheduled, i18n("Loans"), KMyMoneyUtils::transferScheduleIcon(KIcon::Small), "2");
+ KScheduledListItem *itemTransfers = new KScheduledListItem(m_qlistviewScheduled, i18n("Transfers"), KMyMoneyUtils::transferScheduleIcon(KIcon::Small), "3");
+
+ QValueList<MyMoneySchedule>::Iterator it;
+
+ KScheduledListItem *openItem=0;
+
+ for (it = scheduledItems.begin(); it != scheduledItems.end(); ++it)
+ {
+ MyMoneySchedule schedData = (*it);
+ KScheduledListItem* item=0;
+
+ bool bContinue=true;
+ QStringList::iterator accIt;
+ for (accIt=m_filterAccounts.begin(); accIt!=m_filterAccounts.end(); ++accIt)
+ {
+ if (*accIt == schedData.account().id())
+ {
+ bContinue=false; // Filter it out
+ break;
+ }
+ }
+
+ if (!bContinue)
+ continue;
+
+ KScheduledListItem* parent = 0;
+ switch (schedData.type())
+ {
+ case MyMoneySchedule::TYPE_ANY:
+ // Should we display an error ?
+ // We just sort it as bill and fall through here
+
+ case MyMoneySchedule::TYPE_BILL:
+ parent = itemBills;
+ break;
+
+ case MyMoneySchedule::TYPE_DEPOSIT:
+ parent = itemDeposits;
+ break;
+
+ case MyMoneySchedule::TYPE_TRANSFER:
+ parent = itemTransfers;
+ break;
+
+ case MyMoneySchedule::TYPE_LOANPAYMENT:
+ parent = itemLoans;
+ break;
+
+ }
+ if(parent) {
+ if(!KMyMoneyGlobalSettings::hideFinishedSchedules() || !schedData.isFinished()) {
+ item = new KScheduledListItem(parent, schedData);
+ if (schedData.id() == schedId)
+ openItem = item;
+ }
+ }
+ }
+
+ if (openItem)
+ {
+ m_qlistviewScheduled->setSelected(openItem, true);
+ }
+ // using a timeout is the only way, I got the 'ensureTransactionVisible'
+ // working when coming from hidden form to visible form. I assume, this
+ // has something to do with the delayed update of the display somehow.
+ resize(width(), height()-1);
+ QTimer::singleShot(10, this, SLOT(slotTimerDone()));
+ m_qlistviewScheduled->update();
+
+ // force repaint in case the filter is set
+ m_searchWidget->searchLine()->updateSearch(QString::null);
+
+ if (m_openBills)
+ itemBills->setOpen(true);
+
+ if (m_openDeposits)
+ itemDeposits->setOpen(true);
+
+ if (m_openTransfers)
+ itemTransfers->setOpen(true);
+
+ if (m_openLoans)
+ itemLoans->setOpen(true);
+
+ m_qlistviewScheduled->setContentsPos(startPoint.x(), startPoint.y());
+
+ } catch (MyMoneyException *e)
+ {
+ KMessageBox::error(this, e->what());
+ delete e;
+ }
+}
+
+void KScheduledView::slotTimerDone(void)
+{
+ QListViewItem* item;
+
+ item = m_qlistviewScheduled->selectedItem();
+ if(item) {
+ m_qlistviewScheduled->ensureItemVisible(item);
+ }
+
+ // force a repaint of all items to update the branches
+ for(item = m_qlistviewScheduled->firstChild(); item != 0; item = item->itemBelow()) {
+ m_qlistviewScheduled->repaintItem(item);
+ }
+ resize(width(), height()+1);
+}
+
+void KScheduledView::slotReloadView(void)
+{
+ m_needReload = true;
+ if(isVisible()) {
+ m_qbuttonNew->setEnabled(true);
+ m_tabWidget->setEnabled(true);
+
+ refresh(true, m_selectedSchedule);
+
+ m_needReload = false;
+ QTimer::singleShot(50, this, SLOT(slotRearrange()));
+ }
+}
+
+void KScheduledView::show()
+{
+ KScheduledViewDecl::show();
+
+ if(m_needReload)
+ slotReloadView();
+}
+
+void KScheduledView::slotRearrange(void)
+{
+ resizeEvent(0);
+}
+
+void KScheduledView::readConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ m_openBills = config->readBoolEntry("KScheduleView_openBills", true);
+ m_openDeposits = config->readBoolEntry("KScheduleView_openDeposits", true);
+ m_openTransfers = config->readBoolEntry("KScheduleView_openTransfers", true);
+ m_openLoans = config->readBoolEntry("KScheduleView_openLoans", true);
+ m_tabWidget->setCurrentPage(config->readNumEntry("KScheduleView_tab", 0));
+
+ m_qlistviewScheduled->header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
+ m_qlistviewScheduled->restoreLayout(KGlobal::config(), "Schedule View Settings");
+
+}
+
+void KScheduledView::writeConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Last Use Settings");
+ config->writeEntry("KScheduleView_openBills", m_openBills);
+ config->writeEntry("KScheduleView_openDeposits", m_openDeposits);
+ config->writeEntry("KScheduleView_openTransfers", m_openTransfers);
+ config->writeEntry("KScheduleView_openLoans", m_openLoans);
+ config->writeEntry("KScheduleView_tab", m_tabWidget->currentPageIndex());
+ config->sync();
+
+ m_qlistviewScheduled->saveLayout(KGlobal::config(), "Schedule View Settings");
+}
+
+void KScheduledView::slotListViewContextMenu(KListView* /* view */, QListViewItem *item, const QPoint& /* pos */)
+{
+ KScheduledListItem *scheduleItem = dynamic_cast<KScheduledListItem *>(item);
+ if (scheduleItem)
+ {
+ try
+ {
+ QString scheduleId = scheduleItem->scheduleId();
+
+ if (!scheduleId.isEmpty()) // Top level item
+ {
+ MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(scheduleId);
+ emit scheduleSelected(schedule);
+ m_selectedSchedule = schedule.id();
+ }
+ emit openContextMenu();
+ } catch (MyMoneyException *e)
+ {
+ KMessageBox::detailedSorry(this, i18n("Error activating context menu"), e->what());
+ delete e;
+ }
+ }
+ else
+ {
+ emit openContextMenu();
+ }
+}
+
+void KScheduledView::slotListItemExecuted(QListViewItem* item, const QPoint&, int)
+{
+ KScheduledListItem* scheduleItem = (KScheduledListItem*)item;
+ if (!scheduleItem)
+ return;
+
+ try
+ {
+ QString scheduleId = scheduleItem->scheduleId();
+
+ if (!scheduleId.isEmpty()) // Top level item
+ {
+ MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(scheduleId);
+ m_selectedSchedule = schedule.id();
+ emit editSchedule();
+ }
+ } catch (MyMoneyException *e)
+ {
+ KMessageBox::detailedSorry(this, i18n("Error executing item"), e->what());
+ delete e;
+ }
+}
+
+void KScheduledView::slotAccountActivated(int id)
+{
+ m_filterAccounts.clear();
+
+ m_kaccPopup->setItemChecked(id, ((m_kaccPopup->isItemChecked(id))?false:true));
+
+ try
+ {
+ int accountCount=0;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ MyMoneyAccount acc;
+ QStringList::ConstIterator it_s;
+
+ acc = file->asset();
+ for(it_s = acc.accountList().begin(); it_s != acc.accountList().end(); ++it_s)
+ {
+ if (!m_kaccPopup->isItemChecked(accountCount))
+ {
+ m_filterAccounts.append(*it_s);
+ }
+ accountCount++;
+ }
+
+ m_calendar->setFilterAccounts(m_filterAccounts);
+
+ refresh(false, m_selectedSchedule);
+ }
+ catch (MyMoneyException *e)
+ {
+ KMessageBox::detailedError(this, i18n("Unable to filter account"), e->what());
+ delete e;
+ }
+}
+
+void KScheduledView::slotListViewExpanded(QListViewItem* item)
+{
+ KScheduledListItem *scheduleItem = (KScheduledListItem*)item;
+ if (scheduleItem)
+ {
+ if (scheduleItem->text(0) == i18n("Bills"))
+ m_openBills = true;
+ else if (scheduleItem->text(0) == i18n("Deposits"))
+ m_openDeposits = true;
+ else if (scheduleItem->text(0) == i18n("Transfers"))
+ m_openTransfers = true;
+ else if (scheduleItem->text(0) == i18n("Loans"))
+ m_openLoans = true;
+ }
+}
+
+void KScheduledView::slotListViewCollapsed(QListViewItem* item)
+{
+ KScheduledListItem *scheduleItem = (KScheduledListItem*)item;
+ if (scheduleItem)
+ {
+ if (scheduleItem->text(0) == i18n("Bills"))
+ m_openBills = false;
+ else if (scheduleItem->text(0) == i18n("Deposits"))
+ m_openDeposits = false;
+ else if (scheduleItem->text(0) == i18n("Transfers"))
+ m_openTransfers = false;
+ else if (scheduleItem->text(0) == i18n("Loans"))
+ m_openLoans = false;
+ }
+}
+
+void KScheduledView::slotSelectSchedule(const QString& schedule)
+{
+ refresh(true, schedule);
+}
+
+void KScheduledView::slotBriefEnterClicked(const MyMoneySchedule& schedule, const QDate& date)
+{
+ Q_UNUSED(date);
+
+ emit scheduleSelected(schedule);
+ emit enterSchedule();
+}
+
+void KScheduledView::slotBriefSkipClicked(const MyMoneySchedule& schedule, const QDate& date)
+{
+ Q_UNUSED(date);
+
+ emit scheduleSelected(schedule);
+ emit skipSchedule();
+}
+
+void KScheduledView::slotSetSelectedItem(QListViewItem* item)
+{
+ emit scheduleSelected(MyMoneySchedule());
+ KScheduledListItem* schedItem = static_cast<KScheduledListItem*>(item);
+ if(item) {
+ try {
+ MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(schedItem->scheduleId());
+ emit scheduleSelected(schedule);
+ m_selectedSchedule = schedItem->scheduleId();
+ } catch(MyMoneyException* e) {
+ qDebug("KScheduledView::slotSetSelectedItem: %s", e->what().data());
+ delete e;
+ }
+ }
+}
+
+
+#include "kscheduledview.moc"
diff --git a/kmymoney2/views/kscheduledview.h b/kmymoney2/views/kscheduledview.h
new file mode 100644
index 0000000..9eac41a
--- /dev/null
+++ b/kmymoney2/views/kscheduledview.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+ kscheduledview.h - description
+ -------------------
+ begin : Sun Jan 27 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KSCHEDULEDVIEW_H
+#define KSCHEDULEDVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qlistview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KListViewSearchLineWidget;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kscheduledviewdecl.h"
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyaccount.h>
+#include "../widgets/kmymoneyscheduledcalendar.h"
+
+class KPopupMenu;
+
+/**
+ * Contains all the scheduled transactions be they bills, deposits or transfers.
+ * Encapsulates all the operations including adding, editing and deleting.
+ * Used by the KMyMoneyView class to show the view.
+ *
+ * @author Michael Edwardes 2000-2002
+ * $Id: kscheduledview.h,v 1.33 2009/03/01 19:13:08 ipwizard Exp $
+ *
+ * @short A class to encapsulate recurring transaction operations.
+ */
+class KScheduledView : public KScheduledViewDecl
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Standard constructor for QWidgets.
+ */
+ KScheduledView(QWidget *parent=0, const char *name=0);
+
+ /**
+ * Standard destructor.
+ */
+ ~KScheduledView();
+
+ /**
+ * Called by KMyMoneyView.
+ */
+ void show();
+
+public slots:
+ void slotSelectSchedule(const QString& schedule);
+ void slotReloadView(void);
+
+signals:
+ void scheduleSelected(const MyMoneySchedule& schedule);
+ void openContextMenu(void);
+ void skipSchedule(void);
+ void enterSchedule(void);
+ void editSchedule(void);
+
+protected slots:
+ /**
+ * Shows the context menu when the user right clicks or presses
+ * a 'windows' key when an item is selected.
+ *
+ * @param view a pointer to the view
+ * @param item a pointer to the current selected listview item
+ * @param pos The position to popup
+ * @return none
+ **/
+ void slotListViewContextMenu(KListView* view, QListViewItem* item, const QPoint& pos);
+
+ void slotListItemExecuted(QListViewItem*, const QPoint&, int);
+
+ void slotAccountActivated(int);
+
+ void slotListViewCollapsed(QListViewItem* item);
+ void slotListViewExpanded(QListViewItem* item);
+
+ void slotBriefSkipClicked(const MyMoneySchedule& schedule, const QDate&);
+ void slotBriefEnterClicked(const MyMoneySchedule& schedule, const QDate&);
+
+ void slotTimerDone(void);
+
+ void slotSetSelectedItem(QListViewItem* item);
+
+ void slotRearrange(void);
+
+private:
+ /// The selected schedule id in the list view.
+ QString m_selectedSchedule;
+
+ /// Read config file
+ void readConfig(void);
+
+ /// Write config file
+ void writeConfig(void);
+
+ /**
+ * Refresh the view.
+ */
+ void refresh(bool full=true, const QString& schedId = QString());
+
+ /**
+ * Loads the accounts into the combo box.
+ */
+// void loadAccounts(void);
+
+ KPopupMenu *m_kaccPopup;
+ QStringList m_filterAccounts;
+ bool m_openBills;
+ bool m_openDeposits;
+ bool m_openTransfers;
+ bool m_openLoans;
+ bool m_needReload;
+
+ /**
+ * Search widget for the list
+ */
+ KListViewSearchLineWidget* m_searchWidget;
+};
+
+#endif
diff --git a/kmymoney2/views/kscheduledviewdecl.ui b/kmymoney2/views/kscheduledviewdecl.ui
new file mode 100644
index 0000000..faa3fe8
--- /dev/null
+++ b/kmymoney2/views/kscheduledviewdecl.ui
@@ -0,0 +1,161 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KScheduledViewDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KScheduledViewDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>620</width>
+ <height>399</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_qbuttonNew</cstring>
+ </property>
+ <property name="text">
+ <string>New Scheduled transaction...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_accountsCombo</cstring>
+ </property>
+ <property name="text">
+ <string>Filter Accounts</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_listTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>List View</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KListView">
+ <property name="name">
+ <cstring>m_qlistviewScheduled</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="showSortIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ <property name="shadeSortColumn">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_calendarTab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Calendar View</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyScheduledCalendar">
+ <property name="name">
+ <cstring>m_calendar</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>kMyMoneyScheduledCalendar</class>
+ <header location="local">../widgets/kmymoneyscheduledcalendar.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="824">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000002ff49444154388db59531681c4714863f992dde820cb370815b50600f54e8ca0ba43970712a8fb838438a3895634813d238a5ab80e314ae4d0a812060a4226017c27221c8a9da6b8c4fe0e00d28b0571cec82043b85611f78c12966efa4bb8bc085f29a6567df7cef9f7fdeccaec571cc2cbaddee47ae21e2385e5b9b815f1ebcfcd8de6a63ad25cb338af7c52741acb5a4a729a3d723a82ec6bd99d267bf3f23fc1c4cab2442d14a915986e792fdfa59569766573049417784f1b12e8267954dab24b78714450a28beaf941f847c2a14e70a0841035a2d45d641eb027213c210c69756320767794684d6508bef0befde1a860796e4c402333542b4256c0f0cdd1e50b97191458be6e0e27d81563a87c643d8fb2d7793d685d696413cc8a6cae46f65f7d79c7c62b87b4f2e15fd0fb0d302be0fefde4a0d557a5f35e90f84e0334014d590f855c9de4ecee17e4eb319d1ff3a00ec02f8c67299f283307c61e7d06fbf1782d082588a33e1cf1705fd81cf773f3601e1f9bec59e2f4b5c7ef5209f0ac95f16630cfd818067c103b586dd274a726229cee0fe8380d191cb4d1267d3d58aa1de7d258ceae5d7d0a78fdd269a86f0c52d414c49bbe3762c9b686de41560d7a72e41c4795a6486a78f95e4c4151481d686efbe7b3398ac58b1a23868b8c474aaa8068c8e714a8dd06c1af2a9e5d1c38c641c909dba6e08237f19b358a7ac5cf3479bc2e41f257e55d2ffc6a73833746f09e186cfa387904f2cbffc90a2aa9886d0e99464d3c5965b512cebd01f1800f67672e2a392fb0f023a3d883a053ffddcc2340dd65ab452b6074dc2cd15c1cbceb863daed413e353cdfcfd97d92333a12da6d0181ec3443cf753ef3cdd092de0e116ff1a02cdc157338ca9d7b8269461cfee1ba2139b9286e1a427f10110f2d561555b076d18a39383d4d99a4c0cd0b787f20747b214962c8266e3cdcf0e97c59126ec2f6edd089f40a92f115e0d1eb11ba238461dd6a15f32b53666de841965bb203575a3cc15a48c64a965fe57105e3635db8fa96dcffc431172b5d715d7103dc3fea7f015f373c8ee3b57f0135105a0fae7717960000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/Makefile.am b/kmymoney2/widgets/Makefile.am
new file mode 100644
index 0000000..51fa159
--- /dev/null
+++ b/kmymoney2/widgets/Makefile.am
@@ -0,0 +1,95 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+
+noinst_LIBRARIES = libwidgets.a
+
+libwidgets_a_METASOURCES = AUTO
+
+libwidgets_a_SOURCES = kbudgetvalues.cpp kbudgetvaluesdecl.ui kguiutils.cpp klistviewsearchline.cpp kmymoneyaccountcombo.cpp kmymoneyaccountcompletion.cpp kmymoneyaccountselector.cpp kmymoneyaccounttreebase.cpp kmymoneyaccounttree.cpp kmymoneyaccounttreebudget.cpp kmymoneyaccounttreeforecast.cpp kmymoneybriefschedule.cpp kmymoneycalculator.cpp kmymoneycalendar.cpp kmymoneycategory.cpp kmymoneychecklistitem.cpp kmymoneycombo.cpp kmymoneycompletion.cpp kmymoneycurrencyselector.cpp kmymoneydateinput.cpp kmymoneydatetbl.cpp kmymoneyedit.cpp kmymoneyforecastlistviewitem.cpp kmymoneygpgconfig.cpp kmymoneygpgconfigdecl.ui kmymoneylineedit.cpp kmymoneylistviewitem.cpp kmymoneyonlinequoteconfig.cpp kmymoneyonlinequoteconfigdecl.ui kmymoneypriceview.cpp kmymoneyreportconfigtab1decl.ui kmymoneyreportconfigtab2decl.ui kmymoneyreportconfigtab3decl.ui kmymoneyreportconfigtabchartdecl.ui kmymoneyreportcontroldecl.ui kmymoneyscheduledcalendar.cpp kmymoneyscheduleddatetbl.cpp kmymoneyselector.cpp kmymoneytitlelabel.cpp kmymoneywizard.cpp kschedulebriefwidget.ui register.cpp registeritem.cpp registersearchline.cpp transaction.cpp scheduledtransaction.cpp stdtransactiondownloaded.cpp stdtransactionmatched.cpp transactioneditorcontainer.cpp transactionform.cpp kaccounttemplateselectordecl.ui kaccounttemplateselector.cpp \
+transactionsortoption.cpp transactionsortoption.ui \
+selectedtransaction.cpp
+
+#libwidgets_a_SOURCES = kmymoneyregisterinvestment.cpp kmymoneyequity.cpp kmymoneyequitycompletion.cpp kmymoneycompletion.cpp kmymoneyequityselector.cpp kmymoneyaccountcombo.cpp kmymoneyaccountcompletion.cpp kmymoneycurrencyselector.cpp kmymoneypriceview.cpp kmymoneypriceviewdecl.ui kschedulebriefwidget.ui kmymoneyaccountselector.cpp kmymoneyregisterloan.cpp kmymoneyregistersearch.cpp kmymoneybriefschedule.cpp kmymoneyscheduleddatetbl.cpp kmymoneydatetbl.cpp kmymoneyscheduledcalendar.cpp kmymoneycalendar.cpp kmymoneycalculator.cpp kmymoneycategory.cpp kmymoneypayee.cpp kmymoneytransactionform.cpp kmymoneyregistercheckings.cpp kmymoneyregister.cpp kmymoneycombo.cpp kmymoneyhlayout.cpp kmymoneylineedit.cpp kmymoneyedit.cpp kmymoneydateinput.cpp kmymoneyreportcontroldecl.ui kmymoneyreportconfigtab1decl.ui kmymoneyreportconfigtab2decl.ui kmymoneyreportconfigtab3decl.ui kmymoneyreportconfigtabchartdecl.ui kmymoneyonlinequoteconfig.cpp kmymoneyonlinequoteconfigdecl.ui kmymoneyaccounttree.cpp kmymoneygpgconfigdecl.ui kmymoneygpgconfig.cpp kmymoneytitlelabel.cpp kguiutils.cpp kmymoneywizard.cpp kmymoneyaccounttreebudget.cpp kmymoneyaccounttreeforecast.cpp \
+#register.cpp registeritem.cpp transaction.cpp transactionform.cpp transactioneditor.cpp transactioneditorcontainer.cpp kmymoneychecklistitem.cpp kmymoneylistviewitem.cpp kmymoneyforecastlistviewitem.cpp kmymoneyselector.cpp \
+#transactionsortoption.ui
+
+EXTRA_DIST = kmymoney.widgets kmymoneygpgconfigdecl.ui kmymoneyonlinequoteconfigdecl.ui kmymoneyreportconfigtab1decl.ui kmymoneyreportconfigtab2decl.ui kmymoneyreportconfigtab3decl.ui kmymoneyreportcontroldecl.ui kschedulebriefwidget.ui kmymoneyreportconfigtabchartdecl.ui transactionsortoption.ui transactionsortoption.ui.h sortoptionlistitem.h makekdewidgets.in kbudgetvaluesdecl.ui kaccounttemplateselectordecl.ui
+
+# include the widgets that are available to 3rd party sw (e.g. plugins or
+# Qt designer) here
+# Note: The autogenerated file(s) are kept on a separate line so that no
+# symbolic link is created during configure time (see configure.in.in)
+# but the file is included in the tar-ball. See also the separate target
+# $(top_builddir)/kmymoney/xxx.h further down and the BUILT_SOURCES target.
+instdir=$(includedir)/kmymoney
+inst_HEADERS = kmymoneydateinput.h kmymoneyedit.h kmymoneytitlelabel.h kmymoneyaccountselector.h kmymoneycategory.h kmymoneyaccounttreebase.h kmymoneyaccounttree.h kmymoneycurrencyselector.h kguiutils.h kmymoneywizard.h kmymoneyaccounttreebudget.h kmymoneyaccounttreeforecast.h kmymoneyaccountcombo.h register.h registeritem.h transaction.h scheduledtransaction.h stdtransactiondownloaded.h stdtransactionmatched.h selectedtransaction.h transactionform.h transactioneditorcontainer.h kmymoneylineedit.h kmymoneychecklistitem.h kmymoneylistviewitem.h kmymoneyforecastlistviewitem.h kmymoneyselector.h kmymoneyaccountcompletion.h kmymoneycompletion.h kmymoneycombo.h kbudgetvalues.h kaccounttemplateselector.h \
+ transactionsortoption.h
+
+# include the widgets that are only available to KMyMoney here
+noinst_HEADERS = kbudgetvalues.h klistviewsearchline.h kmymoneyaccounttree.h \
+ kmymoneyaccounttreebudget.h kmymoneyaccounttreeforecast.h kmymoneybriefschedule.h kmymoneycalculator.h kmymoneycalendar.h \
+ kmymoneycategory.h kmymoneydatetbl.h kmymoneygpgconfig.h kmymoneyonlinequoteconfig.h \
+ kmymoneypriceview.h kmymoneyscheduledcalendar.h kmymoneyscheduleddatetbl.h \
+ kmymoneywizard_p.h registersearchline.h
+
+# make sure, automatically generated files exist
+BUILT_SOURCES = settings $(top_builddir)/kmymoney/transactionsortoption.h mocs dialogs transactionsortoption.cpp kbudgetvaluesdecl.h kaccounttemplateselectordecl.h libkmymoney.la kmmwidgets.cpp
+
+CLEANFILES = kmmwidgets.cpp
+
+.PHONY: dialogs settings
+dialogs:
+ $(MAKE) -C ../dialogs kcurrencycalculatordecl.h
+
+settings:
+ $(MAKE) -C .. kmymoneysettings.h
+
+# we have to make sure, that the symbolic link exists
+$(top_builddir)/kmymoney/transactionsortoption.h: transactionsortoption.h
+ if test -h $@; then rm $@; fi
+ ln -s `pwd`/transactionsortoption.h $@
+
+PICS_DIR=kmymoney2/pics
+WIDGET_PNGS = kmymoneytitlelabel.png
+
+libkmymoney_la_SOURCES = kmmwidgets.cpp ../kmymoneysettings.cpp kmymoneycompletion.cpp kmymoneyaccountcombo.cpp kmymoneyaccountcompletion.cpp kmymoneycurrencyselector.cpp kmymoneyaccountselector.cpp kmymoneydatetbl.cpp kmymoneycalculator.cpp kmymoneycategory.cpp kmymoneycombo.cpp kmymoneylineedit.cpp kmymoneyedit.cpp kmymoneydateinput.cpp kmymoneyaccounttree.cpp kmymoneytitlelabel.cpp kguiutils.cpp kmymoneyaccounttreebase.cpp kmymoneyaccounttreebudget.cpp kmymoneyaccounttreeforecast.cpp register.cpp registeritem.cpp transaction.cpp scheduledtransaction.cpp stdtransactiondownloaded.cpp stdtransactionmatched.cpp transactionform.cpp kmymoneychecklistitem.cpp kmymoneylistviewitem.cpp kmymoneyselector.cpp transactionsortoption.cpp kbudgetvalues.cpp kbudgetvaluesdecl.cpp kaccounttemplateselector.cpp kaccounttemplateselectordecl.cpp
+
+noinst_LTLIBRARIES = libkmymoney.la
+
+kmmwidgets.cpp: $(srcdir)/kmymoney.widgets
+ chmod +x makekdewidgets
+ ./makekdewidgets -g KMyMoney -n CustomWidgetPlugin -o kmmwidgets.cpp -i kmymoney $(abs_srcdir)/kmymoney.widgets
+
+# make sure to compile the Qt designer version w/o the memory leak checker
+# also we need a copy of the mymoneymoney.lo file which has been compiled
+# already. This is a quick hack around a bootstrap problem. We could link
+# the libkmymoney.so against libkmm_mymoney.so but this is not yet installed
+# but required to let UIC generate the right code for the dialogs and views.
+# Hence the quick hack to include the required objects from the
+# libkmm_mymoney.so directly into libkmymoney.so
+libkmymoney_la_CXXFLAGS = -U_CHECK_MEMORY -DKMM_DESIGNER
+libkmymoney_la_LDFLAGS = `ls ../mymoney/*.lo` $(KDE_LDFLAGS) $(QT_LDFLAGS) $(X_LDFLAGS) -rpath $(DESTDIR)$(qt_libraries)/../plugins/designer $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT)
+
+if INSTALL_QTDESIGNER_SUPPORT
+install-exec-local: libkmymoney.la
+ $(mkinstalldirs) $(DESTDIR)$(qt_libraries)/../plugins/designer
+ $(INSTALL_PROGRAM) .libs/libkmymoney.so $(DESTDIR)$(qt_libraries)/../plugins/designer
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/$(PICS_DIR)
+ for file in $(WIDGET_PNGS); do \
+ $(INSTALL_DATA) $(abs_srcdir)/$$file $(DESTDIR)$(kde_datadir)/$(PICS_DIR); \
+ done
+
+uninstall-local:
+ -rm $(DESTDIR)$(qt_libraries)/../plugins/designer/libkmymoney.so
+ for file in $(WIDGET_PNGS); do \
+ rm -rf $(DESTDIR)$(kde_datadir)/$(PICS_DIR)/$$file; \
+ done
+endif
+
+dist-hook:
+ -rm -rf $(distdir)/transactionsortoption.h
+ -rm -rf $(distdir)/transactionsortoption.cpp
+ -rm -rf $(distdir)/kmmwidgets.cpp
+
+messages: rc.cpp
diff --git a/kmymoney2/widgets/kaccounttemplateselector.cpp b/kmymoney2/widgets/kaccounttemplateselector.cpp
new file mode 100644
index 0000000..8ba6f0a
--- /dev/null
+++ b/kmymoney2/widgets/kaccounttemplateselector.cpp
@@ -0,0 +1,279 @@
+/***************************************************************************
+ kaccounttemplateselector.cpp - description
+ -------------------
+ begin : Tue Feb 5 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdir.h>
+#include <qheader.h>
+#include <qtimer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <klistview.h>
+#include <ktextedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytemplate.h>
+
+#include "kaccounttemplateselector.h"
+
+class KTemplateListItem : public KListViewItem
+{
+ public:
+ KTemplateListItem(QListViewItem* parent, const QString& text);
+ void setAvailable(void);
+ public:
+ bool m_isAvailable;
+};
+
+KTemplateListItem::KTemplateListItem(QListViewItem* parent, const QString& text) :
+ KListViewItem(parent, text),
+ m_isAvailable(false)
+{
+}
+
+void KTemplateListItem::setAvailable(void)
+{
+ m_isAvailable = true;
+}
+
+class KAccountTemplateSelector::Private
+{
+ public:
+ Private(KAccountTemplateSelector* p) { m_parent = p; }
+#ifndef KMM_DESIGNER
+ QValueList<MyMoneyTemplate> selectedTemplates(void) const;
+ QListViewItem* hierarchyItem(const QString& parent, const QString& name);
+ void loadHierarchy(void);
+#endif
+
+ public:
+ KAccountTemplateSelector* m_parent;
+ QMap<QString, QListViewItem*> m_templateHierarchy;
+#ifndef KMM_DESIGNER
+ QMap<QString, MyMoneyTemplate> m_templates;
+ QMap<QString, QString> countries;
+ QMap<QString, QString>::iterator it_m;
+ QStringList dirlist;
+ int id;
+#endif
+};
+
+
+#ifndef KMM_DESIGNER
+QListViewItem* KAccountTemplateSelector::Private::hierarchyItem(const QString& parent, const QString& name)
+{
+ if(!m_templateHierarchy.contains(parent)
+ || m_templateHierarchy[parent] == 0) {
+ QRegExp exp("(.*):(.*)");
+ if(exp.search(parent) != -1)
+ m_templateHierarchy[parent] = hierarchyItem(exp.cap(1), exp.cap(2));
+ }
+ return new KTemplateListItem(m_templateHierarchy[parent], name);
+}
+
+void KAccountTemplateSelector::Private::loadHierarchy(void)
+{
+ m_templateHierarchy.clear();
+ QListViewItemIterator it(m_parent->m_groupList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ while((it_v = it.current()) != 0) {
+ m_templates[it_v->text(2)].hierarchy(m_templateHierarchy);
+ ++it;
+ }
+
+ // I need to think about this some more. The code works and shows
+ // the current account hierarchy. It might be usefull, to show
+ // existing accounts dimmed and the new ones in bold or so.
+#if 0
+
+ // add the hierarchy from the MyMoneyFile object
+ QValueList<MyMoneyAccount> aList;
+ QValueList<MyMoneyAccount>::const_iterator it_a;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ file->accountList(aList);
+ if(aList.count() > 0) {
+ m_templateHierarchy[file->accountToCategory(file->asset().id(), true)] = 0;
+ m_templateHierarchy[file->accountToCategory(file->liability().id(), true)] = 0;
+ m_templateHierarchy[file->accountToCategory(file->income().id(), true)] = 0;
+ m_templateHierarchy[file->accountToCategory(file->expense().id(), true)] = 0;
+ m_templateHierarchy[file->accountToCategory(file->equity().id(), true)] = 0;
+ }
+
+ for(it_a = aList.begin(); it_a != aList.end(); ++it_a) {
+ m_templateHierarchy[file->accountToCategory((*it_a).id(), true)] = 0;
+ }
+#endif
+
+ m_parent->m_accountList->clear();
+ QMap<QString, QListViewItem*>::iterator it_m;
+
+ QRegExp exp("(.*):(.*)");
+ for(it_m = m_templateHierarchy.begin(); it_m != m_templateHierarchy.end(); ++it_m) {
+ if(exp.search(it_m.key()) == -1) {
+ (*it_m) = new KListViewItem(m_parent->m_accountList, it_m.key());
+ } else {
+ (*it_m) = hierarchyItem(exp.cap(1), exp.cap(2));
+ }
+ (*it_m)->setOpen(true);
+ }
+
+ m_parent->m_description->clear();
+ if(m_parent->m_groupList->currentItem()) {
+ m_parent->m_description->setText(m_templates[m_parent->m_groupList->currentItem()->text(2)].longDescription());
+ }
+}
+
+QValueList<MyMoneyTemplate> KAccountTemplateSelector::Private::selectedTemplates(void) const
+{
+ QValueList<MyMoneyTemplate> list;
+ QListViewItemIterator it(m_parent->m_groupList, QListViewItemIterator::Selected);
+ QListViewItem* it_v;
+ while((it_v = it.current()) != 0) {
+ list << m_templates[it_v->text(2)];
+ ++it;
+ }
+ return list;
+}
+#endif
+
+
+KAccountTemplateSelector::KAccountTemplateSelector(QWidget* parent, const char* name) :
+ KAccountTemplateSelectorDecl(parent, name),
+ d(new Private(this))
+{
+ m_accountList->header()->hide();
+ connect(m_groupList, SIGNAL(selectionChanged()), this, SLOT(slotLoadHierarchy()));
+
+ // kick off loading of account template data
+ QTimer::singleShot(0, this, SLOT(slotLoadTemplateList()));
+}
+
+KAccountTemplateSelector::~KAccountTemplateSelector()
+{
+ delete d;
+}
+
+void KAccountTemplateSelector::slotLoadTemplateList(void)
+{
+#ifndef KMM_DESIGNER
+ QStringList dirs;
+ // get list of template subdirs and scan them for the list of subdirs
+ d->dirlist = KGlobal::dirs()->findDirs("appdata", "templates");
+ QStringList::iterator it;
+ for(it = d->dirlist.begin(); it != d->dirlist.end(); ++it) {
+ QDir dir(*it);
+ // qDebug("Reading dir '%s' with %d entries", (*it).data(), dir.count());
+ dirs = dir.entryList("*", QDir::Dirs);
+ QStringList::iterator it_d;
+ for(it_d= dirs.begin(); it_d != dirs.end(); ++it_d) {
+ // we don't care about . and ..
+ if((*it_d) == ".." || (*it_d) == "." || (*it_d) == "C")
+ continue;
+ QRegExp exp("(..)_(..)");
+ if(exp.search(*it_d) != -1) {
+ QString country = KGlobal::locale()->twoAlphaToCountryName(exp.cap(2));
+ if(country.isEmpty())
+ country = exp.cap(2);
+ QString lang = KGlobal::locale()->twoAlphaToLanguageName(exp.cap(1));
+ if(d->countries.contains(country)) {
+ if(d->countries[country] != *it_d) {
+ QString oName = d->countries[country];
+ exp.search(oName);
+ QString oCountry = KGlobal::locale()->twoAlphaToCountryName(exp.cap(2));
+ QString oLang = KGlobal::locale()->twoAlphaToLanguageName(exp.cap(1));
+ d->countries.remove(country);
+ d->countries[QString("%1 (%2)").arg(oCountry).arg(oLang)] = oName;
+ d->countries[QString("%1 (%2)").arg(country).arg(lang)] = *it_d;
+ }
+ } else {
+ d->countries[country] = *it_d;
+ }
+ } else if((*it_d).length() == 2) {
+ QString country = KGlobal::locale()->twoAlphaToCountryName((*it_d).upper());
+ d->countries[country] = *it_d;
+ } else {
+ qDebug("'%s/%s' not scanned", (*it).data(), (*it_d).data());
+ }
+ }
+ }
+
+ // now that we know, what we can get at max, we scan everything
+ // and parse the templates into memory
+ m_groupList->clear();
+ d->m_templates.clear();
+ d->it_m = d->countries.begin();
+ d->id = 1;
+ QTimer::singleShot(0, this, SLOT(slotLoadCountry()));
+#endif
+}
+
+void KAccountTemplateSelector::slotLoadCountry(void)
+{
+#ifndef KMM_DESIGNER
+
+ KListViewItem* parent = new KListViewItem(m_groupList, d->it_m.key());
+ parent->setSelectable(false);
+ QStringList::iterator it;
+ for(it = d->dirlist.begin(); it != d->dirlist.end(); ++it) {
+ QStringList::iterator it_f;
+ QDir dir(QString("%1%2").arg(*it).arg(*(d->it_m)));
+ if(dir.exists()) {
+ QStringList files = dir.entryList("*", QDir::Files);
+ for(it_f = files.begin(); it_f != files.end(); ++it_f) {
+ MyMoneyTemplate templ(QString("%1/%2").arg(dir.canonicalPath()).arg(*it_f));
+ d->m_templates[QString("%1").arg(d->id)] = templ;
+ new KListViewItem(parent, templ.title(), templ.shortDescription(), QString("%1").arg(d->id));
+ ++d->id;
+ }
+ }
+ }
+
+ ++d->it_m;
+ if(d->it_m != d->countries.end())
+ QTimer::singleShot(0, this, SLOT(slotLoadCountry()));
+ else {
+ d->loadHierarchy();
+ }
+#endif
+
+}
+
+void KAccountTemplateSelector::slotLoadHierarchy(void)
+{
+#ifndef KMM_DESIGNER
+ d->loadHierarchy();
+#endif
+}
+
+QValueList<MyMoneyTemplate> KAccountTemplateSelector::selectedTemplates(void) const
+{
+#ifndef KMM_DESIGNER
+ return d->selectedTemplates();
+#else
+ return QValueList<MyMoneyTemplate>();
+#endif
+}
+
+#include "kaccounttemplateselector.moc"
diff --git a/kmymoney2/widgets/kaccounttemplateselector.h b/kmymoney2/widgets/kaccounttemplateselector.h
new file mode 100644
index 0000000..df2c3fd
--- /dev/null
+++ b/kmymoney2/widgets/kaccounttemplateselector.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ kaccounttemplateselector.h - description
+ -------------------
+ begin : Tue Feb 5 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KACCOUNTTEMPLATESELECTOR_H
+#define KACCOUNTTEMPLATESELECTOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney2/widgets/kaccounttemplateselectordecl.h>
+class MyMoneyTemplate;
+
+/**
+ * @author Thomas Baumgart <ipwizard@users.sourceforge.net>
+ */
+class KAccountTemplateSelector : public KAccountTemplateSelectorDecl
+{
+ Q_OBJECT
+ public:
+ KAccountTemplateSelector(QWidget* parent = 0, const char* name = 0);
+ ~KAccountTemplateSelector();
+
+ QValueList<MyMoneyTemplate> selectedTemplates(void) const;
+
+ private slots:
+ void slotLoadHierarchy(void);
+ void slotLoadCountry(void);
+ void slotLoadTemplateList(void);
+
+ private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kaccounttemplateselectordecl.cpp b/kmymoney2/widgets/kaccounttemplateselectordecl.cpp
new file mode 100644
index 0000000..8fed754
--- /dev/null
+++ b/kmymoney2/widgets/kaccounttemplateselectordecl.cpp
@@ -0,0 +1,111 @@
+#include <kdialog.h>
+#include <klocale.h>
+#ifndef KMM_I18N
+#define KMM_I18N
+inline QString kmm_i18n(const char* msg, const char* ctx) { return i18n(ctx, msg); }
+inline QString kmm_i18n(const char* msg) { return i18n(msg); }
+#endif
+/****************************************************************************
+** Form implementation generated from reading ui file '../../../kmymoney2/widgets/kaccounttemplateselectordecl.ui'
+**
+** Created: Fri Feb 12 15:05:39 2010
+**
+** WARNING! All changes made in this file will be lost!
+****************************************************************************/
+
+#include "kaccounttemplateselectordecl.h"
+
+#include <qvariant.h>
+#include <qpushbutton.h>
+#include <qheader.h>
+#include <klistview.h>
+#include <qgroupbox.h>
+#include <ktextedit.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+/*
+ * Constructs a KAccountTemplateSelectorDecl as a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'.
+ */
+KAccountTemplateSelectorDecl::KAccountTemplateSelectorDecl( QWidget* parent, const char* name, WFlags fl )
+ : QWidget( parent, name, fl )
+{
+ if ( !name )
+ setName( "KAccountTemplateSelectorDecl" );
+ KAccountTemplateSelectorDeclLayout = new QVBoxLayout( this, 0, 6, "KAccountTemplateSelectorDeclLayout");
+
+ m_groupList = new KListView( this, "m_groupList" );
+ m_groupList->addColumn( kmm_i18n( "Account Types" ) );
+ m_groupList->addColumn( kmm_i18n( "Description" ) );
+ m_groupList->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, 0, 0, m_groupList->sizePolicy().hasHeightForWidth() ) );
+ m_groupList->setMinimumSize( QSize( 0, 150 ) );
+ m_groupList->setProperty( "selectionMode", "Extended" );
+ m_groupList->setAllColumnsShowFocus( TRUE );
+ m_groupList->setRootIsDecorated( TRUE );
+ m_groupList->setFullWidth( TRUE );
+ KAccountTemplateSelectorDeclLayout->addWidget( m_groupList );
+
+ layout3 = new QHBoxLayout( 0, 0, 6, "layout3");
+
+ groupBox1 = new QGroupBox( this, "groupBox1" );
+ groupBox1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 0, 2, groupBox1->sizePolicy().hasHeightForWidth() ) );
+ groupBox1->setColumnLayout(0, Qt::Vertical );
+ groupBox1->layout()->setSpacing( 6 );
+ groupBox1->layout()->setMargin( 11 );
+ groupBox1Layout = new QVBoxLayout( groupBox1->layout() );
+ groupBox1Layout->setAlignment( Qt::AlignTop );
+
+ m_description = new KTextEdit( groupBox1, "m_description" );
+ m_description->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, 0, 3, m_description->sizePolicy().hasHeightForWidth() ) );
+ m_description->setReadOnly( TRUE );
+ groupBox1Layout->addWidget( m_description );
+ layout3->addWidget( groupBox1 );
+
+ groupBox2 = new QGroupBox( this, "groupBox2" );
+ groupBox2->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 1, 2, groupBox2->sizePolicy().hasHeightForWidth() ) );
+ groupBox2->setColumnLayout(0, Qt::Vertical );
+ groupBox2->layout()->setSpacing( 6 );
+ groupBox2->layout()->setMargin( 11 );
+ groupBox2Layout = new QVBoxLayout( groupBox2->layout() );
+ groupBox2Layout->setAlignment( Qt::AlignTop );
+
+ m_accountList = new KListView( groupBox2, "m_accountList" );
+ m_accountList->addColumn( kmm_i18n( "Name" ) );
+ m_accountList->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, 0, 3, m_accountList->sizePolicy().hasHeightForWidth() ) );
+ m_accountList->setMinimumSize( QSize( 0, 150 ) );
+ m_accountList->setProperty( "selectionMode", "NoSelection" );
+ m_accountList->setAllColumnsShowFocus( TRUE );
+ m_accountList->setRootIsDecorated( TRUE );
+ m_accountList->setFullWidth( TRUE );
+ groupBox2Layout->addWidget( m_accountList );
+ layout3->addWidget( groupBox2 );
+ KAccountTemplateSelectorDeclLayout->addLayout( layout3 );
+ languageChange();
+ resize( QSize(546, 346).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KAccountTemplateSelectorDecl::~KAccountTemplateSelectorDecl()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+/*
+ * Sets the strings of the subwidgets using the current
+ * language.
+ */
+void KAccountTemplateSelectorDecl::languageChange()
+{
+ m_groupList->header()->setLabel( 0, kmm_i18n( "Account Types" ) );
+ m_groupList->header()->setLabel( 1, kmm_i18n( "Description" ) );
+ groupBox1->setTitle( kmm_i18n( "Detailed description" ) );
+ groupBox2->setTitle( kmm_i18n( "Accounts" ) );
+ m_accountList->header()->setLabel( 0, kmm_i18n( "Name" ) );
+}
+
+#include "kaccounttemplateselectordecl.moc"
diff --git a/kmymoney2/widgets/kaccounttemplateselectordecl.ui b/kmymoney2/widgets/kaccounttemplateselectordecl.ui
new file mode 100644
index 0000000..6ed4b6d
--- /dev/null
+++ b/kmymoney2/widgets/kaccounttemplateselectordecl.ui
@@ -0,0 +1,188 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAccountTemplateSelectorDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAccountTemplateSelectorDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>546</width>
+ <height>346</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Account Types</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_groupList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>Extended</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>2</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Detailed description</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>m_description</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>3</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>2</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Accounts</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_accountList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>3</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>NoSelection</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kbudgetvalues.cpp b/kmymoney2/widgets/kbudgetvalues.cpp
new file mode 100644
index 0000000..2d6c2d7
--- /dev/null
+++ b/kmymoney2/widgets/kbudgetvalues.cpp
@@ -0,0 +1,341 @@
+/***************************************************************************
+ kbudgetvalues - description
+ -------------------
+ begin : Wed Nov 28 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtabwidget.h>
+#include <qlabel.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qwidgetstack.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcalendarsystem.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kbudgetvalues.h"
+#include <kmymoney/kmymoneyedit.h>
+
+KBudgetValues::KBudgetValues(QWidget* parent, const char* name) :
+ KBudgetValuesDecl(parent, name),
+ m_currentTab(m_monthlyButton)
+{
+ m_budgetDate = QDate(2007,1,1);
+
+ m_field[0] = m_amount1;
+ m_field[1] = m_amount2;
+ m_field[2] = m_amount3;
+ m_field[3] = m_amount4;
+ m_field[4] = m_amount5;
+ m_field[5] = m_amount6;
+ m_field[6] = m_amount7;
+ m_field[7] = m_amount8;
+ m_field[8] = m_amount9;
+ m_field[9] = m_amount10;
+ m_field[10] = m_amount11;
+ m_field[11] = m_amount12;
+
+ m_label[0] = m_label1;
+ m_label[1] = m_label2;
+ m_label[2] = m_label3;
+ m_label[3] = m_label4;
+ m_label[4] = m_label5;
+ m_label[5] = m_label6;
+ m_label[6] = m_label7;
+ m_label[7] = m_label8;
+ m_label[8] = m_label9;
+ m_label[9] = m_label10;
+ m_label[10] = m_label11;
+ m_label[11] = m_label12;
+
+ // fill with standard labels
+ m_monthlyButton->setChecked(true);
+ slotChangePeriod(m_periodGroup->id(m_monthlyButton));
+
+ // connect(m_budgetLevel, SIGNAL(currentChanged(QWidget*)), this, SIGNAL(valuesChanged()));
+ connect(m_amountMonthly, SIGNAL(valueChanged(const QString&)), this, SLOT(slotNeedUpdate()));
+ connect(m_amountYearly, SIGNAL(valueChanged(const QString&)), this, SLOT(slotNeedUpdate()));
+ m_amountMonthly->installEventFilter(this);
+ m_amountYearly->installEventFilter(this);
+
+ for(int i=0; i < 12; ++i) {
+ connect(m_field[i], SIGNAL(valueChanged(const QString&)), this, SLOT(slotNeedUpdate()));
+ m_field[i]->installEventFilter(this);
+ }
+
+ connect(m_clearButton, SIGNAL(clicked()), this, SLOT(slotClearAllValues()));
+ connect(m_periodGroup, SIGNAL(clicked(int)), this, SLOT(slotChangePeriod(int)));
+ connect(this, SIGNAL(valuesChanged()), this, SLOT(slotUpdateClearButton()));
+
+ KGuiItem clearItem(KStdGuiItem::clear());
+
+ m_clearButton->setGuiItem(clearItem);
+ m_clearButton->setText("");
+ QToolTip::add(m_clearButton, clearItem.toolTip());
+}
+
+
+KBudgetValues::~KBudgetValues()
+{
+}
+
+bool KBudgetValues::eventFilter(QObject* o, QEvent* e)
+{
+ bool rc = false;
+
+ if(o->isWidgetType()
+ && (e->type() == QEvent::KeyPress)) {
+ QKeyEvent* k = dynamic_cast<QKeyEvent*>(e);
+ if((k->state() & Qt::KeyButtonMask) == 0) {
+ QKeyEvent evt(e->type(),
+ Qt::Key_Tab, 0, k->state(), QString::null,
+ k->isAutoRepeat(), k->count());
+ switch(k->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ // send out a TAB key event
+ QApplication::sendEvent( o, &evt );
+ // don't process this one any further
+ rc = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+void KBudgetValues::clear(void)
+{
+ blockSignals(true);
+ for(int i=0; i < 12; ++i)
+ m_field[i]->setValue(MyMoneyMoney());
+ m_amountMonthly->setValue(MyMoneyMoney());
+ m_amountYearly->setValue(MyMoneyMoney());
+ blockSignals(false);
+}
+
+void KBudgetValues::slotClearAllValues(void)
+{
+ QWidget* tab = m_periodGroup->selected();
+ if(tab == m_monthlyButton) {
+ m_amountMonthly->setValue(MyMoneyMoney());
+ } else if(tab == m_yearlyButton) {
+ m_amountYearly->setValue(MyMoneyMoney());
+ } else if(tab == m_individualButton) {
+ for(int i=0; i < 12; ++i)
+ m_field[i]->setValue(MyMoneyMoney());
+ }
+ emit valuesChanged();
+}
+
+void KBudgetValues::slotChangePeriod(int id)
+{
+ // Prevent a recursive entry of this method due to widget changes
+ // performed during execution of this method
+ static bool inside = false;
+ if(inside)
+ return;
+ inside = true;
+
+ QWidget *tab = m_periodGroup->find(id);
+ fillMonthLabels();
+
+ MyMoneyMoney newValue;
+ if(tab == m_monthlyButton) {
+ m_firstItemStack->raiseWidget(m_monthlyPage);
+ enableMonths(false);
+ m_label[0]->setText(" ");
+ if(m_amountMonthly->value().isZero()) {
+ if(m_currentTab == m_yearlyButton) {
+ newValue = (m_amountYearly->value() / MyMoneyMoney(12, 1)).convert();
+
+ } else if(m_currentTab == m_individualButton) {
+ for(int i=0; i < 12; ++i)
+ newValue += m_field[i]->value();
+ newValue = (newValue / MyMoneyMoney(12, 1)).convert();
+ }
+ if(!newValue.isZero()) {
+ if(KMessageBox::questionYesNo(this, QString("<qt>")+i18n("You have entered budget values using a different base which would result in a monthly budget of <b>%1</b>. Should this value be used to fill the monthly budget?").arg(newValue.formatMoney("", 2))+QString("</qt>"), i18n("Auto assignment (caption)", "Auto assignment"), KStdGuiItem::yes(), KStdGuiItem::no(), "use_previous_budget_values") == KMessageBox::Yes) {
+ m_amountMonthly->setValue(newValue);
+ }
+ }
+ }
+
+ } else if(tab == m_yearlyButton) {
+ m_firstItemStack->raiseWidget(m_yearlyPage);
+ enableMonths(false);
+ m_label[0]->setText(" ");
+ if(m_amountYearly->value().isZero()) {
+ if(m_currentTab == m_monthlyButton) {
+ newValue = (m_amountMonthly->value() * MyMoneyMoney(12, 1)).convert();
+
+ } else if(m_currentTab == m_individualButton) {
+ for(int i=0; i < 12; ++i)
+ newValue += m_field[i]->value();
+ }
+ if(!newValue.isZero()) {
+ if(KMessageBox::questionYesNo(this, QString("<qt>")+i18n("You have entered budget values using a different base which would result in a yearly budget of <b>%1</b>. Should this value be used to fill the monthly budget?").arg(newValue.formatMoney("", 2))+QString("</qt>"), i18n("Auto assignment (caption)", "Auto assignment"), KStdGuiItem::yes(), KStdGuiItem::no(), "use_previous_budget_values") == KMessageBox::Yes) {
+ m_amountYearly->setValue(newValue);
+ }
+ }
+ }
+
+ } else if(tab == m_individualButton) {
+ m_firstItemStack->raiseWidget(m_individualPage);
+ enableMonths(true);
+ for(int i=0; i < 12; ++i)
+ newValue += m_field[i]->value();
+ if(newValue.isZero()) {
+ if(m_currentTab == m_monthlyButton) {
+ newValue = m_amountMonthly->value();
+ } else if(m_currentTab == m_yearlyButton) {
+ newValue = (m_amountYearly->value() / MyMoneyMoney(12, 1)).convert();
+ }
+
+ if(!newValue.isZero()) {
+ if(KMessageBox::questionYesNo(this, QString("<qt>")+i18n("You have entered budget values using a different base which would result in an individual monthly budget of <b>%1</b>. Should this value be used to fill the monthly budgets?").arg(newValue.formatMoney("", 2))+QString("</qt>"), i18n("Auto assignment (caption)", "Auto assignment"), KStdGuiItem::yes(), KStdGuiItem::no(), "use_previous_budget_values") == KMessageBox::Yes) {
+ for(int i=0; i < 12; ++i)
+ m_field[i]->setValue(newValue);
+ }
+ }
+ }
+ }
+
+ slotNeedUpdate();
+ m_currentTab = tab;
+ inside = false;
+}
+
+void KBudgetValues::slotNeedUpdate(void)
+{
+ if(!signalsBlocked())
+ QTimer::singleShot(0, this, SIGNAL(valuesChanged()));
+}
+
+void KBudgetValues::enableMonths(bool enabled)
+{
+ for(int i = 1; i < 12; ++i) {
+ m_label[i]->setEnabled(enabled);
+ m_field[i]->setEnabled(enabled);
+ }
+}
+
+void KBudgetValues::fillMonthLabels(void)
+{
+ QDate date(m_budgetDate);
+ for(int i = 0; i < 12; ++i) {
+ m_label[i]->setText(KGlobal::locale()->calendar()->monthName(date, true));
+ date = date.addMonths(1);
+ }
+}
+
+void KBudgetValues::setBudgetValues(const MyMoneyBudget& budget, const MyMoneyBudget::AccountGroup& budgetAccount)
+{
+ MyMoneyBudget::PeriodGroup period;
+ m_budgetDate = budget.budgetStart();
+ QDate date;
+
+ // make sure all values are zero so that slotChangePeriod()
+ // doesn't check for anything.
+ clear();
+
+ blockSignals(true);
+ switch(budgetAccount.budgetLevel()) {
+ case MyMoneyBudget::AccountGroup::eMonthly:
+ default:
+ m_monthlyButton->setChecked(true);
+ slotChangePeriod(m_periodGroup->id(m_monthlyButton));
+ m_amountMonthly->setValue(budgetAccount.period(m_budgetDate).amount());
+ break;
+ case MyMoneyBudget::AccountGroup::eYearly:
+ m_yearlyButton->setChecked(true);
+ slotChangePeriod(m_periodGroup->id(m_yearlyButton));
+ m_amountYearly->setValue(budgetAccount.period(m_budgetDate).amount());
+ break;
+ case MyMoneyBudget::AccountGroup::eMonthByMonth:
+ m_individualButton->setChecked(true);
+ slotChangePeriod(m_periodGroup->id(m_individualButton));
+ date.setYMD(m_budgetDate.year(), 1, 1);
+ for(int i = 0; i < 12; ++i) {
+ m_field[i]->setValue(budgetAccount.period(date).amount());
+ date = date.addMonths(1);
+ }
+ break;
+ }
+ slotUpdateClearButton();
+ blockSignals(false);
+}
+
+void KBudgetValues::budgetValues(const MyMoneyBudget& budget, MyMoneyBudget::AccountGroup& budgetAccount)
+{
+ MyMoneyBudget::PeriodGroup period;
+ m_budgetDate = budget.budgetStart();
+ period.setStartDate(m_budgetDate);
+ QDate date;
+
+ budgetAccount.clearPeriods();
+ if(m_periodGroup->selected() == m_monthlyButton) {
+ budgetAccount.setBudgetLevel(MyMoneyBudget::AccountGroup::eMonthly);
+ period.setAmount(m_amountMonthly->value());
+ budgetAccount.addPeriod(m_budgetDate, period);
+ } else if(m_periodGroup->selected() == m_yearlyButton) {
+ budgetAccount.setBudgetLevel(MyMoneyBudget::AccountGroup::eYearly);
+ period.setAmount(m_amountYearly->value());
+ budgetAccount.addPeriod(m_budgetDate, period);
+ } else if(m_periodGroup->selected() == m_individualButton) {
+ budgetAccount.setBudgetLevel(MyMoneyBudget::AccountGroup::eMonthByMonth);
+ date.setYMD(m_budgetDate.year(), 1, 1);
+ for(int i = 0; i < 12; ++i) {
+ period.setStartDate(date);
+ period.setAmount(m_field[i]->value());
+ budgetAccount.addPeriod(date, period);
+ date = date.addMonths(1);
+ }
+ }
+}
+
+void KBudgetValues::slotUpdateClearButton(void)
+{
+ bool rc = false;
+ if(m_periodGroup->selected() == m_monthlyButton) {
+ rc = !m_amountMonthly->value().isZero();
+ } else if(m_periodGroup->selected() == m_yearlyButton) {
+ rc = !m_amountYearly->value().isZero();
+ } else if(m_periodGroup->selected() == m_individualButton) {
+ for(int i = 0; (i < 12) && (rc == false); ++i) {
+ rc |= !m_field[i]->value().isZero();
+ }
+ }
+ m_clearButton->setEnabled(rc);
+}
+
+#include "kbudgetvalues.moc"
diff --git a/kmymoney2/widgets/kbudgetvalues.h b/kmymoney2/widgets/kbudgetvalues.h
new file mode 100644
index 0000000..5b8c2cc
--- /dev/null
+++ b/kmymoney2/widgets/kbudgetvalues.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ kbudgetvalues - description
+ -------------------
+ begin : Wed Nov 28 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBUDGETVALUES_H
+#define KBUDGETVALUES_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+class QLabel;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../widgets/kbudgetvaluesdecl.h"
+#include <kmymoney/mymoneybudget.h>
+class kMyMoneyEdit;
+
+/**
+ * @author Thomas Baumgart <ipwizard@users.sourceforge.net>
+ */
+class KBudgetValues : public KBudgetValuesDecl
+{
+ Q_OBJECT
+ public:
+ KBudgetValues(QWidget* parent = 0, const char* name = 0);
+ ~KBudgetValues();
+
+ void setBudgetValues(const MyMoneyBudget& budget, const MyMoneyBudget::AccountGroup& budgetAccount);
+ void budgetValues(const MyMoneyBudget& budget, MyMoneyBudget::AccountGroup& budgetAccount);
+ void clear(void);
+
+ private:
+ void enableMonths(bool enabled);
+ void fillMonthLabels(void);
+
+ protected slots:
+ void slotChangePeriod(int id);
+
+ /**
+ * This slot clears the value in the value widgets of the selected budget type.
+ * Values of the other types are unaffected.
+ */
+ void slotClearAllValues(void);
+
+ /**
+ * Helper slot used to postpone sending the valuesChanged() signal.
+ */
+ void slotNeedUpdate(void);
+
+ void slotUpdateClearButton(void);
+
+ protected:
+ bool eventFilter(QObject* o, QEvent* e);
+
+ private:
+ kMyMoneyEdit* m_field[12];
+ QLabel* m_label[12];
+ QWidget* m_currentTab;
+ QDate m_budgetDate;
+
+ signals:
+ void valuesChanged(void);
+};
+
+#endif
diff --git a/kmymoney2/widgets/kbudgetvaluesdecl.cpp b/kmymoney2/widgets/kbudgetvaluesdecl.cpp
new file mode 100644
index 0000000..43d71f5
--- /dev/null
+++ b/kmymoney2/widgets/kbudgetvaluesdecl.cpp
@@ -0,0 +1,257 @@
+#include <kdialog.h>
+#include <klocale.h>
+#ifndef KMM_I18N
+#define KMM_I18N
+inline QString kmm_i18n(const char* msg, const char* ctx) { return i18n(ctx, msg); }
+inline QString kmm_i18n(const char* msg) { return i18n(msg); }
+#endif
+/****************************************************************************
+** Form implementation generated from reading ui file '../../../kmymoney2/widgets/kbudgetvaluesdecl.ui'
+**
+** Created: Fri Feb 12 15:05:38 2010
+**
+** WARNING! All changes made in this file will be lost!
+****************************************************************************/
+
+#include "kbudgetvaluesdecl.h"
+
+#include <qvariant.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qwidgetstack.h>
+#include <kpushbutton.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+/*
+ * Constructs a KBudgetValuesDecl as a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'.
+ */
+KBudgetValuesDecl::KBudgetValuesDecl( QWidget* parent, const char* name, WFlags fl )
+ : QWidget( parent, name, fl )
+{
+ if ( !name )
+ setName( "KBudgetValuesDecl" );
+ KBudgetValuesDeclLayout = new QGridLayout( this, 1, 1, 0, 6, "KBudgetValuesDeclLayout");
+
+ m_amount10 = new kMyMoneyEdit( this, "m_amount10" );
+ m_amount10->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount10, 3, 5 );
+
+ m_amount6 = new kMyMoneyEdit( this, "m_amount6" );
+ m_amount6->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount6, 5, 3 );
+
+ m_amount5 = new kMyMoneyEdit( this, "m_amount5" );
+ m_amount5->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount5, 4, 3 );
+
+ m_label6 = new QLabel( this, "m_label6" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label6, 5, 2 );
+
+ m_label8 = new QLabel( this, "m_label8" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label8, 1, 4 );
+
+ m_amount9 = new kMyMoneyEdit( this, "m_amount9" );
+ m_amount9->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount9, 2, 5 );
+
+ m_amount11 = new kMyMoneyEdit( this, "m_amount11" );
+ m_amount11->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount11, 4, 5 );
+
+ m_label12 = new QLabel( this, "m_label12" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label12, 5, 4 );
+
+ m_label10 = new QLabel( this, "m_label10" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label10, 3, 4 );
+
+ m_label7 = new QLabel( this, "m_label7" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label7, 0, 4 );
+
+ m_amount3 = new kMyMoneyEdit( this, "m_amount3" );
+ m_amount3->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount3, 2, 3 );
+
+ m_label4 = new QLabel( this, "m_label4" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label4, 3, 2 );
+
+ m_amount12 = new kMyMoneyEdit( this, "m_amount12" );
+ m_amount12->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount12, 5, 5 );
+
+ m_label3 = new QLabel( this, "m_label3" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label3, 2, 2 );
+
+ m_label1 = new QLabel( this, "m_label1" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label1, 0, 2 );
+
+ m_label2 = new QLabel( this, "m_label2" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label2, 1, 2 );
+
+ m_label5 = new QLabel( this, "m_label5" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label5, 4, 2 );
+
+ m_label11 = new QLabel( this, "m_label11" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label11, 4, 4 );
+
+ m_amount4 = new kMyMoneyEdit( this, "m_amount4" );
+ m_amount4->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount4, 3, 3 );
+
+ m_label9 = new QLabel( this, "m_label9" );
+
+ KBudgetValuesDeclLayout->addWidget( m_label9, 2, 4 );
+
+ m_amount8 = new kMyMoneyEdit( this, "m_amount8" );
+ m_amount8->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount8, 1, 5 );
+
+ m_amount2 = new kMyMoneyEdit( this, "m_amount2" );
+ m_amount2->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount2, 1, 3 );
+
+ m_amount7 = new kMyMoneyEdit( this, "m_amount7" );
+ m_amount7->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+
+ KBudgetValuesDeclLayout->addWidget( m_amount7, 0, 5 );
+
+ m_firstItemStack = new QWidgetStack( this, "m_firstItemStack" );
+
+ m_monthlyPage = new QWidget( m_firstItemStack, "m_monthlyPage" );
+ m_monthlyPageLayout = new QHBoxLayout( m_monthlyPage, 0, 6, "m_monthlyPageLayout");
+
+ m_amountMonthly = new kMyMoneyEdit( m_monthlyPage, "m_amountMonthly" );
+ m_amountMonthly->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+ m_monthlyPageLayout->addWidget( m_amountMonthly );
+ m_firstItemStack->addWidget( m_monthlyPage, 0 );
+
+ m_yearlyPage = new QWidget( m_firstItemStack, "m_yearlyPage" );
+ m_yearlyPageLayout = new QHBoxLayout( m_yearlyPage, 0, 6, "m_yearlyPageLayout");
+
+ m_amountYearly = new kMyMoneyEdit( m_yearlyPage, "m_amountYearly" );
+ m_amountYearly->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+ m_yearlyPageLayout->addWidget( m_amountYearly );
+ m_firstItemStack->addWidget( m_yearlyPage, 1 );
+
+ m_individualPage = new QWidget( m_firstItemStack, "m_individualPage" );
+ m_individualPageLayout = new QHBoxLayout( m_individualPage, 0, 6, "m_individualPageLayout");
+
+ m_amount1 = new kMyMoneyEdit( m_individualPage, "m_amount1" );
+ m_amount1->setProperty( "resetButtonVisibility", QVariant( FALSE, 0 ) );
+ m_individualPageLayout->addWidget( m_amount1 );
+ m_firstItemStack->addWidget( m_individualPage, 2 );
+
+ KBudgetValuesDeclLayout->addWidget( m_firstItemStack, 0, 3 );
+
+ layout12 = new QVBoxLayout( 0, 0, 6, "layout12");
+
+ m_clearButton = new KPushButton( this, "m_clearButton" );
+ layout12->addWidget( m_clearButton );
+ spacer7 = new QSpacerItem( 20, 21, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ layout12->addItem( spacer7 );
+
+ KBudgetValuesDeclLayout->addMultiCellLayout( layout12, 0, 5, 1, 1 );
+
+ m_periodGroup = new QButtonGroup( this, "m_periodGroup" );
+ m_periodGroup->setColumnLayout(0, Qt::Vertical );
+ m_periodGroup->layout()->setSpacing( 6 );
+ m_periodGroup->layout()->setMargin( 11 );
+ m_periodGroupLayout = new QVBoxLayout( m_periodGroup->layout() );
+ m_periodGroupLayout->setAlignment( Qt::AlignTop );
+
+ m_monthlyButton = new QRadioButton( m_periodGroup, "m_monthlyButton" );
+ m_periodGroupLayout->addWidget( m_monthlyButton );
+
+ m_yearlyButton = new QRadioButton( m_periodGroup, "m_yearlyButton" );
+ m_periodGroupLayout->addWidget( m_yearlyButton );
+
+ m_individualButton = new QRadioButton( m_periodGroup, "m_individualButton" );
+ m_periodGroupLayout->addWidget( m_individualButton );
+ spacer10 = new QSpacerItem( 20, 21, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ m_periodGroupLayout->addItem( spacer10 );
+
+ KBudgetValuesDeclLayout->addMultiCellWidget( m_periodGroup, 0, 5, 0, 0 );
+ languageChange();
+ resize( QSize(553, 188).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+
+ // tab order
+ setTabOrder( m_monthlyButton, m_yearlyButton );
+ setTabOrder( m_yearlyButton, m_individualButton );
+ setTabOrder( m_individualButton, m_clearButton );
+ setTabOrder( m_clearButton, m_amount1 );
+ setTabOrder( m_amount1, m_amountMonthly );
+ setTabOrder( m_amountMonthly, m_amountYearly );
+ setTabOrder( m_amountYearly, m_amount2 );
+ setTabOrder( m_amount2, m_amount3 );
+ setTabOrder( m_amount3, m_amount4 );
+ setTabOrder( m_amount4, m_amount5 );
+ setTabOrder( m_amount5, m_amount6 );
+ setTabOrder( m_amount6, m_amount7 );
+ setTabOrder( m_amount7, m_amount8 );
+ setTabOrder( m_amount8, m_amount9 );
+ setTabOrder( m_amount9, m_amount10 );
+ setTabOrder( m_amount10, m_amount11 );
+ setTabOrder( m_amount11, m_amount12 );
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KBudgetValuesDecl::~KBudgetValuesDecl()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+/*
+ * Sets the strings of the subwidgets using the current
+ * language.
+ */
+void KBudgetValuesDecl::languageChange()
+{
+ m_label6->setText( kmm_i18n( "xxx" ) );
+ m_label8->setText( kmm_i18n( "xxx" ) );
+ m_label12->setText( kmm_i18n( "xxx" ) );
+ m_label10->setText( kmm_i18n( "xxx" ) );
+ m_label7->setText( kmm_i18n( "xxx" ) );
+ m_label4->setText( kmm_i18n( "xxx" ) );
+ m_label3->setText( kmm_i18n( "xxx" ) );
+ m_label1->setText( kmm_i18n( "xxx" ) );
+ m_label2->setText( kmm_i18n( "xxx" ) );
+ m_label5->setText( kmm_i18n( "xxx" ) );
+ m_label11->setText( kmm_i18n( "xxx" ) );
+ m_label9->setText( kmm_i18n( "xxx" ) );
+ m_clearButton->setText( QString::null );
+ m_periodGroup->setTitle( kmm_i18n( "Period" ) );
+ m_monthlyButton->setText( kmm_i18n( "Monthly" ) );
+ m_yearlyButton->setText( kmm_i18n( "Yearly" ) );
+ m_individualButton->setText( kmm_i18n( "Individual" ) );
+}
+
+#include "kbudgetvaluesdecl.moc"
diff --git a/kmymoney2/widgets/kbudgetvaluesdecl.ui b/kmymoney2/widgets/kbudgetvaluesdecl.ui
new file mode 100644
index 0000000..6870d64
--- /dev/null
+++ b/kmymoney2/widgets/kbudgetvaluesdecl.ui
@@ -0,0 +1,400 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KBudgetValuesDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KBudgetValuesDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>553</width>
+ <height>188</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="kMyMoneyEdit" row="3" column="5">
+ <property name="name">
+ <cstring>m_amount10</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="5" column="3">
+ <property name="name">
+ <cstring>m_amount6</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="4" column="3">
+ <property name="name">
+ <cstring>m_amount5</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="2">
+ <property name="name">
+ <cstring>m_label6</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="4">
+ <property name="name">
+ <cstring>m_label8</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="5">
+ <property name="name">
+ <cstring>m_amount9</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="4" column="5">
+ <property name="name">
+ <cstring>m_amount11</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="4">
+ <property name="name">
+ <cstring>m_label12</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="4">
+ <property name="name">
+ <cstring>m_label10</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>m_label7</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="3">
+ <property name="name">
+ <cstring>m_amount3</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>m_label4</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="5" column="5">
+ <property name="name">
+ <cstring>m_amount12</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>m_label3</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>m_label1</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>m_label2</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>m_label5</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="4">
+ <property name="name">
+ <cstring>m_label11</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="3" column="3">
+ <property name="name">
+ <cstring>m_amount4</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="4">
+ <property name="name">
+ <cstring>m_label9</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="5">
+ <property name="name">
+ <cstring>m_amount8</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="3">
+ <property name="name">
+ <cstring>m_amount2</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="0" column="5">
+ <property name="name">
+ <cstring>m_amount7</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QWidgetStack" row="0" column="3">
+ <property name="name">
+ <cstring>m_firstItemStack</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_monthlyPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>0</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_amountMonthly</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_yearlyPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>1</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_amountYearly</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>m_individualPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>2</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_amount1</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1" rowspan="6" colspan="1">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_clearButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0" rowspan="6" colspan="1">
+ <property name="name">
+ <cstring>m_periodGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Period</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_monthlyButton</cstring>
+ </property>
+ <property name="text">
+ <string>Monthly</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_yearlyButton</cstring>
+ </property>
+ <property name="text">
+ <string>Yearly</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_individualButton</cstring>
+ </property>
+ <property name="text">
+ <string>Individual</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>m_monthlyButton</tabstop>
+ <tabstop>m_yearlyButton</tabstop>
+ <tabstop>m_individualButton</tabstop>
+ <tabstop>m_clearButton</tabstop>
+ <tabstop>m_amount1</tabstop>
+ <tabstop>m_amountMonthly</tabstop>
+ <tabstop>m_amountYearly</tabstop>
+ <tabstop>m_amount2</tabstop>
+ <tabstop>m_amount3</tabstop>
+ <tabstop>m_amount4</tabstop>
+ <tabstop>m_amount5</tabstop>
+ <tabstop>m_amount6</tabstop>
+ <tabstop>m_amount7</tabstop>
+ <tabstop>m_amount8</tabstop>
+ <tabstop>m_amount9</tabstop>
+ <tabstop>m_amount10</tabstop>
+ <tabstop>m_amount11</tabstop>
+ <tabstop>m_amount12</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kmymoney/kmymoneyedit.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kguiutils.cpp b/kmymoney2/widgets/kguiutils.cpp
new file mode 100644
index 0000000..c6157f9
--- /dev/null
+++ b/kmymoney2/widgets/kguiutils.cpp
@@ -0,0 +1,178 @@
+/***************************************************************************
+ kguiutils.cpp - description
+ -------------------
+ begin : Fri Jan 27 2006
+ copyright : (C) 2006 Tony Bloomfield
+ email : Tony Bloomfield <tonybloom@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+ // No need for QDateEdit, QSpinBox, etc., since these always return values
+
+#include <qcheckbox.h>
+#include <qlistbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qwidget.h>
+#include <qhbox.h>
+#include <qspinbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kguiutils.h"
+#include "../kmymoneyglobalsettings.h"
+
+ /**************************************************************************
+ * *
+ * The MandatoryFieldGroup code is courtesy of *
+ * Mark Summerfield in Qt Quarterly *
+ * http://doc.trolltech.com/qq/qq11-mandatoryfields.html *
+ * *
+ * Enhanced by Thomas Baumgart to support the lineedit field of a *
+ * a QComboBox. *
+ * *
+ **************************************************************************/
+
+void kMandatoryFieldGroup::add(QWidget *widget)
+{
+ if (!widgets.contains(widget)) {
+ if (widget->inherits("QCheckBox"))
+ connect((QCheckBox*)widget->qt_cast("QCheckBox"),
+ SIGNAL(clicked()),
+ this, SLOT(changed()));
+
+ else if (widget->inherits("QComboBox")) {
+ QComboBox* combo = (QComboBox*)widget->qt_cast("QComboBox");
+ QLineEdit* lineedit = combo->lineEdit();
+ if(lineedit) {
+ connect(lineedit, SIGNAL(textChanged(const QString&)), this, SLOT(changed()));
+ } else {
+ connect(combo, SIGNAL(highlighted(int)), this, SLOT(changed()));
+ }
+ }
+
+ else if (widget->inherits("QLineEdit"))
+ connect((QLineEdit*)widget->qt_cast("QLineEdit"),
+ SIGNAL(textChanged(const QString&)),
+ this, SLOT(changed()));
+
+ else if (widget->inherits("QSpinBox"))
+ connect((QSpinBox*)widget->qt_cast("QSpinBox"),
+ SIGNAL(valueChanged(const QString&)),
+ this, SLOT(changed()));
+
+ else if (widget->inherits("QListBox"))
+ connect((QListBox*)widget->qt_cast("QListBox"),
+ SIGNAL(selectionChanged()),
+ this, SLOT(changed()));
+
+ else {
+ qWarning("MandatoryFieldGroup: unsupported class %s",
+ widget->className());
+ return;
+ }
+
+ widget->setPaletteBackgroundColor(KMyMoneyGlobalSettings::requiredFieldColor());
+ widgets.append(widget);
+ changed();
+ }
+}
+
+
+void kMandatoryFieldGroup::remove(QWidget *widget)
+{
+ widget->setPaletteBackgroundColor(widget->colorGroup().background());
+ widgets.remove(widget);
+ changed();
+}
+
+
+void kMandatoryFieldGroup::setOkButton(QPushButton *button)
+{
+ if (okButton && okButton != button)
+ okButton->setEnabled(true);
+ okButton = button;
+ changed();
+}
+
+
+void kMandatoryFieldGroup::changed(void)
+{
+ bool enable = true;
+ QValueList<QWidget *>::ConstIterator i;
+ for (i = widgets.begin(); i != widgets.end(); ++i) {
+ QWidget *widget = *i;
+ // disabled widgets don't count
+ if(!(widget->isEnabled())) {
+ continue;
+ }
+ if (widget->inherits("QCheckBox")) {
+ if (((QCheckBox*)widget->qt_cast("QCheckBox"))->state() == QButton::NoChange) {
+ enable = false;
+ break;
+ } else
+ continue;
+ }
+ if (widget->inherits("QComboBox")) {
+ if (((QComboBox*)widget->qt_cast("QComboBox"))->currentText().isEmpty()) {
+ enable = false;
+ break;
+ } else
+ continue;
+ }
+ if (widget->inherits("QLineEdit")) {
+ if (((QLineEdit*)widget->qt_cast("QLineEdit"))->text().isEmpty()) {
+ enable = false;
+ break;
+ } else
+ continue;
+ }
+ if (widget->inherits("QListBox")) {
+ if (((QListBox*)widget->qt_cast("QListBox"))->selectedItem() == 0) {
+ enable = false;
+ break;
+ } else
+ continue;
+ }
+ }
+
+ if (okButton)
+ okButton->setEnabled(enable);
+ m_enabled = enable;
+
+ emit stateChanged();
+ emit stateChanged(enable);
+}
+
+
+void kMandatoryFieldGroup::clear(void)
+{
+ QValueList<QWidget *>::Iterator i;
+ for (i = widgets.begin(); i != widgets.end(); ++i)
+ (*i)->setPaletteBackgroundColor((*i)->colorGroup().background());
+ widgets.clear();
+ if (okButton) {
+ okButton->setEnabled(true);
+ okButton = 0;
+ m_enabled = true;
+ }
+}
+
+
+#include "kguiutils.moc"
+
diff --git a/kmymoney2/widgets/kguiutils.h b/kmymoney2/widgets/kguiutils.h
new file mode 100644
index 0000000..9a7b603
--- /dev/null
+++ b/kmymoney2/widgets/kguiutils.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ kguiutils.h - description
+ -------------------
+ begin : Fri Jan 27 2006
+ copyright : (C) 2006 Tony Bloomfield
+ email : Tony Bloomfield <tonybloom@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KGUIUTILS_H
+#define KGUIUTILS_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qvaluelist.h>
+class QWidget;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ * @author Tony Bloomfield
+ */
+class kMandatoryFieldGroup : public QObject
+{
+ Q_OBJECT
+
+public:
+ kMandatoryFieldGroup(QObject *parent) :
+ QObject(parent), okButton(0), m_enabled(true) {}
+
+ /**
+ * This method adds a widget to the list of mandatory fields for the current dialog
+ *
+ * @param widget pointer to the widget to be added
+ */
+ void add(QWidget *widget);
+
+ /**
+ * This method removes a widget form the list of mandatory fields for the current dialog
+ *
+ * @param widget pointer to the widget to be removed
+ */
+ void remove(QWidget *widget);
+
+ /**
+ * This method designates the button to be enabled when all mandatory fields
+ * have been completed
+ *
+ * @param button pointer to the 'ok' button
+ */
+ void setOkButton(QPushButton *button);
+
+ /**
+ * This method returns if all requirements for the mandatory group
+ * have been fulfilled (@p true) or not (@p false).
+ */
+ bool isEnabled(void) const { return m_enabled; }
+
+public slots:
+ void clear(void);
+
+ /**
+ * Force update of ok button
+ */
+ void changed(void);
+
+signals:
+ void stateChanged(void);
+ void stateChanged(bool state);
+
+private:
+ QValueList<QWidget *> widgets;
+ QPushButton* okButton;
+ bool m_enabled;
+};
+
+#endif // KGUIUTILS_H
diff --git a/kmymoney2/widgets/klistviewsearchline.cpp b/kmymoney2/widgets/klistviewsearchline.cpp
new file mode 100644
index 0000000..5aba160
--- /dev/null
+++ b/kmymoney2/widgets/klistviewsearchline.cpp
@@ -0,0 +1,507 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2003 Scott Wheeler <wheeler@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "klistviewsearchline.h"
+
+#include <klistview.h>
+#include <kiconloader.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qapplication.h>
+#include <qtimer.h>
+#include <qpopupmenu.h>
+#include <qlabel.h>
+#include <qheader.h>
+
+#define KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID 2004
+
+class KListViewSearchLine::KListViewSearchLinePrivate
+{
+public:
+ KListViewSearchLinePrivate() :
+ listView(0),
+ caseSensitive(false),
+ activeSearch(false),
+ keepParentsVisible(true),
+ queuedSearches(0) {}
+
+ KListView *listView;
+ bool caseSensitive;
+ bool activeSearch;
+ bool keepParentsVisible;
+ QString search;
+ int queuedSearches;
+ QValueList<int> searchColumns;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public methods
+////////////////////////////////////////////////////////////////////////////////
+
+KListViewSearchLine::KListViewSearchLine(QWidget *parent, KListView *listView, const char *name) :
+ KLineEdit(parent, name)
+{
+ d = new KListViewSearchLinePrivate;
+
+ d->listView = listView;
+
+ connect(this, SIGNAL(textChanged(const QString &)),
+ this, SLOT(queueSearch(const QString &)));
+
+ if(listView) {
+ connect(listView, SIGNAL(destroyed()),
+ this, SLOT(listViewDeleted()));
+
+#if KDE_IS_VERSION(3,3,0)
+ connect(listView, SIGNAL(itemAdded(QListViewItem *)),
+ this, SLOT(itemAdded(QListViewItem *)));
+#endif
+ }
+ else
+ setEnabled(false);
+}
+
+KListViewSearchLine::KListViewSearchLine(QWidget *parent, const char *name) :
+ KLineEdit(parent, name)
+{
+ d = new KListViewSearchLinePrivate;
+
+ d->listView = 0;
+
+ connect(this, SIGNAL(textChanged(const QString &)),
+ this, SLOT(queueSearch(const QString &)));
+
+ setEnabled(false);
+}
+
+KListViewSearchLine::~KListViewSearchLine()
+{
+ delete d;
+}
+
+bool KListViewSearchLine::caseSensitive() const
+{
+ return d->caseSensitive;
+}
+
+QValueList<int> KListViewSearchLine::searchColumns() const
+{
+ return d->searchColumns;
+}
+
+bool KListViewSearchLine::keepParentsVisible() const
+{
+ return d->keepParentsVisible;
+}
+
+KListView *KListViewSearchLine::listView() const
+{
+ return d->listView;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public slots
+////////////////////////////////////////////////////////////////////////////////
+
+void KListViewSearchLine::updateSearch(const QString &s)
+{
+ if(!d->listView)
+ return;
+
+ d->search = s.isNull() ? text() : s;
+
+ // If there's a selected item that is visible, make sure that it's visible
+ // when the search changes too (assuming that it still matches).
+
+ QListViewItem *currentItem = 0;
+
+ switch(d->listView->selectionMode())
+ {
+ case KListView::NoSelection:
+ break;
+ case KListView::Single:
+ currentItem = d->listView->selectedItem();
+ break;
+ default:
+ {
+ int flags = QListViewItemIterator::Selected | QListViewItemIterator::Visible;
+ for(QListViewItemIterator it(d->listView, flags);
+ it.current() && !currentItem;
+ ++it)
+ {
+ if(d->listView->itemRect(it.current()).isValid())
+ currentItem = it.current();
+ }
+ }
+ }
+
+ if(d->keepParentsVisible)
+ checkItemParentsVisible(d->listView->firstChild());
+ else
+ checkItemParentsNotVisible();
+
+ if(currentItem)
+ d->listView->ensureItemVisible(currentItem);
+}
+
+void KListViewSearchLine::setCaseSensitive(bool cs)
+{
+ d->caseSensitive = cs;
+}
+
+void KListViewSearchLine::setKeepParentsVisible(bool v)
+{
+ d->keepParentsVisible = v;
+}
+
+void KListViewSearchLine::setSearchColumns(const QValueList<int> &columns)
+{
+ d->searchColumns = columns;
+}
+
+void KListViewSearchLine::setListView(KListView *lv)
+{
+ if(d->listView) {
+ disconnect(d->listView, SIGNAL(destroyed()),
+ this, SLOT(listViewDeleted()));
+
+#if KDE_IS_VERSION(3,3,0)
+ disconnect(d->listView, SIGNAL(itemAdded(QListViewItem *)),
+ this, SLOT(itemAdded(QListViewItem *)));
+#endif
+ }
+
+ d->listView = lv;
+
+ if(lv) {
+ connect(d->listView, SIGNAL(destroyed()),
+ this, SLOT(listViewDeleted()));
+
+#if KDE_IS_VERSION(3,3,0)
+ connect(d->listView, SIGNAL(itemAdded(QListViewItem *)),
+ this, SLOT(itemAdded(QListViewItem *)));
+#endif
+ }
+
+ setEnabled(bool(lv));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected members
+////////////////////////////////////////////////////////////////////////////////
+
+bool KListViewSearchLine::itemMatches(const QListViewItem *item, const QString &s) const
+{
+ if(s.isEmpty())
+ return true;
+
+ // If the search column list is populated, search just the columns
+ // specifified. If it is empty default to searching all of the columns.
+
+ if(!d->searchColumns.isEmpty()) {
+ QValueList<int>::ConstIterator it = d->searchColumns.begin();
+ for(; it != d->searchColumns.end(); ++it) {
+ if(*it < item->listView()->columns() &&
+ item->text(*it).find(s, 0, d->caseSensitive) >= 0)
+ return true;
+ }
+ }
+ else {
+ for(int i = 0; i < item->listView()->columns(); i++) {
+ if(item->listView()->columnWidth(i) > 0 &&
+ item->text(i).find(s, 0, d->caseSensitive) >= 0)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+QPopupMenu *KListViewSearchLine::createPopupMenu()
+{
+ QPopupMenu *popup = KLineEdit::createPopupMenu();
+
+ if (d->listView->columns()>1) {
+ QPopupMenu *subMenu = new QPopupMenu(popup);
+ connect(subMenu, SIGNAL(activated(int)), this, SLOT(searchColumnsMenuActivated(int)));
+
+ popup->insertSeparator();
+ popup->insertItem(i18n("Search Columns"), subMenu);
+
+ subMenu->insertItem(i18n("All Visible Columns"), KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID);
+ subMenu->insertSeparator();
+
+ bool allColumnsAreSearchColumns = true;
+ // TODO Make the entry order match the actual column order
+ QHeader* const header = d->listView->header();
+ int visibleColumns = 0;
+ for(int i = 0; i < d->listView->columns(); i++) {
+ if(d->listView->columnWidth(i)>0) {
+ QString columnText = d->listView->columnText(i);
+ if(columnText.isEmpty()) {
+ int visiblePosition=1;
+ for(int j = 0; j < header->mapToIndex(i); j++)
+ if(d->listView->columnWidth(header->mapToSection(j))>0)
+ visiblePosition++;
+ columnText = i18n("Column number %1","Column No. %1").arg(visiblePosition);
+ }
+ subMenu->insertItem(columnText, visibleColumns);
+ if(d->searchColumns.isEmpty() || d->searchColumns.find(i) != d->searchColumns.end())
+ subMenu->setItemChecked(visibleColumns, true);
+ else
+ allColumnsAreSearchColumns = false;
+ visibleColumns++;
+ }
+ }
+ subMenu->setItemChecked(KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID, allColumnsAreSearchColumns);
+
+ // searchColumnsMenuActivated() relies on one possible "all" representation
+ if(allColumnsAreSearchColumns && !d->searchColumns.isEmpty())
+ d->searchColumns.clear();
+ }
+
+ return popup;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected slots
+////////////////////////////////////////////////////////////////////////////////
+
+void KListViewSearchLine::queueSearch(const QString &search)
+{
+ d->queuedSearches++;
+ d->search = search;
+ QTimer::singleShot(200, this, SLOT(activateSearch()));
+}
+
+void KListViewSearchLine::activateSearch()
+{
+ --(d->queuedSearches);
+
+ if(d->queuedSearches == 0)
+ updateSearch(d->search);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private slots
+////////////////////////////////////////////////////////////////////////////////
+
+void KListViewSearchLine::itemAdded(QListViewItem *item) const
+{
+ item->setVisible(itemMatches(item, text()));
+}
+
+void KListViewSearchLine::listViewDeleted()
+{
+ d->listView = 0;
+ setEnabled(false);
+}
+
+void KListViewSearchLine::searchColumnsMenuActivated(int id)
+{
+ if(id == KLISTVIEWSEARCHLINE_ALLVISIBLECOLUMNS_ID) {
+ if(d->searchColumns.isEmpty())
+ d->searchColumns.append(0);
+ else
+ d->searchColumns.clear();
+ }
+ else {
+ if(d->searchColumns.find(id) != d->searchColumns.end())
+ d->searchColumns.remove(id);
+ else {
+ if(d->searchColumns.isEmpty()) {
+ for(int i = 0; i < d->listView->columns(); i++) {
+ if(i != id)
+ d->searchColumns.append(i);
+ }
+ }
+ else
+ d->searchColumns.append(id);
+ }
+ }
+ updateSearch();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private methods
+////////////////////////////////////////////////////////////////////////////////
+
+void KListViewSearchLine::checkItemParentsNotVisible()
+{
+ QListViewItemIterator it(d->listView);
+ for(; it.current(); ++it)
+ {
+ QListViewItem *item = it.current();
+ if(itemMatches(item, d->search))
+ item->setVisible(true);
+ else
+ item->setVisible(false);
+ }
+}
+
+#include <kdebug.h>
+
+/** Check whether \p item, its siblings and their descendents should be shown. Show or hide the items as necessary.
+ *
+ * \p item The list view item to start showing / hiding items at. Typically, this is the first child of another item, or the
+ * the first child of the list view.
+ * \p highestHiddenParent The highest (closest to root) ancestor of \p item which is hidden. If 0, all parents of
+ * \p item must be visible.
+ * \return \c true if an item which should be visible is found, \c false if all items found should be hidden. If this function
+ * returns true and \p highestHiddenParent was not 0, highestHiddenParent will have been shown.
+ */
+bool KListViewSearchLine::checkItemParentsVisible(QListViewItem *item, QListViewItem *highestHiddenParent)
+{
+ bool visible = false;
+ QListViewItem * first = item;
+ for(; item; item = item->nextSibling())
+ {
+ //What we pass to our children as highestHiddenParent:
+ QListViewItem * hhp = highestHiddenParent ? highestHiddenParent : item->isVisible() ? 0L : item;
+ bool childMatch = false;
+ if(item->firstChild() && checkItemParentsVisible(item->firstChild(), hhp))
+ childMatch = true;
+ // Should this item be shown? It should if any children should be, or if it matches.
+ if(childMatch || itemMatches(item, d->search))
+ {
+ visible = true;
+ if (highestHiddenParent)
+ {
+ highestHiddenParent->setVisible(true);
+ // Calling setVisible on our ancestor will unhide all its descendents. Hide the ones
+ // before us that should not be shown.
+ for(QListViewItem *hide = first; hide != item; hide = hide->nextSibling())
+ hide->setVisible(false);
+ highestHiddenParent = 0;
+ // If we matched, than none of our children matched, yet the setVisible() call on our
+ // ancestor unhid them, undo the damage:
+ if(!childMatch)
+ for(QListViewItem *hide = item->firstChild(); hide; hide = hide->nextSibling())
+ hide->setVisible(false);
+ }
+ else
+ item->setVisible(true);
+ }
+ else
+ item->setVisible(false);
+ }
+ return visible;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// KListViewSearchLineWidget
+////////////////////////////////////////////////////////////////////////////////
+
+class KListViewSearchLineWidget::KListViewSearchLineWidgetPrivate
+{
+public:
+ KListViewSearchLineWidgetPrivate() : listView(0), searchLine(0), clearButton(0) {}
+ KListView *listView;
+ KListViewSearchLine *searchLine;
+ QToolButton *clearButton;
+};
+
+KListViewSearchLineWidget::KListViewSearchLineWidget(KListView *listView,
+ QWidget *parent,
+ const char *name) :
+ QHBox(parent, name)
+{
+ d = new KListViewSearchLineWidgetPrivate;
+ d->listView = listView;
+
+ setSpacing(5);
+
+ QTimer::singleShot(0, this, SLOT(createWidgets()));
+}
+
+KListViewSearchLineWidget::~KListViewSearchLineWidget()
+{
+ delete d;
+}
+
+KListViewSearchLine *KListViewSearchLineWidget::createSearchLine(KListView *listView)
+{
+ if(!d->searchLine)
+ d->searchLine = new KListViewSearchLine(this, listView);
+ return d->searchLine;
+}
+
+void KListViewSearchLineWidget::createWidgets()
+{
+ positionInToolBar();
+
+ if(!d->clearButton) {
+ d->clearButton = new QToolButton(this);
+ QIconSet icon = SmallIconSet(QApplication::reverseLayout() ? "clear_left" : "locationbar_erase");
+ d->clearButton->setIconSet(icon);
+ }
+
+ d->clearButton->show();
+
+ QLabel *label = new QLabel(i18n("S&earch:"), this, "kde toolbar widget");
+
+ d->searchLine = createSearchLine(d->listView);
+ d->searchLine->show();
+
+ label->setBuddy(d->searchLine);
+ label->show();
+
+ connect(d->clearButton, SIGNAL(clicked()), d->searchLine, SLOT(clear()));
+}
+
+KListViewSearchLine *KListViewSearchLineWidget::searchLine() const
+{
+ return d->searchLine;
+}
+
+void KListViewSearchLineWidget::positionInToolBar()
+{
+ KToolBar *toolBar = dynamic_cast<KToolBar *>(parent());
+
+ if(toolBar) {
+
+ // Here we have The Big Ugly. Figure out how many widgets are in the
+ // and do a hack-ish iteration over them to find this widget so that we
+ // can insert the clear button before it.
+
+ int widgetCount = toolBar->count();
+
+ for(int index = 0; index < widgetCount; index++) {
+ int id = toolBar->idAt(index);
+ if(toolBar->getWidget(id) == this) {
+ toolBar->setItemAutoSized(id);
+ if(!d->clearButton) {
+ QString icon = QApplication::reverseLayout() ? "clear_left" : "locationbar_erase";
+ d->clearButton = new KToolBarButton(icon, 2005, toolBar);
+ }
+ toolBar->insertWidget(2005, d->clearButton->width(), d->clearButton, index);
+ break;
+ }
+ }
+ }
+
+ if(d->searchLine)
+ d->searchLine->show();
+}
+
+#include "klistviewsearchline.moc"
diff --git a/kmymoney2/widgets/klistviewsearchline.h b/kmymoney2/widgets/klistviewsearchline.h
new file mode 100644
index 0000000..041687e
--- /dev/null
+++ b/kmymoney2/widgets/klistviewsearchline.h
@@ -0,0 +1,258 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2003 Scott Wheeler <wheeler@kde.org>
+ Adapted to be used with KMyMoney under KDE 3.2 .. 3.4
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLISTVIEWSEARCHLINE_H
+#define KLISTVIEWSEARCHLINE_H
+
+#include <klineedit.h>
+#include <qhbox.h>
+#include <kmymoney/export.h>
+
+class KListView;
+class QListViewItem;
+class QToolButton;
+
+/**
+ * This class makes it easy to add a search line for filtering the items in a
+ * listview based on a simple text search.
+ *
+ * No changes to the application other than instantiating this class with an
+ * appropriate KListView should be needed.
+ *
+ * @since 3.3
+ */
+
+class KMYMONEY_EXPORT KListViewSearchLine : public KLineEdit
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Constructs a KListViewSearchLine with \a listView being the KListView to
+ * be filtered.
+ *
+ * If \a listView is null then the widget will be disabled until a listview
+ * is set with setListView().
+ */
+ KListViewSearchLine(QWidget *parent = 0, KListView *listView = 0, const char *name = 0);
+
+ /**
+ * Constructs a KListViewSearchLine without any KListView to filter. The
+ * KListView object has to be set later with setListView().
+ */
+ KListViewSearchLine(QWidget *parent, const char *name);
+
+ /**
+ * Destroys the KListViewSearchLine.
+ */
+ virtual ~KListViewSearchLine();
+
+ /**
+ * Returns true if the search is case sensitive. This defaults to false.
+ *
+ * @see setCaseSensitive()
+ */
+ bool caseSensitive() const;
+
+ /**
+ * Returns the current list of columns that will be searched. If the
+ * returned list is empty all visible columns will be searched.
+ *
+ * @see setSearchColumns
+ */
+ QValueList<int> searchColumns() const;
+
+ /**
+ * If this is true (the default) then the parents of matched items will also
+ * be shown.
+ *
+ * @see setKeepParentsVisible()
+ */
+ bool keepParentsVisible() const;
+
+ /**
+ * Returns the listview that is currently filtered by the search.
+ *
+ * @see setListView()
+ */
+ KListView *listView() const;
+
+public slots:
+ /**
+ * Updates search to only make visible the items that match \a s. If
+ * \a s is null then the line edit's text will be used.
+ */
+ virtual void updateSearch(const QString &s = QString::null);
+
+ /**
+ * Make the search case sensitive or case insensitive.
+ *
+ * @see caseSenstive()
+ */
+ void setCaseSensitive(bool cs);
+
+ /**
+ * When a search is active on a list that's organized into a tree view if
+ * a parent or ancesestor of an item is does not match the search then it
+ * will be hidden and as such so too will any children that match.
+ *
+ * If this is set to true (the default) then the parents of matching items
+ * will be shown.
+ *
+ * @see keepParentsVisible
+ */
+ void setKeepParentsVisible(bool v);
+
+ /**
+ * Sets the list of columns to be searched. The default is to search all,
+ * visible columns which can be restored by passing \a columns as an empty
+ * list.
+ *
+ * @see searchColumns
+ */
+ void setSearchColumns(const QValueList<int> &columns);
+
+ /**
+ * Sets the KListView that is filtered by this search line. If \a lv is null
+ * then the widget will be disabled.
+ *
+ * @see listView()
+ */
+ void setListView(KListView *lv);
+
+protected:
+
+ /**
+ * Returns true if \a item matches the search \a s. This will be evaluated
+ * based on the value of caseSensitive(). This can be overridden in
+ * subclasses to implement more complicated matching schemes.
+ */
+ virtual bool itemMatches(const QListViewItem *item, const QString &s) const;
+
+ /**
+ * Re-implemented for internal reasons. API not affected.
+ *
+ * See QLineEdit::mousePressEvent().
+ */
+ virtual QPopupMenu *createPopupMenu();
+
+protected slots:
+ /**
+ * When keys are pressed a new search string is created and a timer is
+ * activated. The most recent search is activated when this timer runs out
+ * if another key has not yet been pressed.
+ *
+ * This method makes @param search the most recent search and starts the
+ * timer.
+ *
+ * Together with activateSearch() this makes it such that searches are not
+ * started until there is a short break in the users typing.
+ *
+ * @see activateSearch()
+ */
+ void queueSearch(const QString &search);
+
+ /**
+ * When the timer started with queueSearch() expires this slot is called.
+ * If there has been another timer started then this slot does nothing.
+ * However if there are no other pending searches this starts the list view
+ * search.
+ *
+ * @see queueSearch()
+ */
+ void activateSearch();
+
+private:
+
+ /**
+ * This is used in case parent items of matching items shouldn't be
+ * visible. It hides all items that don't match the search string.
+ */
+ void checkItemParentsNotVisible();
+
+ /**
+ * This is used in case parent items of matching items should be visible.
+ * It makes a recursive call to all children. It returns true if at least
+ * one item in the subtree with the given root item is visible.
+ */
+ bool checkItemParentsVisible(QListViewItem *item, QListViewItem *highestHiddenParent = 0);
+
+private slots:
+ void itemAdded(QListViewItem *item) const;
+ void listViewDeleted();
+ void searchColumnsMenuActivated(int);
+
+private:
+ class KListViewSearchLinePrivate;
+ KListViewSearchLinePrivate *d;
+};
+
+/**
+ * Creates a widget featuring a KListViewSearchLine, a label with the text
+ * "Search" and a button to clear the search.
+ *
+ * @since 3.4
+ */
+class KMYMONEY_EXPORT KListViewSearchLineWidget : public QHBox
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Creates a KListViewSearchLineWidget for \a listView with \a parent as the
+ * parent with and \a name.
+ */
+ KListViewSearchLineWidget(KListView *listView = 0, QWidget *parent = 0,
+ const char *name = 0);
+
+ /**
+ * Destroys the KListViewSearchLineWidget
+ */
+ ~KListViewSearchLineWidget();
+
+ /**
+ * Creates the search line. This can be useful to reimplement in cases where
+ * a KListViewSearchLine subclass is used.
+ */
+ virtual KListViewSearchLine *createSearchLine(KListView *listView);
+
+ /**
+ * Returns a pointer to the search line.
+ */
+ KListViewSearchLine *searchLine() const;
+
+protected slots:
+ /**
+ * Creates the widgets inside of the widget. This is called from the
+ * constructor via a single shot timer so that it it guaranteed to run
+ * after construction is complete. This makes it suitable for overriding in
+ * subclasses.
+ */
+ virtual void createWidgets();
+
+private slots:
+ void positionInToolBar();
+
+private:
+ class KListViewSearchLineWidgetPrivate;
+ KListViewSearchLineWidgetPrivate *d;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoney.widgets b/kmymoney2/widgets/kmymoney.widgets
new file mode 100644
index 0000000..f844780
--- /dev/null
+++ b/kmymoney2/widgets/kmymoney.widgets
@@ -0,0 +1,54 @@
+[Includes]
+kinstance.h
+
+[Init]
+new KInstance("kmmwidgets");
+
+[KMyMoneyTitleLabel]
+
+[kMyMoneyEdit]
+
+[kMyMoneyDateInput]
+
+[KMyMoneyAccountTree]
+
+[KMyMoneySecuritySelector]
+IncludeFile=kmymoney/kmymoneycurrencyselector.h
+
+[KMyMoneyCurrencySelector]
+
+[KMyMoneyRegister::Register]
+IconSet=register.png
+IncludeFile=kmymoney/register.h
+
+[KMyMoneyTransactionForm::TransactionForm]
+IconSet=transactionform.png
+IncludeFile=kmymoney/transactionform.h
+
+[KMyMoneyCategory]
+
+[KMyMoneyPayeeCombo]
+IncludeFile=kmymoney/kmymoneycombo.h
+
+[KMyMoneyPeriodCombo]
+IncludeFile=kmymoney/kmymoneycombo.h
+
+[KMyMoneyFrequencyCombo]
+IncludeFile=kmymoney/kmymoneycombo.h
+
+[KMyMoneyOccurencePeriodCombo]
+IncludeFile=kmymoney/kmymoneycombo.h
+
+[TransactionSortOption]
+
+[KMyMoneyGeneralCombo]
+IncludeFile=kmymoney/kmymoneycombo.h
+
+[KBudgetValues]
+
+[KAccountTemplateSelector]
+
+# deprecated will be removed at some point in time
+
+[KMyMoneyAccountCombo]
+
diff --git a/kmymoney2/widgets/kmymoneyaccountcombo.cpp b/kmymoney2/widgets/kmymoneyaccountcombo.cpp
new file mode 100644
index 0000000..8a44786
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccountcombo.cpp
@@ -0,0 +1,218 @@
+/***************************************************************************
+ kmymoneyaccountbutton - description
+ -------------------
+ begin : Mon May 31 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdrawutil.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccountcombo.h>
+#include "kmymoneyaccountcompletion.h"
+
+KMyMoneyAccountCombo::KMyMoneyAccountCombo( QWidget* parent, const char* name ) :
+ KComboBox( parent, name ),
+ m_completion(0),
+ m_mlbDown(false)
+{
+#ifndef KMM_DESIGNER
+ m_completion = new kMyMoneyAccountCompletion(this);
+
+ connect(this, SIGNAL(clicked()), this, SLOT(slotButtonPressed()));
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotSelected(const QString&)));
+#endif
+
+ // make sure that we can display a minimum of characters
+ QFontMetrics fm(font());
+ setMinimumWidth(fm.maxWidth()*15);
+ setMaximumHeight(height());
+
+ // we only use this one item and replace the text as we have our own dropdown box
+ insertItem(QString(""));
+}
+
+KMyMoneyAccountCombo::~KMyMoneyAccountCombo()
+{
+}
+
+void KMyMoneyAccountCombo::slotButtonPressed(void)
+{
+ m_completion->show();
+}
+
+void KMyMoneyAccountCombo::slotSelected(const QString& id)
+{
+ try {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(id);
+ setText(acc.name());
+ emit accountSelected(id);
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+}
+
+void KMyMoneyAccountCombo::setSelected(const QString& id)
+{
+ if(!id.isEmpty()) {
+ try {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(id);
+ setSelected(acc);
+ } catch(MyMoneyException *e) {
+ qDebug("Account '%s' not found in %s(%d)", id.data(), __FILE__, __LINE__);
+ delete e;
+ }
+ } else {
+ setText(QString());
+ m_completion->setSelected(id);
+ }
+}
+
+void KMyMoneyAccountCombo::setSelected(const MyMoneyAccount& acc)
+{
+ m_completion->setSelected(acc.id());
+ setText(acc.name());
+}
+
+void KMyMoneyAccountCombo::setText(const QString& txt)
+{
+ changeItem(txt, currentItem());
+}
+
+int KMyMoneyAccountCombo::loadList(const QString& baseName, const QValueList<QString>& accountIdList, const bool clear)
+{
+ AccountSet set;
+
+ return set.load(m_completion->selector(), baseName, accountIdList, clear);
+}
+
+int KMyMoneyAccountCombo::loadList(KMyMoneyUtils::categoryTypeE typeMask)
+{
+ AccountSet set;
+ QValueList<int> typeList;
+
+ if(typeMask & KMyMoneyUtils::asset) {
+ set.addAccountGroup(MyMoneyAccount::Asset);
+ }
+ if(typeMask & KMyMoneyUtils::liability) {
+ set.addAccountGroup(MyMoneyAccount::Liability);
+ }
+ if(typeMask & KMyMoneyUtils::income) {
+ set.addAccountGroup(MyMoneyAccount::Income);
+ }
+ if(typeMask & KMyMoneyUtils::expense) {
+ set.addAccountGroup(MyMoneyAccount::Expense);
+ }
+
+ return set.load(m_completion->selector());
+}
+
+int KMyMoneyAccountCombo::loadList(MyMoneyAccount::accountTypeE type)
+{
+ AccountSet set;
+
+ set.addAccountType(type);
+
+ return set.load(m_completion->selector());
+}
+
+void KMyMoneyAccountCombo::keyPressEvent(QKeyEvent* k)
+{
+ switch(k->key()) {
+ case Qt::Key_Tab:
+ break;
+
+ case Qt::Key_Space:
+ emit clicked();
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
+void KMyMoneyAccountCombo::mousePressEvent(QMouseEvent *e)
+{
+ if ( e->button() != LeftButton ) {
+ e->ignore();
+ return;
+ }
+ bool hit = rect().contains( e->pos() );
+ if ( hit ) { // mouse press on button
+ m_mlbDown = TRUE; // left mouse button down
+ emit pressed();
+ }
+}
+
+void KMyMoneyAccountCombo::mouseReleaseEvent(QMouseEvent *e)
+{
+ if ( e->button() != LeftButton ) {
+ e->ignore();
+ return;
+ }
+ if ( !m_mlbDown )
+ return;
+ m_mlbDown = FALSE; // left mouse button up
+ emit released();
+ if ( rect().contains( e->pos() ) ) { // mouse release on button
+ emit clicked();
+ }
+}
+
+int KMyMoneyAccountCombo::count(void) const
+{
+ return m_completion->selector()->accountList().count();
+}
+
+QStringList KMyMoneyAccountCombo::accountList(const QValueList<MyMoneyAccount::accountTypeE>& list) const
+{
+ return m_completion->selector()->accountList(list);
+};
+
+int KMyMoneyAccountCombo::loadList(const QValueList<int>& list)
+{
+ // FIXME make the caller construct the AccountSet directly
+ AccountSet set;
+ QValueList<int>::const_iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ set.addAccountType(static_cast<MyMoneyAccount::accountTypeE>(*it));
+ }
+ return set.load(m_completion->selector());
+};
+
+QStringList KMyMoneyAccountCombo::selectedAccounts(void) const
+{
+ QStringList list;
+ m_completion->selector()->selectedItems(list);
+ return list;
+};
+
+#include "kmymoneyaccountcombo.moc"
diff --git a/kmymoney2/widgets/kmymoneyaccountcombo.h b/kmymoney2/widgets/kmymoneyaccountcombo.h
new file mode 100644
index 0000000..770d5ad
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccountcombo.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ kmymoneyaccountbutton - description
+ -------------------
+ begin : Mon May 31 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTBUTTON_H
+#define KMYMONEYACCOUNTBUTTON_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneyutils.h>
+class kMyMoneyAccountCompletion;
+
+/**
+ * @author Thomas Baumgart
+ */
+class KMyMoneyAccountCombo : public KComboBox
+{
+ Q_OBJECT
+public:
+ KMyMoneyAccountCombo( QWidget* parent = 0, const char* name = 0 );
+ ~KMyMoneyAccountCombo();
+
+ /**
+ * Method returns how many items are in the account selector list.
+ */
+ int count(void) const;
+
+ /**
+ * This method loads the set of accounts into the widget
+ * as defined by the parameter @p accountIdList. @p accountIdList is
+ * a QValueList of account ids.
+ *
+ * @param baseName QString which should be used as group text
+ * @param accountIdList QValueList of QString account ids
+ * which should be loaded into the widget
+ * @param clear if true (default) clears the widget before populating
+ * @return This method returns the number of accounts loaded into the list
+ */
+ int loadList(const QString& baseName, const QValueList<QString>& accountIdList, const bool clear = true);
+
+ QStringList accountList(const QValueList<MyMoneyAccount::accountTypeE>& list = QValueList<MyMoneyAccount::accountTypeE>()) const;
+
+ int loadList(KMyMoneyUtils::categoryTypeE typeMask);
+ int loadList(const QValueList<int>& list);
+ int loadList(MyMoneyAccount::accountTypeE type);
+
+ void setSelected(const QString& id);
+ void setSelected(const MyMoneyAccount& acc);
+
+ /**
+ * This method returns the list of selected account id's. If
+ * no account is selected, the list is empty.
+ *
+ * @return list of selected accounts
+ */
+ QStringList selectedAccounts(void) const;
+
+ virtual void keyPressEvent(QKeyEvent* e);
+
+public slots:
+ void slotButtonPressed(void);
+ void slotSelected(const QString&);
+
+protected slots:
+
+signals:
+ void accountSelected(const QString&);
+
+ void pressed();
+ void released();
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+ void setText(const QString& txt);
+
+private:
+ kMyMoneyAccountCompletion* m_completion;
+ bool m_mlbDown;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyaccountcompletion.cpp b/kmymoney2/widgets/kmymoneyaccountcompletion.cpp
new file mode 100644
index 0000000..bb2af2e
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccountcompletion.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+ kmymoneyaccountcompletion.cpp - description
+ -------------------
+ begin : Mon Apr 26 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qapplication.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyaccountcompletion.h"
+#include <kmymoney/mymoneyfile.h>
+
+kMyMoneyAccountCompletion::kMyMoneyAccountCompletion(QWidget *parent, const char *name ) :
+ kMyMoneyCompletion(parent, name)
+{
+ delete m_selector;
+ m_selector = new kMyMoneyAccountSelector(this, 0, 0, false);
+ m_selector->listView()->setFocusProxy(this);
+
+#ifndef KMM_DESIGNER
+ // Default is to show all accounts
+ // FIXME We should leave this also to the caller
+ AccountSet set;
+ set.addAccountGroup(MyMoneyAccount::Asset);
+ set.addAccountGroup(MyMoneyAccount::Liability);
+ set.addAccountGroup(MyMoneyAccount::Income);
+ set.addAccountGroup(MyMoneyAccount::Expense);
+ set.load(selector());
+#endif
+
+ connectSignals(m_selector, m_selector->listView());
+}
+
+kMyMoneyAccountCompletion::~kMyMoneyAccountCompletion()
+{
+}
+
+void kMyMoneyAccountCompletion::slotMakeCompletion(const QString& txt)
+{
+ // if(txt.isEmpty() || txt.length() == 0)
+ // return;
+
+ int cnt = 0;
+ if(txt.contains(MyMoneyFile::AccountSeperator) == 0) {
+ m_lastCompletion = QRegExp(QRegExp::escape(txt.stripWhiteSpace()), false);
+ cnt = selector()->slotMakeCompletion(m_lastCompletion);
+ } else {
+ QStringList parts = QStringList::split(MyMoneyFile::AccountSeperator, txt);
+ QString pattern("^");
+ QStringList::iterator it;
+ for(it = parts.begin(); it != parts.end(); ++it) {
+ if(pattern.length() > 1)
+ pattern += MyMoneyFile::AccountSeperator;
+ pattern += QRegExp::escape(QString(*it).stripWhiteSpace()) + ".*";
+ }
+ pattern += "$";
+ m_lastCompletion = QRegExp(pattern, false);
+ cnt = selector()->slotMakeCompletion(m_lastCompletion);
+ // if we don't have a match, we try it again, but this time
+ // we add a wildcard for the top level
+ if(cnt == 0) {
+ pattern = pattern.insert(1, QString(".*")+MyMoneyFile::AccountSeperator);
+ m_lastCompletion = QRegExp(pattern, false);
+ cnt = selector()->slotMakeCompletion(m_lastCompletion);
+ }
+ }
+
+ if(m_parent && m_parent->isVisible() && !isVisible() && cnt)
+ show(false);
+ else {
+ if(cnt != 0) {
+ adjustSize();
+ } else {
+ hide();
+ }
+ }
+}
+
+#include "kmymoneyaccountcompletion.moc"
diff --git a/kmymoney2/widgets/kmymoneyaccountcompletion.h b/kmymoney2/widgets/kmymoneyaccountcompletion.h
new file mode 100644
index 0000000..725a07c
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccountcompletion.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ kmymoneyaccountcompletion.h - description
+ -------------------
+ begin : Mon Apr 26 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTCOMPLETION_H
+#define KMYMONEYACCOUNTCOMPLETION_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneyaccountselector.h>
+#include "kmymoneycompletion.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+class kMyMoneyAccountCompletion : public kMyMoneyCompletion
+{
+ Q_OBJECT
+public:
+
+ kMyMoneyAccountCompletion(QWidget *parent=0, const char *name=0);
+ virtual ~kMyMoneyAccountCompletion();
+
+ QStringList accountList(const QValueList<MyMoneyAccount::accountTypeE>& list = QValueList<MyMoneyAccount::accountTypeE>()) const { return selector()->accountList(list); }
+
+ /**
+ * reimplemented from kMyMoneyCompletion
+ */
+ kMyMoneyAccountSelector* selector(void) const { return dynamic_cast<kMyMoneyAccountSelector*>(m_selector); }
+
+public slots:
+ void slotMakeCompletion(const QString& txt);
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyaccountselector.cpp b/kmymoney2/widgets/kmymoneyaccountselector.cpp
new file mode 100644
index 0000000..f1596b4
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccountselector.cpp
@@ -0,0 +1,544 @@
+/***************************************************************************
+ kmymoneyaccountselector.cpp - description
+ -------------------
+ begin : Thu Sep 18 2003
+ copyright : (C) 2003 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qheader.h>
+#include <qlabel.h>
+#include <qtimer.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qrect.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyaccountselector.h"
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneylistviewitem.h>
+#include <kmymoney/kmymoneychecklistitem.h>
+
+#include "../kmymoneyutils.h"
+#include "../kmymoneyglobalsettings.h"
+
+kMyMoneyAccountSelector::kMyMoneyAccountSelector(QWidget *parent, const char *name, QWidget::WFlags flags, const bool createButtons) :
+ KMyMoneySelector(parent, name, flags),
+ m_allAccountsButton(0),
+ m_noAccountButton(0),
+ m_incomeCategoriesButton(0),
+ m_expenseCategoriesButton(0)
+{
+
+ if(createButtons) {
+ QVBoxLayout* buttonLayout = new QVBoxLayout( 0, 0, 6, "accountSelectorButtonLayout");
+
+ m_allAccountsButton = new KPushButton( this, "m_allAccountsButton" );
+ m_allAccountsButton->setText( i18n( "All" ) );
+ buttonLayout->addWidget( m_allAccountsButton );
+
+ m_incomeCategoriesButton = new KPushButton( this, "m_incomeCategoriesButton" );
+ m_incomeCategoriesButton->setText( i18n( "Income" ) );
+ buttonLayout->addWidget( m_incomeCategoriesButton );
+
+ m_expenseCategoriesButton = new KPushButton( this, "m_expenseCategoriesButton" );
+ m_expenseCategoriesButton->setText( i18n( "Expense" ) );
+ buttonLayout->addWidget( m_expenseCategoriesButton );
+
+ m_noAccountButton = new KPushButton( this, "m_noAccountButton" );
+ m_noAccountButton->setText( i18n( "None" ) );
+ buttonLayout->addWidget( m_noAccountButton );
+
+ QSpacerItem* spacer = new QSpacerItem( 0, 67, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ buttonLayout->addItem( spacer );
+ m_layout->addLayout( buttonLayout );
+
+ connect(m_allAccountsButton, SIGNAL(clicked()), this, SLOT(slotSelectAllAccounts()));
+ connect(m_noAccountButton, SIGNAL(clicked()), this, SLOT(slotDeselectAllAccounts()));
+ connect(m_incomeCategoriesButton, SIGNAL(clicked()), this, SLOT(slotSelectIncomeCategories()));
+ connect(m_expenseCategoriesButton, SIGNAL(clicked()), this, SLOT(slotSelectExpenseCategories()));
+ }
+
+ // sort the list of accounts in ascending order
+ m_listView->setSorting(0);
+}
+
+kMyMoneyAccountSelector::~kMyMoneyAccountSelector()
+{
+}
+
+void kMyMoneyAccountSelector::removeButtons(void)
+{
+ delete m_allAccountsButton;
+ delete m_incomeCategoriesButton;
+ delete m_expenseCategoriesButton;
+ delete m_noAccountButton;
+}
+
+void kMyMoneyAccountSelector::selectCategories(const bool income, const bool expense)
+{
+ QListViewItem* it_v;
+
+ for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(static_cast<QCheckListItem*>(it_v)->text() == i18n("Income categories"))
+ selectAllSubItems(it_v, income);
+ else
+ selectAllSubItems(it_v, expense);
+ }
+ emit stateChanged();
+}
+
+void kMyMoneyAccountSelector::setSelectionMode(QListView::SelectionMode mode)
+{
+ m_incomeCategoriesButton->setHidden(mode == QListView::Multi);
+ m_expenseCategoriesButton->setHidden(mode == QListView::Multi);
+ KMyMoneySelector::setSelectionMode(mode);
+}
+
+QStringList kMyMoneyAccountSelector::accountList(const QValueList<MyMoneyAccount::accountTypeE>& filterList) const
+{
+ QStringList list;
+ QListViewItemIterator it;
+ QListViewItem* it_v;
+ QValueList<MyMoneyAccount::accountTypeE>::ConstIterator it_f;
+
+ it = QListViewItemIterator(m_listView, QListViewItemIterator::Selectable);
+ while((it_v = it.current()) != 0) {
+ {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(it_c->id());
+ it_f = filterList.find(acc.accountType());
+ if(filterList.count() == 0 || it_f != filterList.end())
+ list << it_c->id();
+ }
+ } else if(it_v->rtti() == 0) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(it_c->id());
+ it_f = filterList.find(acc.accountType());
+ if(filterList.count() == 0 || it_f != filterList.end())
+ list << it_c->id();
+ }
+ }
+ it++;
+ }
+ return list;
+}
+
+bool kMyMoneyAccountSelector::match(const QRegExp& exp, QListViewItem* item) const
+{
+ if(!item->isSelectable())
+ return false;
+
+ KMyMoneyListViewItem* it_l = dynamic_cast<KMyMoneyListViewItem*>(item);
+ if(!it_l) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(item);
+ if(!it_c) {
+ return KMyMoneySelector::match(exp, item);
+ }
+ return exp.search(it_c->key(1, true)) != -1;
+ }
+ return exp.search(it_l->key(1, true)) != -1;
+}
+
+bool kMyMoneyAccountSelector::contains(const QString& txt) const
+{
+ QListViewItemIterator it(m_listView, QListViewItemIterator::Selectable);
+ QListViewItem* it_v;
+
+ QString baseName = i18n("Asset") + "|" +
+ i18n("Liability") + "|" +
+ i18n("Income")+ "|" +
+ i18n("Expense")+ "|" +
+ i18n("Equity") + "|" +
+ i18n("Security");
+
+ while((it_v = it.current()) != 0) {
+ QRegExp exp(QString("^(?:%1):%2$").arg(baseName).arg(QRegExp::escape(txt)));
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(exp.search(it_c->key(1, true)) != -1) {
+ return true;
+ }
+ } else if(it_v->rtti() == 0) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ if(exp.search(it_c->key(1, true)) != -1) {
+ return true;
+ }
+ }
+ it++;
+ }
+ return false;
+}
+
+# if 0
+void kMyMoneyAccountSelector::update(const QString& /* id */)
+{
+ QListViewItem* it_v = m_listView->currentItem();
+ QString previousHighlighted;
+ bool state = false;
+
+ if(m_selMode == QListView::Multi && it_v) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = static_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ previousHighlighted = it_c->id();
+ state = it_c->isOn();
+ }
+ }
+ }
+
+ QStringList list = selectedAccounts();
+ QStringList::Iterator it;
+
+ if(!m_typeList.isEmpty())
+ loadList(m_typeList);
+ else if(!m_baseName.isEmpty()) {
+ loadList(m_baseName, m_accountList);
+ }
+
+ // because loadList() sets all accounts selected, we have to
+ // clear the selection and only turn on those, that were on
+ // before the update.
+ slotDeselectAllAccounts();
+ for(it = list.begin(); it != list.end(); ++it) {
+ setSelected(*it, true);
+ }
+
+ if(m_selMode == QListView::Multi) {
+ // make the previous highlighted item highlighted again
+ if(!previousHighlighted.isEmpty()) {
+ setSelected(previousHighlighted);
+ }
+ }
+}
+#endif
+
+AccountSet::AccountSet() :
+ m_count(0),
+ m_file(MyMoneyFile::instance()),
+ m_favorites(0),
+ m_hideClosedAccounts(true)
+{
+}
+
+void AccountSet::addAccountGroup(MyMoneyAccount::accountTypeE group)
+{
+ if(group == MyMoneyAccount::Asset) {
+ m_typeList << MyMoneyAccount::Checkings;
+ m_typeList << MyMoneyAccount::Savings;
+ m_typeList << MyMoneyAccount::Cash;
+ m_typeList << MyMoneyAccount::AssetLoan;
+ m_typeList << MyMoneyAccount::CertificateDep;
+ m_typeList << MyMoneyAccount::Investment;
+ m_typeList << MyMoneyAccount::Stock;
+ m_typeList << MyMoneyAccount::MoneyMarket;
+ m_typeList << MyMoneyAccount::Asset;
+ m_typeList << MyMoneyAccount::Currency;
+
+ } else if(group == MyMoneyAccount::Liability) {
+ m_typeList << MyMoneyAccount::CreditCard;
+ m_typeList << MyMoneyAccount::Loan;
+ m_typeList << MyMoneyAccount::Liability;
+
+ } else if(group == MyMoneyAccount::Income) {
+ m_typeList << MyMoneyAccount::Income;
+
+ } else if(group == MyMoneyAccount::Expense) {
+ m_typeList << MyMoneyAccount::Expense;
+
+ } else if(group == MyMoneyAccount::Equity) {
+ m_typeList << MyMoneyAccount::Equity;
+ }
+}
+
+void AccountSet::addAccountType(MyMoneyAccount::accountTypeE type)
+{
+ m_typeList << type;
+}
+
+void AccountSet::removeAccountType(MyMoneyAccount::accountTypeE type)
+{
+ QValueList<MyMoneyAccount::accountTypeE>::iterator it;
+ it = m_typeList.find(type);
+ if(it != m_typeList.end()) {
+ m_typeList.remove(it);
+ }
+}
+
+void AccountSet::clear(void)
+{
+ m_typeList.clear();
+}
+
+int AccountSet::load(kMyMoneyAccountSelector* selector)
+{
+ QStringList list;
+ QStringList::ConstIterator it_l;
+ int count = 0;
+ int typeMask = 0;
+ QString currentId;
+
+ if(selector->selectionMode() == QListView::Single) {
+ QStringList list;
+ selector->selectedItems(list);
+ if(list.count() > 0)
+ currentId = list.first();
+ }
+ if((m_typeList.contains(MyMoneyAccount::Checkings)
+ + m_typeList.contains(MyMoneyAccount::Savings)
+ + m_typeList.contains(MyMoneyAccount::Cash)
+ + m_typeList.contains(MyMoneyAccount::AssetLoan)
+ + m_typeList.contains(MyMoneyAccount::CertificateDep)
+ + m_typeList.contains(MyMoneyAccount::Investment)
+ + m_typeList.contains(MyMoneyAccount::Stock)
+ + m_typeList.contains(MyMoneyAccount::MoneyMarket)
+ + m_typeList.contains(MyMoneyAccount::Asset)
+ + m_typeList.contains(MyMoneyAccount::Currency)) > 0)
+ typeMask |= KMyMoneyUtils::asset;
+
+ if((m_typeList.contains(MyMoneyAccount::CreditCard)
+ + m_typeList.contains(MyMoneyAccount::Loan)
+ + m_typeList.contains(MyMoneyAccount::Liability)) > 0)
+ typeMask |= KMyMoneyUtils::liability;
+
+ if((m_typeList.contains(MyMoneyAccount::Income)) > 0)
+ typeMask |= KMyMoneyUtils::income;
+
+ if((m_typeList.contains(MyMoneyAccount::Expense)) > 0)
+ typeMask |= KMyMoneyUtils::expense;
+
+ if((m_typeList.contains(MyMoneyAccount::Equity)) > 0)
+ typeMask |= KMyMoneyUtils::equity;
+
+ selector->clear();
+ KListView* lv = selector->listView();
+ m_count = 0;
+ QString key;
+ QListViewItem* after = 0;
+
+ // create the favorite section first and sort it to the beginning
+ key = QString("A%1").arg(i18n("Favorites"));
+ m_favorites = selector->newItem(i18n("Favorites"), key);
+
+ for(int mask = 0x01; mask != KMyMoneyUtils::last; mask <<= 1) {
+ QListViewItem* item = 0;
+ if((typeMask & mask & KMyMoneyUtils::asset) != 0) {
+ ++m_count;
+ key = QString("B%1").arg(i18n("Asset"));
+ item = selector->newItem(i18n("Asset accounts"), key);
+ list = m_file->asset().accountList();
+ }
+
+ if((typeMask & mask & KMyMoneyUtils::liability) != 0) {
+ ++m_count;
+ key = QString("C%1").arg(i18n("Liability"));
+ item = selector->newItem(i18n("Liability accounts"), key);
+ list = m_file->liability().accountList();
+ }
+
+ if((typeMask & mask & KMyMoneyUtils::income) != 0) {
+ ++m_count;
+ key = QString("D%1").arg(i18n("Income"));
+ item = selector->newItem(i18n("Income categories"), key);
+ list = m_file->income().accountList();
+ if(selector->selectionMode() == QListView::Multi) {
+ selector->m_incomeCategoriesButton->show();
+ }
+ }
+
+ if((typeMask & mask & KMyMoneyUtils::expense) != 0) {
+ ++m_count;
+ key = QString("E%1").arg(i18n("Expense"));
+ item = selector->newItem(i18n("Expense categories"), key);
+ list = m_file->expense().accountList();
+ if(selector->selectionMode() == QListView::Multi) {
+ selector->m_expenseCategoriesButton->show();
+ }
+ }
+
+ if((typeMask & mask & KMyMoneyUtils::equity) != 0) {
+ ++m_count;
+ key = QString("F%1").arg(i18n("Equity"));
+ item = selector->newItem(i18n("Equity accounts"), key);
+ list = m_file->equity().accountList();
+ }
+
+ if(!after)
+ after = item;
+
+ if(item != 0) {
+ // scan all matching accounts found in the engine
+ for(it_l = list.begin(); it_l != list.end(); ++it_l) {
+ const MyMoneyAccount& acc = m_file->account(*it_l);
+ ++m_count;
+ ++count;
+ //this will include an account if it matches the account type and
+ //if it is still open or it has been set to show closed accounts
+ if(includeAccount(acc)
+ && (!isHidingClosedAccounts() || !acc.isClosed()) ) {
+ QString tmpKey;
+ tmpKey = key + MyMoneyFile::AccountSeperator + acc.name();
+ QListViewItem* subItem = selector->newItem(item, acc.name(), tmpKey, acc.id());
+ if(acc.value("PreferredAccount") == "Yes"
+ && m_typeList.contains(acc.accountType())) {
+ selector->newItem(m_favorites, acc.name(), tmpKey, acc.id());
+ }
+ if(acc.accountList().count() > 0) {
+ subItem->setOpen(true);
+ count += loadSubAccounts(selector, subItem, tmpKey, acc.accountList());
+ }
+
+ //disable the item if it has been added only because a subaccount matches the type
+ if( !m_typeList.contains(acc.accountType()) ) {
+ subItem->setEnabled(false);
+ }
+ }
+ }
+ item->sortChildItems(0, true);
+ }
+ }
+
+ // if we don't have a favorite account or the selector is for multi-mode
+ // we get rid of the favorite entry and subentries.
+ if(m_favorites->childCount() == 0 || selector->selectionMode() == QListView::Multi) {
+ delete m_favorites;
+ m_favorites = 0;
+ }
+
+ // sort the list
+ selector->listView()->sort();
+
+ if(lv->firstChild()) {
+ if(currentId.isEmpty()) {
+ lv->setCurrentItem(lv->firstChild());
+ lv->clearSelection();
+ } else {
+ selector->setSelected(currentId);
+ }
+ }
+ selector->update();
+ return count;
+}
+
+int AccountSet::load(kMyMoneyAccountSelector* selector, const QString& baseName, const QValueList<QString>& accountIdList, const bool clear)
+{
+ int count = 0;
+ QListViewItem* item = 0;
+
+ m_typeList.clear();
+ if(clear) {
+ m_count = 0;
+ selector->clear();
+ }
+
+ item = selector->newItem(baseName);
+ ++m_count;
+
+ QValueList<QString>::ConstIterator it;
+ for(it = accountIdList.begin(); it != accountIdList.end(); ++it) {
+ const MyMoneyAccount& acc = m_file->account(*it);
+ if(acc.isClosed())
+ continue;
+ QString tmpKey;
+ // the first character must be preset. Since we don't know any sort order here, we just use A
+ tmpKey = QString("A%1%2%3").arg(baseName, MyMoneyFile::AccountSeperator, acc.name());
+ selector->newItem(item, acc.name(), tmpKey, acc.id());
+ ++m_count;
+ ++count;
+ }
+
+ KListView* lv = selector->listView();
+ if(lv->firstChild()) {
+ lv->setCurrentItem(lv->firstChild());
+ lv->clearSelection();
+ }
+
+ selector->update();
+ return count;
+}
+
+int AccountSet::loadSubAccounts(kMyMoneyAccountSelector* selector, QListViewItem* parent, const QString& key, const QStringList& list)
+{
+ QStringList::ConstIterator it_l;
+ int count = 0;
+
+ for(it_l = list.begin(); it_l != list.end(); ++it_l) {
+ const MyMoneyAccount& acc = m_file->account(*it_l);
+ // don't include stock accounts if not in expert mode
+ if(acc.isInvest() && !KMyMoneyGlobalSettings::expertMode())
+ continue;
+
+ if(includeAccount(acc)
+ && !acc.isClosed()) {
+ QString tmpKey;
+ tmpKey = key + MyMoneyFile::AccountSeperator + acc.name();
+ ++count;
+ ++m_count;
+ QListViewItem* item = selector->newItem(parent, acc.name(), tmpKey, acc.id());
+ if(acc.value("PreferredAccount") == "Yes"
+ && m_typeList.contains(acc.accountType())) {
+ selector->newItem(m_favorites, acc.name(), tmpKey, acc.id());
+ }
+ if(acc.accountList().count() > 0) {
+ item->setOpen(true);
+ count += loadSubAccounts(selector, item, tmpKey, acc.accountList());
+ }
+
+ //disable the item if it has been added only because a subaccount matches the type
+ if( !m_typeList.contains(acc.accountType()) ) {
+ item->setEnabled(false);
+ }
+ }
+ }
+ return count;
+}
+
+bool AccountSet::includeAccount(const MyMoneyAccount& acc)
+{
+ if( m_typeList.contains(acc.accountType()) )
+ return true;
+
+ QStringList accounts = acc.accountList();
+
+ if(accounts.size() > 0) {
+ QStringList::ConstIterator it_acc;
+ for(it_acc = accounts.begin(); it_acc != accounts.end(); ++it_acc) {
+ MyMoneyAccount account = m_file->account(*it_acc);
+ if( includeAccount(account) )
+ return true;
+ }
+ }
+ return false;
+}
+
+
+#include "kmymoneyaccountselector.moc"
diff --git a/kmymoney2/widgets/kmymoneyaccountselector.h b/kmymoney2/widgets/kmymoneyaccountselector.h
new file mode 100644
index 0000000..2fc0635
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccountselector.h
@@ -0,0 +1,187 @@
+/***************************************************************************
+ kmymoneyaccountselector.h
+ -------------------
+ begin : Thu Sep 18 2003
+ copyright : (C) 2003 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTSELECTOR_H
+#define KMYMONEYACCOUNTSELECTOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KPushButton;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneyselector.h>
+#include <kmymoney/kmymoneyutils.h>
+#include <kmymoney/mymoneyaccount.h>
+
+class kMyMoneyAccountCompletion;
+class AccountSet;
+class MyMoneyFile;
+
+/**
+ * This class implements an account/category selector. It is based
+ * on a tree view. Using this widget, one can select one or multiple
+ * accounts depending on the mode of operation and the set of accounts
+ * selected to be displayed. (see setSelectionMode()
+ * and loadList() about the specifics of configuration).
+ *
+ * - Single selection mode\n
+ * In this mode the widget allows to select a single entry out of
+ * the set of displayed accounts.
+ *
+ * - Multi selection mode\n
+ * In this mode, the widget allows to select one or more entries
+ * out of the set of displayed accounts. Selection is performed
+ * by marking the account in the view.
+ */
+class kMyMoneyAccountSelector : public KMyMoneySelector
+{
+ Q_OBJECT
+public:
+ friend class AccountSet;
+
+ kMyMoneyAccountSelector(QWidget *parent=0, const char *name=0, QWidget::WFlags flags = 0, const bool createButtons = true);
+ virtual ~kMyMoneyAccountSelector();
+
+ /**
+ * This method returns a list of account ids of those accounts
+ * currently loaded into the widget. It is possible to select
+ * a list of specific account types only. In this case, pass
+ * a list of account types as parameter @p list.
+ *
+ * @param list QValueList of account types to be returned. If this
+ * list is empty (the default), then the ids of all accounts
+ * will be returned.
+ * @return QStringList of account ids
+ */
+ QStringList accountList(const QValueList<MyMoneyAccount::accountTypeE>& list = QValueList<MyMoneyAccount::accountTypeE>()) const;
+
+ void setSelectionMode(QListView::SelectionMode mode);
+
+ /**
+ * This method checks if a given @a item matches the given regular expression @a exp.
+ *
+ * @param exp const reference to a regular expression object
+ * @param item pointer to QListViewItem
+ *
+ * @retval true item matches
+ * @retval false item does not match
+ */
+ virtual bool match(const QRegExp& exp, QListViewItem* item) const;
+
+ /**
+ * This method returns, if any of the items in the selector contains
+ * the text @a txt.
+ *
+ * @param txt const reference to string to be looked for
+ * @retval true exact match found
+ * @retval false no match found
+ */
+ virtual bool contains(const QString& txt) const;
+
+ /**
+ * This method removes all the buttons of the widget
+ */
+ void removeButtons(void);
+
+public slots:
+ /**
+ * This slot selects all items that are currently in
+ * the account list of the widget.
+ */
+ void slotSelectAllAccounts(void) { selectAllItems(true); };
+
+ /**
+ * This slot deselects all items that are currently in
+ * the account list of the widget.
+ */
+ void slotDeselectAllAccounts(void) { selectAllItems(false); };
+
+protected:
+ /**
+ * This method loads the list of subaccounts as found in the
+ * @p list and attaches them to the parent widget passed as @p parent.
+ *
+ * @param parent pointer to parent widget
+ * @param list QStringList containing the ids of all subaccounts to load
+ * @return This method returns the number of accounts loaded into the list
+ */
+ int loadSubAccounts(QListViewItem* parent, const QStringList& list);
+
+ /**
+ * This is a helper method for selectAllIncomeCategories()
+ * and selectAllExpenseCategories().
+ */
+ void selectCategories(const bool income, const bool expense);
+
+protected slots:
+ /**
+ * This slot selects all income categories
+ */
+ void slotSelectIncomeCategories(void) { selectCategories(true, false); };
+
+ /**
+ * This slot selects all expense categories
+ */
+ void slotSelectExpenseCategories(void) { selectCategories(false, true); };
+
+protected:
+ KPushButton* m_allAccountsButton;
+ KPushButton* m_noAccountButton;
+ KPushButton* m_incomeCategoriesButton;
+ KPushButton* m_expenseCategoriesButton;
+ QValueList<int> m_typeList;
+ QStringList m_accountList;
+};
+
+
+class AccountSet
+{
+public:
+ AccountSet();
+
+ void addAccountType(MyMoneyAccount::accountTypeE type);
+ void addAccountGroup(MyMoneyAccount::accountTypeE type);
+ void removeAccountType(MyMoneyAccount::accountTypeE type);
+
+ void clear(void);
+
+ int load(kMyMoneyAccountSelector* selector);
+ int load(kMyMoneyAccountSelector* selector, const QString& baseName, const QValueList<QString>& accountIdList, const bool clear = false);
+
+ int count(void) const { return m_count; }
+
+ void setHideClosedAccounts (bool _bool) { m_hideClosedAccounts = _bool; }
+ bool isHidingClosedAccounts (void) { return m_hideClosedAccounts; }
+
+protected:
+ int loadSubAccounts(kMyMoneyAccountSelector* selector, QListViewItem* parent, const QString& key, const QStringList& list);
+ bool includeAccount(const MyMoneyAccount& acc);
+
+private:
+ int m_count;
+ MyMoneyFile* m_file;
+ QValueList<MyMoneyAccount::accountTypeE> m_typeList;
+ QListViewItem* m_favorites;
+ bool m_hideClosedAccounts;
+};
+#endif
diff --git a/kmymoney2/widgets/kmymoneyaccounttree.cpp b/kmymoney2/widgets/kmymoneyaccounttree.cpp
new file mode 100644
index 0000000..1b669ef
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttree.cpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+ kmymoneyaccounttree.cpp - description
+ -------------------
+ begin : Sat Jan 1 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpoint.h>
+#include <qevent.h>
+#include <qdragobject.h>
+#include <qtimer.h>
+#include <qcursor.h>
+#include <qheader.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include <kmymoney/kmymoneyutils.h>
+
+KMyMoneyAccountTree::KMyMoneyAccountTree(QWidget* parent, const char *name) :
+ KMyMoneyAccountTreeBase(parent,name)
+{
+ showType();
+
+ m_taxReportColumn = addColumn(i18n("Column heading for category in tax report", "Tax"));
+ setColumnWidthMode(m_taxReportColumn, QListView::Manual);
+ setColumnAlignment(m_taxReportColumn, Qt::AlignHCenter);
+
+ m_vatCategoryColumn = addColumn(i18n("Column heading for VAT category", "VAT"));
+ setColumnWidthMode(m_vatCategoryColumn, QListView::Manual);
+ setColumnAlignment(m_vatCategoryColumn, Qt::AlignHCenter);
+
+ showValue();
+}
+
+KMyMoneyAccountTreeItem::KMyMoneyAccountTreeItem(KListView *parent, const MyMoneyAccount& account, const MyMoneySecurity& security , const QString& name) :
+ KMyMoneyAccountTreeBaseItem(parent,account,security,name),
+ m_reconcileFlag(false)
+{
+ updateAccount();
+}
+
+KMyMoneyAccountTreeItem::KMyMoneyAccountTreeItem(KMyMoneyAccountTreeBaseItem *parent, const MyMoneyAccount& account, const QValueList<MyMoneyPrice>& price, const MyMoneySecurity& security) :
+ KMyMoneyAccountTreeBaseItem(parent,account,price,security),
+ m_reconcileFlag(false)
+{
+ updateAccount();
+}
+
+KMyMoneyAccountTreeItem::KMyMoneyAccountTreeItem(KListView *parent, const MyMoneyInstitution& institution) :
+ KMyMoneyAccountTreeBaseItem(parent,institution),
+ m_reconcileFlag(false)
+{
+}
+
+void KMyMoneyAccountTreeItem::fillColumns()
+{
+ KMyMoneyAccountTree* lv = dynamic_cast<KMyMoneyAccountTree*>(listView());
+ if (!lv)
+ return;
+ KMyMoneyAccountTreeBaseItem::fillColumns();
+ QPixmap checkMark = QPixmap(KGlobal::iconLoader()->loadIcon("ok", KIcon::Small));
+ MyMoneyMoney vatRate;
+ if (!isInstitution())
+ setPixmap(lv->nameColumn(), m_account.accountPixmap(m_reconcileFlag, 22));
+ switch(m_account.accountType()) {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ if(m_account.value("Tax").lower() == "yes")
+ setPixmap(lv->taxReportColumn(), checkMark);
+ if(!m_account.value("VatAccount").isEmpty()) {
+ setPixmap(lv->vatCategoryColumn(), checkMark);
+ }
+ if(!m_account.value("VatRate").isEmpty()) {
+ vatRate = MyMoneyMoney(m_account.value("VatRate")) * MyMoneyMoney(100,1);
+ setText(lv->vatCategoryColumn(), QString("%1 %").arg(vatRate.formatMoney("", 1)));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void KMyMoneyAccountTreeItem::setReconciliation(bool on)
+{
+ if(m_reconcileFlag == on)
+ return;
+ m_reconcileFlag = on;
+ updateAccount();
+}
+
+MyMoneyMoney KMyMoneyAccountTreeItem::balance() const
+{
+ MyMoneyMoney result;
+ // account.balance() is not compatable with stock accounts
+ if ( m_account.isInvest() )
+ result = MyMoneyFile::instance()->balance(m_account.id());
+ else
+ result = m_account.balance();
+ // for income and liability accounts, we reverse the sign
+ switch(m_account.accountGroup()) {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Equity:
+ result = -result;
+ break;
+
+ default:
+ break;
+ }
+ return result;
+}
+
+
+#include "kmymoneyaccounttree.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/widgets/kmymoneyaccounttree.h b/kmymoney2/widgets/kmymoneyaccounttree.h
new file mode 100644
index 0000000..a4b741d
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttree.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+ kmymoneyaccounttree.h - description
+ -------------------
+ begin : Sat Jan 1 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTTREE_H
+#define KMYMONEYACCOUNTTREE_H
+
+
+#include <kmymoney/kmymoneyaccounttreebase.h>
+
+class KMyMoneyAccountTreeItem;
+
+class KMyMoneyAccountTree : public KMyMoneyAccountTreeBase
+{
+ Q_OBJECT
+public:
+ KMyMoneyAccountTree(QWidget* parent = 0, const char *name = 0);
+ int taxReportColumn(void) const { return m_taxReportColumn; }
+ int vatCategoryColumn(void) const { return m_vatCategoryColumn; }
+private:
+ int m_taxReportColumn;
+ int m_vatCategoryColumn;
+};
+
+class KMyMoneyAccountTreeItem : public KMyMoneyAccountTreeBaseItem
+{
+public:
+ /**
+ * Constructor to be used to construct an institution entry
+ * object.
+ *
+ * @param parent pointer to the KListView object this entry should be
+ * added to.
+ * @param institution const reference to MyMoneyInstitution for which
+ * the KListView entry is constructed
+ */
+ KMyMoneyAccountTreeItem(KListView *parent, const MyMoneyInstitution& institution);
+
+ /**
+ * Constructor to be used to construct a standard account entry object (e.g. Asset,
+ * Liability, etc.).
+ *
+ * @param parent pointer to the KListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ * @param name name of the account to be used instead of the one stored with @p account
+ * If empty, the one stored with @p account will be used. Default: empty
+ */
+ KMyMoneyAccountTreeItem(KListView *parent, const MyMoneyAccount& account, const MyMoneySecurity& security = MyMoneySecurity(), const QString& name = QString());
+
+ /**
+ * Constructor to be used to construct an account entry
+ * object.
+ *
+ * @param parent pointer to the parent KAccountListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param price price to be used to calculate value (defaults to 1)
+ * This is used for accounts denominated in foreign currencies or stocks
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ */
+ KMyMoneyAccountTreeItem(KMyMoneyAccountTreeBaseItem *parent, const MyMoneyAccount& account, const QValueList<MyMoneyPrice>& price = QValueList<MyMoneyPrice>(), const MyMoneySecurity& security = MyMoneySecurity());
+
+ void setReconciliation(bool);
+
+
+protected:
+ /**
+ * Returns the current balance of this account.
+ *
+ * This is a pure virtual function, to allow subclasses to calculate
+ * the balance in different ways.
+ *
+ * Parent items in the tree will only be recomputed if the balance() for
+ * a son changes.
+ * @param account Account to get the balance for
+ * @return Balance of this account
+ */
+ MyMoneyMoney balance() const;
+
+ bool m_reconcileFlag;
+
+ /**
+ * populates the columns. Derived classes should override this. The
+ * name column is already filled and should not be changed.
+ */
+ void fillColumns();
+};
+
+#endif
+
diff --git a/kmymoney2/widgets/kmymoneyaccounttreebase.cpp b/kmymoney2/widgets/kmymoneyaccounttreebase.cpp
new file mode 100644
index 0000000..da35ea1
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttreebase.cpp
@@ -0,0 +1,825 @@
+/***************************************************************************
+ kmymoneyaccounttree.cpp - description
+ -------------------
+ begin : Sat Jan 1 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpoint.h>
+#include <qevent.h>
+#include <qdragobject.h>
+#include <qtimer.h>
+#include <qcursor.h>
+#include <qheader.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include <kmymoney/kmymoneyutils.h>
+
+KMyMoneyAccountTreeBase::KMyMoneyAccountTreeBase(QWidget* parent, const char* name) :
+ KListView(parent, name),
+ m_accountConnections(false),
+ m_institutionConnections(false),
+ m_queuedSort(0)
+{
+ setRootIsDecorated(true);
+ setAllColumnsShowFocus(true);
+
+ m_nameColumn = addColumn(i18n("Account"));
+ setColumnWidthMode(m_nameColumn, QListView::Manual);
+
+ m_typeColumn = -1;
+ m_balanceColumn = -1;
+ m_valueColumn = -1;
+
+ setMultiSelection(false);
+
+ setResizeMode(QListView::LastColumn);
+ setShowSortIndicator(true);
+ setSorting(0);
+
+ header()->setResizeEnabled(true);
+
+ setDragEnabled(false);
+ setAcceptDrops(false);
+ setItemsMovable(false);
+ setDropVisualizer(false);
+ setDropHighlighter(true);
+
+ // setup a default
+ m_baseCurrency.setSmallestAccountFraction(100);
+ m_baseCurrency.setSmallestCashFraction(100);
+
+ connect(this, SIGNAL(dropped(QDropEvent*,QListViewItem*,QListViewItem*)), this, SLOT(slotObjectDropped(QDropEvent*,QListViewItem*,QListViewItem*)));
+ connect(this, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotSelectObject(QListViewItem*)));
+ connect(this, SIGNAL(contextMenu(KListView*, QListViewItem* , const QPoint&)), this, SLOT(slotOpenContextMenu(KListView*, QListViewItem*, const QPoint&)));
+ connect(this, SIGNAL(doubleClicked(QListViewItem*,const QPoint&,int)), this, SLOT(slotOpenObject(QListViewItem*)));
+
+ // drag and drop timer connections
+ connect( &m_autoopenTimer, SIGNAL( timeout() ), this, SLOT( slotOpenFolder() ) );
+ connect( &m_autoscrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ) );
+
+}
+
+KMyMoneyAccountTreeBase::~KMyMoneyAccountTreeBase()
+{
+ if (!m_configGroup.isEmpty())
+ saveLayout(KGlobal::config(), m_configGroup);
+}
+
+void KMyMoneyAccountTreeBase::restoreLayout(const QString& group)
+{
+ if (!m_configGroup.isEmpty())
+ return; // already done
+ // make sure to use the previous settings. If no settings are found
+ // we use equal distribution of all fields as an initial setting
+ // TODO this only makes the first column invisible if settings exist setColumnWidth(0, 0);
+ m_configGroup = group;
+ KListView::restoreLayout(KGlobal::config(), m_configGroup);
+}
+
+void KMyMoneyAccountTreeBase::showType(void)
+{
+ m_typeColumn = addColumn(i18n("Type"));
+ setColumnWidthMode(m_typeColumn, QListView::Manual);
+ setColumnAlignment(m_typeColumn, Qt::AlignLeft);
+}
+
+void KMyMoneyAccountTreeBase::showValue(void)
+{
+ m_balanceColumn = addColumn(i18n("Total Balance"));
+ setColumnWidthMode(m_balanceColumn, QListView::Manual);
+ setColumnAlignment(m_balanceColumn, Qt::AlignRight);
+
+ m_valueColumn = addColumn(i18n("Total Value"));
+ setColumnWidthMode(m_valueColumn, QListView::Manual);
+ setColumnAlignment(m_valueColumn, Qt::AlignRight);
+}
+
+void KMyMoneyAccountTreeBase::connectNotify(const char * /* s */)
+{
+ // update drag and drop settings
+ m_accountConnections = (receivers(SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&))) != 0);
+ m_institutionConnections = (receivers(SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&))) != 0);
+ setDragEnabled(m_accountConnections | m_institutionConnections);
+ setAcceptDrops(m_accountConnections | m_institutionConnections);
+}
+
+void KMyMoneyAccountTreeBase::disconnectNotify(const char * /* s */)
+{
+ // update drag and drop settings
+ m_accountConnections = (receivers(SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&))) != 0);
+ m_institutionConnections = (receivers(SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&))) != 0);
+ setDragEnabled(m_accountConnections | m_institutionConnections);
+ setAcceptDrops(m_accountConnections | m_institutionConnections);
+}
+
+void KMyMoneyAccountTreeBase::setSectionHeader(const QString& txt)
+{
+ header()->setLabel(nameColumn(), txt);
+}
+
+KMyMoneyAccountTreeBaseItem* KMyMoneyAccountTreeBase::selectedItem(void) const
+{
+ return dynamic_cast<KMyMoneyAccountTreeBaseItem *>(KListView::selectedItem());
+}
+
+const KMyMoneyAccountTreeBaseItem* KMyMoneyAccountTreeBase::findItem(const QString& id) const
+{
+ // tried to use a QListViewItemIterator but that does not fit
+ // with the constness of this method. Arghhh.
+
+ QListViewItem* p = firstChild();
+ while(p) {
+ // item found, check for the id
+ KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(p);
+ if(item && item->id() == id)
+ break;
+
+ // item did not match, search the next one
+ QListViewItem* next = p->firstChild();
+ if(!next) {
+ while((next = p->nextSibling()) == 0) {
+ p = p->parent();
+ if(!p)
+ break;
+ }
+ }
+ p = next;
+ }
+
+ return dynamic_cast<KMyMoneyAccountTreeBaseItem*>(p);
+}
+
+bool KMyMoneyAccountTreeBase::dropAccountOnAccount(const MyMoneyAccount& accFrom, const MyMoneyAccount& accTo) const
+{
+ bool rc = false;
+
+ // it does not make sense to reparent an account to oneself
+ // or to reparent it to it's current parent
+ if(accTo.id() != accFrom.id()
+ && accFrom.parentAccountId() != accTo.id()) {
+ // Moving within a group is generally ok
+ rc = accTo.accountGroup() == accFrom.accountGroup();
+
+ // now check for exceptions
+ if(rc) {
+ if(accTo.accountType() == MyMoneyAccount::Investment
+ && !accFrom.isInvest())
+ rc = false;
+
+ else if(accFrom.isInvest()
+ && accTo.accountType() != MyMoneyAccount::Investment)
+ rc = false;
+
+ } else {
+ if(accFrom.accountGroup() == MyMoneyAccount::Income
+ && accTo.accountGroup() == MyMoneyAccount::Expense)
+ rc = true;
+
+ if(accFrom.accountGroup() == MyMoneyAccount::Expense
+ && accTo.accountGroup() == MyMoneyAccount::Income)
+ rc = true;
+ }
+
+ // if it's generally ok to drop here, make sure that
+ // the accTo does not have a child with the same name
+ const KMyMoneyAccountTreeBaseItem* to = findItem(accTo.id());
+ if(to) {
+ to = dynamic_cast<KMyMoneyAccountTreeBaseItem*> (to->firstChild());
+ while(to && rc) {
+ if(to->isAccount()) {
+ const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(to->itemObject());
+ if(acc.name() == accFrom.name())
+ rc = false;
+ }
+ to = dynamic_cast<KMyMoneyAccountTreeBaseItem*> (to->nextSibling());
+ }
+ }
+ }
+
+ return rc;
+}
+
+bool KMyMoneyAccountTreeBase::acceptDrag(QDropEvent* event) const
+{
+ bool rc;
+
+ if((rc = (acceptDrops()) && (event->source() == viewport()))) {
+ rc = false;
+ KMyMoneyAccountTreeBaseItem* to = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(itemAt( contentsToViewport(event->pos()) ));
+ QString fromId(event->encodedData("text/plain"));
+ const KMyMoneyAccountTreeBaseItem* from = findItem(fromId);
+
+ // we can only move accounts around
+ if(!from->isAccount())
+ from = 0;
+
+ if(to && from && !to->isChildOf(from)) {
+ const MyMoneyAccount& accFrom = dynamic_cast<const MyMoneyAccount&>(from->itemObject());
+
+ if(to->isAccount() && m_accountConnections) {
+ const MyMoneyAccount& accTo = dynamic_cast<const MyMoneyAccount&>(to->itemObject());
+ rc = dropAccountOnAccount(accFrom, accTo);
+
+ } else if(to->isInstitution() && m_institutionConnections) {
+ // Moving a non-stock account to an institution is ok
+ if(!accFrom.isInvest())
+ rc = true;
+ }
+ }
+ }
+
+ return rc;
+}
+
+void KMyMoneyAccountTreeBase::startDrag(void)
+{
+ QListViewItem* item = currentItem();
+ KMyMoneyAccountTreeBaseItem* p = dynamic_cast<KMyMoneyAccountTreeBaseItem *>(item);
+ if(!p)
+ return;
+
+ if(p->isAccount()) {
+ QTextDrag* drag = new QTextDrag(p->id(), viewport());
+ drag->setSubtype("plain");
+
+ // use the icon that is attached to the item to be dragged
+ if (p->pixmap(0)) {
+ QPixmap pixmap(*p->pixmap(0));
+ QPoint hotspot( pixmap.width() / 2, pixmap.height() / 2 );
+ drag->setPixmap(pixmap, hotspot);
+ }
+
+ if (drag->dragMove() && drag->target() != viewport())
+ emit moved();
+ }
+ return;
+}
+
+void KMyMoneyAccountTreeBase::slotObjectDropped(QDropEvent* event, QListViewItem* /* parent */, QListViewItem* /* after */)
+{
+ m_autoopenTimer.stop();
+ slotStopAutoScroll();
+ if(dropHighlighter())
+ cleanItemHighlighter();
+
+ KMyMoneyAccountTreeBaseItem* newParent = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(m_dropItem);
+ if(newParent) {
+ QString fromId(event->encodedData("text/plain"));
+ const KMyMoneyAccountTreeBaseItem* from = findItem(fromId);
+
+ // we can only move accounts around
+ if(!from->isAccount())
+ from = 0;
+
+ if(from) {
+ const MyMoneyAccount& accFrom = dynamic_cast<const MyMoneyAccount&>(from->itemObject());
+ if(newParent->isAccount()) {
+ const MyMoneyAccount& accTo = dynamic_cast<const MyMoneyAccount&>(newParent->itemObject());
+ if(dropAccountOnAccount(accFrom, accTo)) {
+ emit reparent(accFrom, accTo);
+ }
+
+ } else if(newParent->isInstitution()) {
+ if(!accFrom.isInvest()) {
+ const MyMoneyInstitution& institution = dynamic_cast<const MyMoneyInstitution&>(newParent->itemObject());
+ emit reparent(accFrom, institution);
+ }
+ }
+ }
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotSelectObject(QListViewItem* i)
+{
+ emit selectObject(MyMoneyInstitution());
+ emit selectObject(MyMoneyAccount());
+
+ KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(i);
+ if(item != 0) {
+ emit selectObject(item->itemObject());
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotOpenContextMenu(KListView* lv, QListViewItem* i, const QPoint&)
+{
+ Q_UNUSED(lv);
+
+ KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem *>(i);
+ if(item) {
+ emit selectObject(item->itemObject());
+
+ // Create a copy of the item since the original might be destroyed
+ // during processing of this signal.
+ if(item->isInstitution()) {
+ MyMoneyInstitution institution = dynamic_cast<const MyMoneyInstitution&>(item->itemObject());
+ emit openContextMenu(institution);
+ } else {
+ MyMoneyAccount account = dynamic_cast<const MyMoneyAccount&>(item->itemObject());
+ emit openContextMenu(account);
+ }
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotOpenObject(QListViewItem* i)
+{
+ KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem *>(i);
+ if(item) {
+ // Create a copy of the item since the original might be destroyed
+ // during processing of this signal.
+ if(item->isAccount()) {
+ MyMoneyAccount acc = dynamic_cast<const MyMoneyAccount&>(item->itemObject());
+ emit openObject(acc);
+ } else if(item->isInstitution()) {
+ MyMoneyInstitution inst = dynamic_cast<const MyMoneyInstitution&>(item->itemObject());
+ emit openObject(inst);
+ }
+ }
+}
+
+/* drag and drop support inspired partially from KMail */
+/* --------------------------------------------------- */
+static const int autoscrollMargin = 16;
+static const int initialScrollTime = 30;
+static const int initialScrollAccel = 5;
+static const int autoopenTime = 750;
+
+void KMyMoneyAccountTreeBase::slotOpenFolder(void)
+{
+ m_autoopenTimer.stop();
+ if ( m_dropItem && !m_dropItem->isOpen() ) {
+ m_dropItem->setOpen( TRUE );
+ m_dropItem->repaint();
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotStartAutoScroll(void)
+{
+ if ( !m_autoscrollTimer.isActive() ) {
+ m_autoscrollTime = initialScrollTime;
+ m_autoscrollAccel = initialScrollAccel;
+ m_autoscrollTimer.start( m_autoscrollTime );
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotStopAutoScroll(void)
+{
+ m_autoscrollTimer.stop();
+}
+
+void KMyMoneyAccountTreeBase::slotAutoScroll(void)
+{
+ // don't show a highlighter during scrolling
+ cleanItemHighlighter();
+
+ QPoint p = viewport()->mapFromGlobal( QCursor::pos() );
+
+ if ( m_autoscrollAccel-- <= 0 && m_autoscrollTime ) {
+ m_autoscrollAccel = initialScrollAccel;
+ m_autoscrollTime--;
+ m_autoscrollTimer.start( m_autoscrollTime );
+ }
+ int l = QMAX(1,(initialScrollTime-m_autoscrollTime));
+
+ int dx=0,dy=0;
+ if ( p.y() < autoscrollMargin ) {
+ dy = -l;
+ } else if ( p.y() > visibleHeight()-autoscrollMargin ) {
+ dy = +l;
+ }
+ if ( p.x() < autoscrollMargin ) {
+ dx = -l;
+ } else if ( p.x() > visibleWidth()-autoscrollMargin ) {
+ dx = +l;
+ }
+ if ( dx || dy ) {
+ scrollBy(dx, dy);
+ } else {
+ slotStopAutoScroll();
+ }
+}
+
+void KMyMoneyAccountTreeBase::contentsDragMoveEvent(QDragMoveEvent* e)
+{
+ QPoint vp = contentsToViewport(e->pos());
+ QRect inside_margin((contentsX() > 0) ? autoscrollMargin : 0,
+ (contentsY() > 0) ? autoscrollMargin : 0,
+ visibleWidth() - ((contentsX() + visibleWidth() < contentsWidth())
+ ? autoscrollMargin*2 : 0),
+ visibleHeight() - ((contentsY() + visibleHeight() < contentsHeight())
+ ? autoscrollMargin*2 : 0));
+
+ bool accepted = false;
+ QListViewItem *i = itemAt( vp );
+ if ( i ) {
+ accepted = acceptDrag(e);
+ if(accepted && !m_autoscrollTimer.isActive()) {
+ if (dropHighlighter()) {
+ QRect tmpRect = drawItemHighlighter(0, i);
+ if (tmpRect != m_lastDropHighlighter) {
+ cleanItemHighlighter();
+ m_lastDropHighlighter = tmpRect;
+ viewport()->repaint(tmpRect);
+ }
+ }
+ }
+ if ( !inside_margin.contains(vp) ) {
+ slotStartAutoScroll();
+ e->accept(QRect(0,0,0,0)); // Keep sending move events
+ m_autoopenTimer.stop();
+
+ } else {
+ if(accepted)
+ e->accept();
+ else
+ e->ignore();
+ if ( i != m_dropItem ) {
+ m_autoopenTimer.stop();
+ m_dropItem = i;
+ m_autoopenTimer.start( autoopenTime );
+ }
+ }
+ if ( accepted ) {
+ switch ( e->action() ) {
+ case QDropEvent::Copy:
+ case QDropEvent::Link:
+ break;
+ case QDropEvent::Move:
+ e->acceptAction();
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ e->ignore();
+ m_autoopenTimer.stop();
+ m_dropItem = 0;
+ }
+
+ if(!accepted && dropHighlighter())
+ cleanItemHighlighter();
+}
+
+void KMyMoneyAccountTreeBase::cleanItemHighlighter(void)
+{
+ if(m_lastDropHighlighter.isValid()) {
+ QRect rect=m_lastDropHighlighter;
+ m_lastDropHighlighter = QRect();
+ // make sure, we repaint a bit more. that's important during
+ // autoscroll. if we don't do that, parts of the highlighter
+ // do not get removed
+ rect.moveBy(-1, -1);
+ rect.setSize(rect.size() + QSize(2,2));
+ viewport()->repaint(rect, true);
+ }
+}
+
+void KMyMoneyAccountTreeBase::viewportPaintEvent(QPaintEvent* e)
+{
+ QListView::viewportPaintEvent(e);
+
+ if (m_lastDropHighlighter.isValid() && e->rect().intersects(m_lastDropHighlighter)) {
+ QPainter painter(viewport());
+
+ // This is where we actually draw the drop-highlighter
+ style().drawPrimitive(QStyle::PE_FocusRect, &painter, m_lastDropHighlighter, colorGroup(),
+ QStyle::Style_FocusAtBorder);
+ }
+}
+
+
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+const MyMoneyObject& KMyMoneyAccountTreeBaseItem::itemObject(void) const
+{
+ if(m_type == Institution)
+ return m_institution;
+ return m_account;
+}
+
+KMyMoneyAccountTreeBaseItem::KMyMoneyAccountTreeBaseItem(KListView *parent, const MyMoneyInstitution& institution) :
+ KListViewItem(parent),
+ m_totalValue(MyMoneyMoney(0)),
+ m_negative(false),
+ m_institution(institution),
+ m_type(Institution)
+{
+ setName();
+}
+
+KMyMoneyAccountTreeBaseItem::KMyMoneyAccountTreeBaseItem(KListView *parent, const MyMoneyAccount& account, const MyMoneySecurity& security, const QString& name) :
+ KListViewItem(parent),
+ m_security(security),
+ m_totalValue(MyMoneyMoney(0)),
+ m_account(account),
+ m_negative(false),
+ m_type(Account)
+{
+ if(!name.isEmpty()) {
+ // we do not want to modify the original account
+ MyMoneyAccount acc(account);
+ acc.setName(name);
+ m_account = acc;
+ }
+ setName();
+}
+
+KMyMoneyAccountTreeBaseItem::KMyMoneyAccountTreeBaseItem(KMyMoneyAccountTreeBaseItem *parent, const MyMoneyAccount& account, const QValueList<MyMoneyPrice>& price, const MyMoneySecurity& security) :
+ KListViewItem(parent),
+ m_price(price),
+ m_security(security),
+ m_totalValue(MyMoneyMoney(0)),
+ m_account(account),
+ m_negative(false),
+ m_type(Account)
+{
+ setName();
+}
+
+KMyMoneyAccountTreeBaseItem::~KMyMoneyAccountTreeBaseItem()
+{
+}
+
+const QString& KMyMoneyAccountTreeBaseItem::id(void) const
+{
+ if(m_type == Institution)
+ return m_institution.id();
+ return m_account.id();
+}
+
+bool KMyMoneyAccountTreeBaseItem::isChildOf(const QListViewItem* const item) const
+{
+ QListViewItem *p = parent();
+ while(p && p != item) {
+ p = p->parent();
+ }
+ return (p != 0);
+}
+
+MyMoneyMoney KMyMoneyAccountTreeBaseItem::value() const
+{
+ // calculate the new value by running down the price list
+ MyMoneyMoney result = balance();
+ QValueList<MyMoneyPrice>::const_iterator it_p;
+ QString security = m_security.id();
+ for(it_p = m_price.begin(); it_p != m_price.end(); ++it_p) {
+ result = (result * (MyMoneyMoney(1,1) / (*it_p).rate(security))).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()));
+ if((*it_p).from() == security)
+ security = (*it_p).to();
+ else
+ security = (*it_p).from();
+ }
+ if (listView())
+ result = result.convert(listView()->baseCurrency().smallestAccountFraction());
+ return result;
+}
+
+void KMyMoneyAccountTreeBaseItem::setName()
+{
+ KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
+ if (!lv)
+ return;
+ if (isInstitution()) {
+ setPixmap(lv->nameColumn(), m_institution.pixmap());
+ setText(lv->nameColumn(), m_institution.name());
+ } else {
+ setPixmap(lv->nameColumn(), m_account.accountPixmap(false, 22));
+ setText(lv->nameColumn(), m_account.name());
+#ifndef KMM_DESIGNER
+ if(lv->typeColumn()>=0 && !MyMoneyFile::instance()->isStandardAccount(m_account.id()))
+ setText(lv->typeColumn(), KMyMoneyUtils::accountTypeToString(m_account.accountType()));
+#endif
+ }
+}
+
+void KMyMoneyAccountTreeBaseItem::fillColumns()
+{
+ KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
+ if (!lv)
+ return;
+ if (lv->valueColumn()<0)
+ return;
+ // show the top accounts always in total value
+ if((isOpen() || m_account.accountList().count() == 0) && parent()) {
+
+ // only show the balance, if its a different security/currency
+ if(m_security.id() != listView()->baseCurrency().id()) {
+ setText(lv->balanceColumn(), balance().formatMoney(m_security));
+ }
+ setText(lv->valueColumn(), m_value.formatMoney(listView()->baseCurrency()) + " ");
+
+ } else {
+ setText(lv->balanceColumn(), " ");
+ if(parent())
+ setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()) + " ");
+ else
+ setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()));
+ }
+}
+
+void KMyMoneyAccountTreeBaseItem::updateAccount(bool forceTotalUpdate)
+{
+ MyMoneyMoney oldValue = m_value;
+ m_value = value();
+
+ fillColumns();
+
+ // check if we need to tell upstream account objects in the tree
+ // that the value has changed
+ if(oldValue != m_value || forceTotalUpdate) {
+ adjustTotalValue(m_value - oldValue);
+ if (listView())
+ listView()->emitValueChanged();
+ }
+}
+
+void KMyMoneyAccountTreeBaseItem::setOpen(bool open)
+{
+ if (open == isOpen())
+ return;
+ KListViewItem::setOpen(open);
+ fillColumns();
+
+ if(listView())
+ listView()->queueSort();
+}
+
+void KMyMoneyAccountTreeBaseItem::adjustTotalValue(const MyMoneyMoney& diff)
+{
+ m_totalValue += diff;
+
+ // if the entry has no children,
+ // or it is the top entry
+ // or it is currently not open
+ // we need to display the value of it
+ KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
+ if(!lv)
+ return;
+ if(!firstChild() || !parent() || (!isOpen() && firstChild())) {
+ if(firstChild())
+ setText(lv->balanceColumn(), " ");
+ if(parent())
+ setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()) + " ");
+ else
+ setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()));
+ }
+
+ // now make sure, the upstream accounts also get notified about the value change
+ KMyMoneyAccountTreeBaseItem* p = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(parent());
+ if(p != 0) {
+ p->adjustTotalValue(diff);
+ }
+}
+
+int KMyMoneyAccountTreeBaseItem::compare(QListViewItem* i, int col, bool ascending) const
+{
+ KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(i);
+ // do special sorting only if
+ // a) name
+ // b) account
+ // c) and different group
+ // d) value column
+ // in all other cases use the standard sorting
+ KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
+ if(lv && item) {
+ if (col == lv->nameColumn()) {
+ if(m_account.accountGroup() != item->m_account.accountGroup())
+ return (m_account.accountGroup() - item->m_account.accountGroup());
+ } else if (col == lv->balanceColumn() || col == lv->valueColumn()) {
+ MyMoneyMoney result = MyMoneyMoney(text(col)) - MyMoneyMoney(item->text(col));
+ if(result.isNegative())
+ return -1;
+ if(result.isZero())
+ return 0;
+ return 1;
+ }
+ }
+ // do standard sorting here
+ return KListViewItem::compare(i, col, ascending);
+}
+
+void KMyMoneyAccountTreeBaseItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align)
+{
+ QColorGroup cg2(cg);
+
+ //set item background
+ if(isAlternate())
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg2.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+
+#ifndef KMM_DESIGNER
+ // display base accounts in bold
+ QFont font = KMyMoneyGlobalSettings::listCellFont();
+ if(!parent())
+ font.setBold(true);
+
+ // strike out closed accounts
+ if(m_account.isClosed())
+ font.setStrikeOut(true);
+
+ p->setFont(font);
+#endif
+ //set text color
+ QColor textColour;
+ if(m_negative == true) {
+ textColour = KMyMoneyGlobalSettings::listNegativeValueColor(); //if the item is marked is marked as negative, all columns will be painted negative
+ } else {
+ textColour = m_columnsColor[column]; //otherwise, respect the color for each column
+ }
+ cg2.setColor(QColorGroup::Text, textColour);
+
+ QListViewItem::paintCell(p, cg2, column, width, align);
+}
+
+void KMyMoneyAccountTreeBase::expandCollapseAll(bool expand)
+{
+ QListViewItemIterator it(this);
+ QListViewItem* p;
+ while((p = it.current()) != 0) {
+ p->setOpen(expand);
+ ++it;
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotExpandAll(void)
+{
+ expandCollapseAll(true);
+}
+
+void KMyMoneyAccountTreeBase::slotCollapseAll(void)
+{
+ expandCollapseAll(false);
+}
+
+void KMyMoneyAccountTreeBase::queueSort(void)
+{
+ if (sortColumn() == balanceColumn() || sortColumn() == valueColumn()) {
+ ++m_queuedSort;
+ QTimer::singleShot(100, this, SLOT(slotActivateSort()));
+ }
+}
+
+void KMyMoneyAccountTreeBase::slotActivateSort(void)
+{
+ --m_queuedSort;
+ if(!m_queuedSort)
+ KListView::sort();
+}
+
+void KMyMoneyAccountTreeBaseItem::setNegative(bool isNegative)
+{
+ m_negative = isNegative;
+}
+
+void KMyMoneyAccountTreeBaseItem::setText( int column, const QString &text, const bool &negative)
+{
+ //if negative set the map to negative color according to KMyMoneySettings
+ if(negative) {
+ m_columnsColor[column] = KMyMoneyGlobalSettings::listNegativeValueColor();
+ } else {
+ m_columnsColor[column] = QColorGroup::Text;
+ }
+
+ KListViewItem::setText(column, text);
+}
+
+
+#include "kmymoneyaccounttreebase.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/widgets/kmymoneyaccounttreebase.h b/kmymoney2/widgets/kmymoneyaccounttreebase.h
new file mode 100644
index 0000000..4ee6a32
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttreebase.h
@@ -0,0 +1,475 @@
+/***************************************************************************
+ kmymoneyaccounttreebase.h - description
+ -------------------
+ begin : Sat Jan 1 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTTREEBASE_H
+#define KMYMONEYACCOUNTTREEBASE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtimer.h>
+class QDragObject;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyprice.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneybudget.h>
+
+class KMyMoneyAccountTreeBaseItem;
+
+class KMyMoneyAccountTreeBase : public KListView
+{
+ friend class KMyMoneyAccountTreeBaseItem;
+
+ Q_OBJECT
+public:
+ KMyMoneyAccountTreeBase(QWidget* parent = 0, const char *name = 0);
+ virtual ~KMyMoneyAccountTreeBase();
+
+ /**
+ * Modify the text shown in the header of the name column.
+ *
+ * @param txt the text to be used in the header
+ */
+ void setSectionHeader(const QString& txt);
+
+ /**
+ * overridden from base class implementation to return a pointer
+ * to a KMyMoneyAccountTreeBaseItem.
+ *
+ * @return pointer to currently selected item
+ */
+ KMyMoneyAccountTreeBaseItem* selectedItem(void) const;
+
+ /**
+ */
+ void setBaseCurrency(const MyMoneySecurity& currency) { m_baseCurrency = currency; };
+
+ const MyMoneySecurity& baseCurrency(void) const { return m_baseCurrency; };
+
+ void emitValueChanged(void) { emit valueChanged(); };
+
+ /**
+ * restores the layout from the config file
+ * @param group the group to be used from the config file.
+ * At destruction time, we will use this group name to save
+ * the layout.
+ */
+ void restoreLayout(const QString& group);
+
+public slots:
+ /** autoscroll support */
+ void slotStartAutoScroll(void);
+ void slotStopAutoScroll(void);
+ void slotExpandAll(void);
+ void slotCollapseAll(void);
+
+protected:
+ virtual bool acceptDrag (QDropEvent* event) const;
+ virtual void startDrag(void);
+ const KMyMoneyAccountTreeBaseItem* findItem(const QString& id) const;
+
+ /**
+ * This method checks, if account @p accFrom can be dropped onto
+ * account @p accTo.
+ *
+ * @param accFrom source account
+ * @param accTo new parent account for @p accFrom
+ * @retval true drop is ok
+ * @retval false drop is not ok (@p accTo cannot be parent of @p accFrom)
+ */
+ bool dropAccountOnAccount(const MyMoneyAccount& accFrom, const MyMoneyAccount& accTo) const;
+ // virtual void contentsDropEvent(QDropEvent*);
+
+ /**
+ * This member counts the connects to the signals
+ * newAccountParent(const MyMoneyAccount&, const MyMoneyAccount&)) and
+ * newAccountParent(const MyMoneyAccount&, const MyMoneyInstitution&))
+ * in m_accountConnections and m_institutionConnections.
+ */
+ void connectNotify(const char *);
+
+ /**
+ * This member counts the disconnects from the signals
+ * newAccountParent(const MyMoneyAccount&, const MyMoneyAccount&)) and
+ * newAccountParent(const MyMoneyAccount&, const MyMoneyInstitution&))
+ * in m_accountConnections and m_institutionConnections.
+ */
+ void disconnectNotify(const char *);
+
+ void contentsDragMoveEvent( QDragMoveEvent *e );
+
+ /**
+ * Reimplemented for internal reasons.
+ * Further reimplementations should call this function or else
+ * some features may not work correctly.
+ *
+ * The API is unaffected.
+ */
+ virtual void viewportPaintEvent(QPaintEvent*);
+
+ void expandCollapseAll(bool expand);
+
+ void queueSort(void);
+
+protected slots:
+ void slotObjectDropped(QDropEvent* event, QListViewItem* parent, QListViewItem* after);
+
+ /**
+ * Select the object pointed to by @p i. This slot emits selectObject signals
+ * with an emtpy MyMoneyAccount and an empty MyMoneyInstitution object
+ * to deselect current selections. If @p i points to a KMyMoneyAccountTreeItem
+ * object, it emits selectObject() for this item.
+ *
+ * @param i pointer to QListViewItem of object to be selected
+ */
+ void slotSelectObject(QListViewItem *i);
+
+ /**
+ * This slot is connected to the accout list view's contextMenu signal
+ * and checks if the item pointed to by @p i is either an account or institution
+ * and sends out the necessary signal openContextMenu.
+ *
+ * @param lv pointer to KListView
+ * @param i pointer to QListViewItem
+ * @param p position information
+ */
+ void slotOpenContextMenu(KListView* lv, QListViewItem* i, const QPoint& p);
+
+ /**
+ * This slot is connected to the accout list view's executed signal
+ * and checks if the item pointed to by @p i is either an account or institution
+ * and sends out the necessary signal openObject.
+ *
+ * @param i pointer to QListViewItem
+ */
+ void slotOpenObject(QListViewItem* i);
+
+ void slotAutoScroll(void);
+
+ /** Open the folder pointed to by m_dropItem */
+ void slotOpenFolder(void);
+
+ /** override KListView implementation */
+ void cleanItemHighlighter(void);
+
+ void slotActivateSort(void);
+
+private:
+ MyMoneySecurity m_baseCurrency;
+ bool m_accountConnections;
+ bool m_institutionConnections;
+ QTimer m_autoopenTimer;
+ QTimer m_autoscrollTimer;
+ int m_autoscrollTime;
+ int m_autoscrollAccel;
+ QListViewItem* m_dropItem;
+ QRect m_lastDropHighlighter;
+ int m_queuedSort;
+ int m_nameColumn;
+ int m_typeColumn;
+ int m_valueColumn;
+ int m_balanceColumn;
+ QString m_configGroup;
+
+public:
+ int typeColumn(void) const { return m_typeColumn; }
+ int nameColumn(void) const { return m_nameColumn; }
+ int balanceColumn(void) const { return m_balanceColumn; }
+ int valueColumn(void) const { return m_valueColumn; }
+
+ void showType(void);
+ void showValue(void);
+
+
+signals:
+ /**
+ * This signal is emitted whenever an object in the view is selected
+ *
+ * @param obj reference to actual MyMoneyObject (is either
+ * MyMoneyAccount or MyMoneyInstitution depending on selected item)
+ */
+ void selectObject(const MyMoneyObject& obj);
+
+ /**
+ * This signal is emitted whenever the user requests the context menu for an object
+ *
+ * @param obj reference to actual MyMoneyObject (is either
+ * MyMoneyAccount or MyMoneyInstitution depending on selected item)
+ */
+ void openContextMenu(const MyMoneyObject& obj);
+
+ /**
+ * This signal is emitted whenever the user requests to open an object
+ *
+ * @param obj reference to actual MyMoneyObject (is either
+ * MyMoneyAccount or MyMoneyInstitution depending on selected item)
+ */
+ void openObject(const MyMoneyObject& obj);
+
+ /**
+ * This signal is emitted whenever the value of an object changed
+ */
+ void valueChanged(void);
+
+ /**
+ * This signal is emitted, when the user selected to reparent the
+ * account @p acc to be a subordinate account of @p parent.
+ *
+ * @param acc const reference to account to be reparented
+ * @param parent const reference to new parent account
+ */
+ void reparent(const MyMoneyAccount& acc, const MyMoneyAccount& parent);
+
+ /**
+ * This signal is emitted, when the user selected to reparent the
+ * account @p acc to be a subordinate account of @p institution.
+ *
+ * @param acc const reference to account to be reparented
+ * @param institution const reference to new institution
+ */
+ void reparent(const MyMoneyAccount& acc, const MyMoneyInstitution& institution);
+};
+
+class KMyMoneyAccountTreeBaseItem : public KListViewItem
+{
+public:
+ typedef enum {
+ Account,
+ Institution
+ } KMyMoneyAccountTreeItemType;
+
+ /**
+ * Constructor to be used to construct an institution entry
+ * object.
+ *
+ * @param parent pointer to the KListView object this entry should be
+ * added to.
+ * @param institution const reference to MyMoneyInstitution for which
+ * the KListView entry is constructed
+ */
+ KMyMoneyAccountTreeBaseItem(KListView *parent, const MyMoneyInstitution& institution);
+
+ /**
+ * Constructor to be used to construct a standard account entry object (e.g. Asset,
+ * Liability, etc.).
+ *
+ * @param parent pointer to the KListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ * @param name name of the account to be used instead of the one stored with @p account
+ * If empty, the one stored with @p account will be used. Default: empty
+ */
+ KMyMoneyAccountTreeBaseItem(KListView *parent, const MyMoneyAccount& account, const MyMoneySecurity& security = MyMoneySecurity(), const QString& name = QString());
+
+ /**
+ * Constructor to be used to construct an account entry
+ * object.
+ *
+ * @param parent pointer to the parent KAccountListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param price price to be used to calculate value (defaults to 1)
+ * This is used for accounts denominated in foreign currencies or stocks
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ */
+ KMyMoneyAccountTreeBaseItem(KMyMoneyAccountTreeBaseItem *parent, const MyMoneyAccount& account, const QValueList<MyMoneyPrice>& price = QValueList<MyMoneyPrice>(), const MyMoneySecurity& security = MyMoneySecurity());
+
+ ~KMyMoneyAccountTreeBaseItem();
+
+ /**
+ * populates the columns. Derived classes should override this. The
+ * name column is already filled and should not be changed.
+ */
+ virtual void fillColumns();
+
+ /**
+ * This method loads new information into the item and updates the fields
+ *
+ * @param forceTotalUpdate set to true to force update of total values
+ * (used in constructor, should not be necessary to
+ * be set by application code)
+ *
+ */
+ void updateAccount(bool forceTotalUpdate = false);
+
+ /**
+ * This method checks, if the item contains an account or not.
+ *
+ * @retval true item holds an account
+ * @retval false item does not hold an account
+ */
+ bool isAccount(void) const { return m_type == Account; };
+
+ /**
+ * This method checks, if the item contains an institution or not.
+ *
+ * @retval true item holds an institution
+ * @retval false item does not hold an institution
+ */
+ bool isInstitution(void) const { return m_type == Institution; };
+
+ /**
+ * This method returns the id of the object held by this item
+ *
+ * @return const reference to id of object
+ */
+ const QString& id(void) const;
+
+ /**
+ * Helper method to show the right order
+ */
+ int compare(QListViewItem* i, int col, bool ascending) const;
+
+ /**
+ * If o is TRUE all child items are shown initially. The user can
+ * hide them by clicking the - icon to the left of the item. If
+ * o is FALSE, the children of this item are initially hidden.
+ * The user can show them by clicking the + icon to the left of the item.
+ *
+ * Overrides KListViewItem::setOpen() and exchanges the value field
+ * with either the value of this account and its subaccounts if @p o
+ * is false or the value of this account if @p o is true.
+ *
+ * @param o show item open (true) or closed (false)
+ */
+ virtual void setOpen(bool o);
+
+ /**
+ * This method is re-implemented from QListViewItem::paintCell().
+ * Besides the standard implementation, the QPainter is set
+ * according to the applications settings.
+ */
+ void paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align);
+
+ /**
+ * Convenience method to return casted pointer
+ */
+ KMyMoneyAccountTreeBase* listView(void) const { return dynamic_cast<KMyMoneyAccountTreeBase*>(KListViewItem::listView()); };
+
+ /**
+ * Return the type of entry
+ *
+ * @return type of this entry.
+ */
+ KMyMoneyAccountTreeItemType entryType(void) const { return m_type; };
+
+ /**
+ * This method returns a const reference to this item (either the m_account or m_institution)
+ * depending on m_type.
+ *
+ * @return reference to the MyMoneyObject of this entry
+ */
+ const MyMoneyObject& itemObject(void) const;
+
+ /**
+ * This method returns the value of this account and all it's subordinate accounts.
+ *
+ * @return value of this account including all subordinate accounts
+ */
+ const MyMoneyMoney& totalValue(void) const { return m_totalValue; };
+
+ /**
+ * This method adjusts the current total value by @p diff.
+ *
+ * @param diff difference to be added to the current value to
+ * get the new value
+ */
+ void adjustTotalValue(const MyMoneyMoney& diff);
+
+ /**
+ * Checks whether this object is a child of the one passed
+ * by @p item.
+ *
+ * @param item pointer to other KMyMoneyAccountTreeItem that
+ * should be checked for parent/grand-parenthood of this
+ * object
+ * @retval true @p this object is a decendant of @p item
+ * @retval false @p this object is no decendant of @p item
+ */
+ bool isChildOf(const QListViewItem* const item) const;
+
+ /**
+ * Sets the whole item to be shown with negative colors
+ */
+ void setNegative(bool isNegative);
+
+ /**
+ * Sets the text of a given column. @param negative indicates whether it should
+ * be shown as negative number or not
+ */
+ void setText( int column, const QString &text, const bool &negative = false );
+
+protected:
+ /**
+ * Returns the current balance of this account.
+ *
+ * This is a pure virtual function, to allow subclasses to calculate
+ * the balance in different ways.
+ *
+ * Parent items in the tree will only be recomputed if the balance() for
+ * a child changes.
+ * @param account Account to get the balance for
+ * @return Balance of this account
+ */
+ virtual MyMoneyMoney balance() const = 0;
+
+ /**
+ * Computes and returns the current value of the account held by this item.
+ * This is the same as balance() but in the currency of the view.
+ * if value() changed since the item has been displayed, updateAccount()
+ * will notify the parent.
+ * @return value of the account held by this item
+ */
+ MyMoneyMoney value() const;
+
+protected:
+ MyMoneyMoney m_value;
+ QValueList<MyMoneyPrice> m_price;
+ MyMoneySecurity m_security;
+ MyMoneyMoney m_totalValue;
+ MyMoneyAccount m_account;
+ QMap<int, QColor> m_columnsColor;
+ bool m_negative;
+
+private:
+ MyMoneyInstitution m_institution;
+ KMyMoneyAccountTreeItemType m_type;
+
+ /**
+ * fills the name column with text and pixmap
+ */
+ void setName();
+
+};
+
+#endif
+
diff --git a/kmymoney2/widgets/kmymoneyaccounttreebudget.cpp b/kmymoney2/widgets/kmymoneyaccounttreebudget.cpp
new file mode 100644
index 0000000..cd1da0b
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttreebudget.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ kmymoneyaccounttreebudget.cpp - description
+ -------------------
+ begin : Tue Feb 21 2006
+ copyright : (C) 2005 by Darren Gould
+ email : Darren Gould <darren_gould@gmx.de>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include <kmymoneyaccounttreebudget.h>
+
+KMyMoneyAccountTreeBudget::KMyMoneyAccountTreeBudget(QWidget* parent, const char* name) :
+ KMyMoneyAccountTreeBase::KMyMoneyAccountTreeBase(parent, name)
+{
+ showType();
+ showValue();
+}
+
+void KMyMoneyAccountTreeBudget::slotSelectObject(const QListViewItem* i)
+{
+ emit selectObject(MyMoneyInstitution());
+ emit selectObject(MyMoneyAccount());
+
+ const KMyMoneyAccountTreeBaseItem* item = dynamic_cast<const KMyMoneyAccountTreeBaseItem*>(i);
+ if(item) {
+ emit openObject(item->itemObject());
+ }
+}
+
+KMyMoneyAccountTreeBudgetItem::KMyMoneyAccountTreeBudgetItem(KListView *parent, const MyMoneyAccount& account, const MyMoneyBudget &budget, const MyMoneySecurity& security, const QString& name) :
+ KMyMoneyAccountTreeBaseItem(parent, account, security, name),
+ m_budget(budget)
+{
+ updateAccount(true);
+}
+
+KMyMoneyAccountTreeBudgetItem::KMyMoneyAccountTreeBudgetItem(KMyMoneyAccountTreeBudgetItem *parent, const MyMoneyAccount& account, const MyMoneyBudget& budget, const QValueList<MyMoneyPrice>& price, const MyMoneySecurity& security) :
+ KMyMoneyAccountTreeBaseItem(parent, account, price, security),
+ m_budget(budget)
+{
+ updateAccount(true);
+}
+
+
+KMyMoneyAccountTreeBudgetItem::~KMyMoneyAccountTreeBudgetItem()
+{
+}
+
+void KMyMoneyAccountTreeBudgetItem::setBudget(const MyMoneyBudget& budget)
+{
+ m_budget = budget;
+ updateAccount();
+}
+
+MyMoneyMoney KMyMoneyAccountTreeBudgetItem::balance() const
+{
+ MyMoneyMoney result = MyMoneyMoney();
+ // find out if the account is budgeted
+ MyMoneyBudget::AccountGroup budgetAccount = m_budget.account( m_account.id() );
+ if ( budgetAccount.id() == m_account.id() ) {
+ result = budgetAccount.balance();
+ switch(budgetAccount.budgetLevel()) {
+ case MyMoneyBudget::AccountGroup::eMonthly:
+ result = result * 12;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+#include "kmymoneyaccounttreebudget.moc"
diff --git a/kmymoney2/widgets/kmymoneyaccounttreebudget.h b/kmymoney2/widgets/kmymoneyaccounttreebudget.h
new file mode 100644
index 0000000..86c1b07
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttreebudget.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ kmymoneyaccounttreebudget.h - description
+ -------------------
+ begin : Tue Feb 21 2006
+ copyright : (C) 2005 by Darren Gould
+ email : Darren Gould <darren_gould@gmx.de>
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTTREEBUDGET_H
+#define KMYMONEYACCOUNTTREEBUDGET_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtimer.h>
+class QDragObject;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kmymoneyaccounttree.h"
+#include "../../kmymoney/mymoneybudget.h"
+
+class KMyMoneyAccountTreeBudgetItem;
+
+class KMyMoneyAccountTreeBudget : public KMyMoneyAccountTreeBase
+{
+ Q_OBJECT
+public:
+ KMyMoneyAccountTreeBudget(QWidget* parent = 0, const char *name = 0);
+ virtual ~KMyMoneyAccountTreeBudget() {}
+
+public slots:
+ void slotSelectObject(const QListViewItem* i);
+
+};
+
+class KMyMoneyAccountTreeBudgetItem : public KMyMoneyAccountTreeBaseItem
+{
+public:
+
+ /**
+ * Constructor to be used to construct an account
+ * entry object for a budget.
+ *
+ * @param parent pointer to the parent KAccountListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param budget const reference to the budget to
+ * which the account belongs
+ * @param price price to be used to calculate value (defaults to 1)
+ * This is used for accounts denominated in foreign currencies or stocks
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ */
+ KMyMoneyAccountTreeBudgetItem(KMyMoneyAccountTreeBudgetItem *parent, const MyMoneyAccount& account, const MyMoneyBudget& budget, const QValueList<MyMoneyPrice>& price = QValueList<MyMoneyPrice>(), const MyMoneySecurity& security = MyMoneySecurity());
+
+ /**
+ * Constructor to be used to construct an account
+ * entry object for a budget.
+ *
+ * @param parent pointer to the parent KAccountListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param budget const reference to the budget to
+ * which the account belongs
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ * @param name name of the account to be used instead of the one stored with @p account
+ * If empty, the one stored with @p account will be used. Default: empty
+ */
+ KMyMoneyAccountTreeBudgetItem(KListView *parent, const MyMoneyAccount& account, const MyMoneyBudget &budget, const MyMoneySecurity& security = MyMoneySecurity(), const QString& name = QString());
+
+ ~KMyMoneyAccountTreeBudgetItem();
+
+ void setBudget(const MyMoneyBudget& budget);
+
+protected:
+ /**
+ * Returns the current balance of this account.
+ *
+ * This is a pure virtual function, to allow subclasses to calculate
+ * the balance in different ways.
+ *
+ * Parent items in the tree will only be recomputed if the balance() for
+ * a son changes.
+ * @param account Account to get the balance for
+ * @return Balance of this account
+ */
+ MyMoneyMoney balance() const;
+
+private:
+ MyMoneyBudget m_budget;
+};
+
+#endif
+
diff --git a/kmymoney2/widgets/kmymoneyaccounttreeforecast.cpp b/kmymoney2/widgets/kmymoneyaccounttreeforecast.cpp
new file mode 100644
index 0000000..0da5194
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttreeforecast.cpp
@@ -0,0 +1,401 @@
+/***************************************************************************
+ kmymoneyaccounttreeforecast.cpp
+ -------------------
+ begin : Fri Aug 01 2008
+ copyright : (C) 2008 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoneyaccounttreeforecast.h>
+#include "../kmymoney2.h"
+#include "../kmymoneyglobalsettings.h"
+#include "../mymoney/mymoneyforecast.h"
+#include "../reports/reportaccount.h"
+
+using namespace reports;
+
+KMyMoneyAccountTreeForecast::KMyMoneyAccountTreeForecast(QWidget* parent, const char* name) :
+ KMyMoneyAccountTreeBase::KMyMoneyAccountTreeBase(parent, name)
+{
+ setResizeMode(QListView::NoColumn);
+}
+
+void KMyMoneyAccountTreeForecast::showAccount( void )
+{
+ addColumn(i18n("Account"));
+}
+
+void KMyMoneyAccountTreeForecast::clearColumns( void )
+{
+ clear();
+ while(columns() > 0) {
+ removeColumn(0);
+ }
+}
+
+void KMyMoneyAccountTreeForecast::showSummary(MyMoneyForecast& forecast)
+{
+ int daysToBeginDay;
+
+ //add cycle interval columns
+ addColumn(i18n("Current"), -1);
+
+ //if beginning of forecast is today, set the begin day to next cycle to avoid repeating the first cycle
+ if(QDate::currentDate() < forecast.beginForecastDate()) {
+ daysToBeginDay = QDate::currentDate().daysTo(forecast.beginForecastDate());
+ } else {
+ daysToBeginDay = forecast.accountsCycle();
+ }
+ for(int i = 0; ((i*forecast.accountsCycle())+daysToBeginDay) <= forecast.forecastDays(); ++i) {
+ int intervalDays = ((i*forecast.accountsCycle())+daysToBeginDay);
+ QString columnName = i18n("%1 days").arg(intervalDays, 0, 10);
+ addColumn(columnName, -1);
+ }
+
+ //add variation columns
+ addColumn(i18n("Total variation"), -1);
+
+ //align columns
+ for(int i = 1; i < columns(); ++i) {
+ setColumnAlignment(i, Qt::AlignRight);
+ }
+
+}
+
+void KMyMoneyAccountTreeForecast::showDetailed(MyMoneyForecast& forecast)
+{
+ //add cycle interval columns
+ addColumn(i18n("Current"), -1);
+
+ for(int i = 1; i <= forecast.forecastDays(); ++i) {
+ QDate forecastDate = QDate::currentDate().addDays(i);
+ QString columnName = KGlobal::locale()->formatDate(forecastDate, true);
+ addColumn(columnName, -1);
+ }
+
+ //add variation columns
+ addColumn(i18n("Total variation"), -1);
+
+ //align columns
+ for(int i = 1; i < columns(); ++i) {
+ setColumnAlignment(i, Qt::AlignRight);
+ }
+}
+
+void KMyMoneyAccountTreeForecast::showAdvanced(MyMoneyForecast& forecast)
+{
+ int daysToBeginDay;
+
+ //if beginning of forecast is today, set the begin day to next cycle to avoid repeating the first cycle
+ if(QDate::currentDate() < forecast.beginForecastDate()) {
+ daysToBeginDay = QDate::currentDate().daysTo(forecast.beginForecastDate());
+ } else {
+ daysToBeginDay = forecast.accountsCycle();
+ }
+
+ //add columns
+ for(int i = 1; ((i * forecast.accountsCycle()) + daysToBeginDay) <= forecast.forecastDays(); ++i) {
+ int col = addColumn(i18n("Min Bal %1").arg(i), -1);
+ setColumnAlignment(col, Qt::AlignRight);
+ addColumn(i18n("Min Date %1").arg(i), -1);
+ }
+ for(int i = 1; ((i * forecast.accountsCycle()) + daysToBeginDay) <= forecast.forecastDays(); ++i) {
+ int col = addColumn(i18n("Max Bal %1").arg(i), -1);
+ setColumnAlignment(col, Qt::AlignRight);
+ addColumn(i18n("Max Date %1").arg(i), -1);
+ }
+ int col = addColumn(i18n("Average"), -1);
+ setColumnAlignment(col, Qt::AlignRight);
+}
+
+void KMyMoneyAccountTreeForecast::showBudget(MyMoneyForecast& forecast)
+{
+ QDate forecastStartDate = forecast.forecastStartDate();
+ QDate forecastEndDate = forecast.forecastEndDate();
+
+ //add cycle interval columns
+ QDate f_date = forecastStartDate;
+ for(; f_date <= forecastEndDate; f_date = f_date.addMonths(1)) {
+ QString columnName = QDate::longMonthName(f_date.month());
+ addColumn(columnName, -1);
+ }
+ //add total column
+ addColumn(i18n("Total"), -1);
+
+
+ //align columns
+ for(int i = 1; i < columns(); ++i) {
+ setColumnAlignment(i, Qt::AlignRight);
+ }
+}
+
+void KMyMoneyAccountTreeForecast::slotSelectObject(const QListViewItem* i)
+{
+ emit selectObject(MyMoneyInstitution());
+ emit selectObject(MyMoneyAccount());
+
+ const KMyMoneyAccountTreeBaseItem* item = dynamic_cast<const KMyMoneyAccountTreeBaseItem*>(i);
+ if(item) {
+ emit openObject(item->itemObject());
+ }
+}
+
+KMyMoneyAccountTreeForecastItem::KMyMoneyAccountTreeForecastItem(KListView *parent, const MyMoneyAccount& account, const MyMoneyForecast &forecast, const MyMoneySecurity& security, const QString& name) :
+ KMyMoneyAccountTreeBaseItem(parent, account, security, name),
+ m_forecast(forecast)
+{
+ updateAccount(true);
+
+}
+
+KMyMoneyAccountTreeForecastItem::KMyMoneyAccountTreeForecastItem(KMyMoneyAccountTreeForecastItem *parent, const MyMoneyAccount& account, const MyMoneyForecast& forecast, const QValueList<MyMoneyPrice>& price, const MyMoneySecurity& security, const EForecastViewType forecastType) :
+ KMyMoneyAccountTreeBaseItem(parent, account, price, security),
+ m_forecast(forecast),
+ m_forecastType(forecastType)
+{
+ //setForecastViewType(forecastViewType);
+ updateAccount(true);
+ switch(forecastViewType())
+ {
+ case eSummary:
+ updateSummary();
+ break;
+ case eDetailed:
+ updateDetailed();
+ break;
+ case eBudget:
+ updateBudget();
+ break;
+ default:
+ break;
+ }
+}
+
+
+KMyMoneyAccountTreeForecastItem::~KMyMoneyAccountTreeForecastItem()
+{
+}
+
+void KMyMoneyAccountTreeForecastItem::setForecast(const MyMoneyForecast& forecast)
+{
+ m_forecast = forecast;
+ updateAccount();
+}
+
+void KMyMoneyAccountTreeForecastItem::updateSummary()
+{
+ MyMoneyMoney amountMM;
+ int it_c = 1; // iterator for the columns of the listview
+ MyMoneyFile* file = MyMoneyFile::instance();
+ int daysToBeginDay;
+
+ if(QDate::currentDate() < m_forecast.beginForecastDate()) {
+ daysToBeginDay = QDate::currentDate().daysTo(m_forecast.beginForecastDate());
+ } else {
+ daysToBeginDay = m_forecast.accountsCycle();
+ }
+
+ MyMoneySecurity currency;
+ if(m_account.isInvest()) {
+ MyMoneySecurity underSecurity = file->security(m_account.currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security(m_account.currencyId());
+ }
+
+
+ //add current balance column
+ QDate summaryDate = QDate::currentDate();
+ amountMM = m_forecast.forecastBalance(m_account, summaryDate);
+
+ //calculate the balance in base currency for the total row
+ setAmount(it_c, amountMM);
+ setValue(it_c, amountMM, summaryDate);
+ showAmount(it_c, amountMM, currency);
+ it_c++;
+
+ //iterate through all other columns
+ for(QDate summaryDate = QDate::currentDate().addDays(daysToBeginDay); summaryDate <= m_forecast.forecastEndDate();summaryDate = summaryDate.addDays(m_forecast.accountsCycle()), ++it_c) {
+ amountMM = m_forecast.forecastBalance(m_account, summaryDate);
+
+ //calculate the balance in base currency for the total row
+ setAmount(it_c, amountMM);
+ setValue(it_c, amountMM, summaryDate);
+ showAmount(it_c, amountMM, currency);
+ }
+ //calculate and add variation per cycle
+ setNegative(m_forecast.accountTotalVariation(m_account).isNegative());
+ setAmount(it_c, m_forecast.accountTotalVariation(m_account));
+ setValue(it_c, m_forecast.accountTotalVariation(m_account), m_forecast.forecastEndDate());
+ showAmount(it_c, m_forecast.accountTotalVariation(m_account), currency);
+}
+
+void KMyMoneyAccountTreeForecastItem::updateDetailed()
+{
+ QString amount;
+ QString vAmount;
+ MyMoneyMoney vAmountMM;
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ MyMoneySecurity currency;
+ if(m_account.isInvest()) {
+ MyMoneySecurity underSecurity = file->security(m_account.currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security(m_account.currencyId());
+ }
+
+ int it_c = 1; // iterator for the columns of the listview
+
+ for(QDate forecastDate = QDate::currentDate(); forecastDate <= m_forecast.forecastEndDate(); ++it_c, forecastDate = forecastDate.addDays(1)) {
+ MyMoneyMoney amountMM = m_forecast.forecastBalance(m_account, forecastDate);
+
+ //calculate the balance in base currency for the total row
+ setAmount(it_c, amountMM);
+ setValue(it_c, amountMM, forecastDate);
+ showAmount(it_c, amountMM, currency);
+ }
+
+ //calculate and add variation per cycle
+ vAmountMM = m_forecast.accountTotalVariation(m_account);
+ setAmount(it_c, vAmountMM);
+ setValue(it_c, vAmountMM, m_forecast.forecastEndDate());
+ showAmount(it_c, vAmountMM, currency);
+}
+
+void KMyMoneyAccountTreeForecastItem::updateBudget()
+{
+ MyMoneySecurity currency;
+ MyMoneyMoney tAmountMM;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ int it_c = 1; // iterator for the columns of the listview
+ QDate forecastDate = m_forecast.forecastStartDate();
+
+ if(m_account.isInvest()) {
+ MyMoneySecurity underSecurity = file->security(m_account.currencyId());
+ currency = file->security(underSecurity.tradingCurrency());
+ } else {
+ currency = file->security(m_account.currencyId());
+ }
+
+ //iterate columns
+ for(; forecastDate <= m_forecast.forecastEndDate(); forecastDate = forecastDate.addMonths(1), ++it_c) {
+ MyMoneyMoney amountMM;
+ amountMM = m_forecast.forecastBalance(m_account,forecastDate);
+ if(m_account.accountType() == MyMoneyAccount::Expense)
+ amountMM = -amountMM;
+
+ tAmountMM += amountMM;
+ setAmount(it_c, amountMM);
+ setValue(it_c, amountMM, forecastDate);
+ showAmount(it_c, amountMM, currency);
+ }
+
+ //set total column
+ setAmount(it_c, tAmountMM);
+ setValue(it_c, tAmountMM, m_forecast.forecastEndDate());
+ showAmount(it_c, tAmountMM, currency);
+}
+
+MyMoneyMoney KMyMoneyAccountTreeForecastItem::balance() const
+{
+ return MyMoneyMoney();
+}
+
+void KMyMoneyAccountTreeForecastItem::showAmount(int column, const MyMoneyMoney amount, const MyMoneySecurity security)
+{
+ setText(column, amount.formatMoney(m_account, security), amount.isNegative() );
+}
+
+void KMyMoneyAccountTreeForecastItem::adjustParentValue(int column, const MyMoneyMoney& value)
+{
+ m_values[column] += value;
+ m_values[column] = m_values[column].convert(listView()->baseCurrency().smallestAccountFraction());
+
+ // if the entry has no children,
+ // or it is the top entry
+ // or it is currently not open
+ // we need to display the value of it
+ KMyMoneyAccountTreeForecast* lv = dynamic_cast<KMyMoneyAccountTreeForecast*>(listView());
+ if(!lv)
+ return;
+ if(!firstChild() || !parent() || (!isOpen() && firstChild())
+ || depth() == 1 ) {
+ if(firstChild())
+ setText(column, " ");
+
+ showAmount(column, m_values[column], listView()->baseCurrency());
+ }
+
+ // now make sure, the upstream accounts also get notified about the value change
+ KMyMoneyAccountTreeForecastItem* p = dynamic_cast<KMyMoneyAccountTreeForecastItem*>(parent());
+ if(p != 0) {
+ p->adjustParentValue(column, value);
+ }
+}
+
+void KMyMoneyAccountTreeForecastItem::setValue(int column, MyMoneyMoney amount, QDate forecastDate)
+{
+ KMyMoneyAccountTreeForecastItem* p = dynamic_cast<KMyMoneyAccountTreeForecastItem*>(parent());
+
+ //calculate the balance in base currency for the total row
+ if(m_account.currencyId() != listView()->baseCurrency().id()) {
+ ReportAccount repAcc = ReportAccount(m_account.id());
+ MyMoneyMoney curPrice = repAcc.baseCurrencyPrice(forecastDate);
+ MyMoneyMoney baseAmountMM = amount * curPrice;
+ m_values[column] = baseAmountMM.convert(listView()->baseCurrency().smallestAccountFraction());
+
+ if(p != 0) {
+ p->adjustParentValue(column, m_values[column]);
+ }
+ } else {
+ m_values[column] += amount;
+ if(p != 0) {
+ p->adjustParentValue(column, amount);
+ }
+ }
+}
+
+void KMyMoneyAccountTreeForecastItem::setAmount(int column, MyMoneyMoney amount)
+{
+ m_amounts[column] = amount;
+}
+
+void KMyMoneyAccountTreeForecastItem::setOpen(bool open)
+{
+ if (open == isOpen())
+ return;
+ KMyMoneyAccountTreeBaseItem::setOpen(open);
+
+ if(!open)
+ {
+ for(int i = 1; i < listView()->columns(); ++i)
+ {
+ showAmount(i, m_values[i], listView()->baseCurrency());
+ }
+ } else if (depth() > 1) {
+ for(int i = 1; i < listView()->columns(); ++i)
+ {
+ showAmount(i, m_amounts[i], m_security);
+ }
+ }
+}
+
+#include "kmymoneyaccounttreeforecast.moc"
diff --git a/kmymoney2/widgets/kmymoneyaccounttreeforecast.h b/kmymoney2/widgets/kmymoneyaccounttreeforecast.h
new file mode 100644
index 0000000..925d2e9
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyaccounttreeforecast.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+ kmymoneyaccounttreeforecast.h
+ -------------------
+ begin : Fri Aug 01 2008
+ copyright : (C) 2008 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYACCOUNTTREEFORECAST_H
+#define KMYMONEYACCOUNTTREEFORECAST_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtimer.h>
+class QDragObject;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kmymoneyaccounttree.h"
+#include "../../kmymoney/mymoneyforecast.h"
+
+class KMyMoneyAccountTreeForecastItem;
+
+class KMyMoneyAccountTreeForecast : public KMyMoneyAccountTreeBase
+{
+ Q_OBJECT
+ public:
+ KMyMoneyAccountTreeForecast(QWidget* parent = 0, const char *name = 0);
+ virtual ~KMyMoneyAccountTreeForecast() {}
+
+ void showSummary(MyMoneyForecast& forecast);
+ void showDetailed(MyMoneyForecast& forecast);
+ void showAdvanced(MyMoneyForecast& forecast);
+ void showBudget(MyMoneyForecast& forecast);
+ void showAccount(void);
+ void clearColumns(void);
+
+ public slots:
+ void slotSelectObject(const QListViewItem* i);
+
+};
+
+class KMyMoneyAccountTreeForecastItem : public KMyMoneyAccountTreeBaseItem
+{
+public:
+
+ enum EForecastViewType { eSummary = 0, eDetailed, eAdvanced, eBudget, eUndefined };
+
+ /**
+ * Constructor to be used to construct an account
+ * entry object for a forecast.
+ *
+ * @param parent pointer to the parent KAccountListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param forecast const reference to the forecast to
+ * which the account belongs
+ * @param price price to be used to calculate value (defaults to 1)
+ * This is used for accounts denominated in foreign currencies or stocks
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ */
+ KMyMoneyAccountTreeForecastItem(KMyMoneyAccountTreeForecastItem *parent, const MyMoneyAccount& account, const MyMoneyForecast& forecast, const QValueList<MyMoneyPrice>& price = QValueList<MyMoneyPrice>(), const MyMoneySecurity& security = MyMoneySecurity(), const EForecastViewType forecastViewType = eUndefined);
+
+ /**
+ * Constructor to be used to construct an account
+ * entry object for a forecast.
+ *
+ * @param parent pointer to the parent KAccountListView object this entry should be
+ * added to.
+ * @param account const reference to MyMoneyAccount for which
+ * the KListView entry is constructed
+ * @param forecast const reference to the forecast to
+ * which the account belongs
+ * @param security const reference to the security used to show the value. Usually
+ * one should pass MyMoneyFile::baseCurrency() here.
+ * @param name name of the account to be used instead of the one stored with @p account
+ * If empty, the one stored with @p account will be used. Default: empty
+ */
+ KMyMoneyAccountTreeForecastItem(KListView *parent, const MyMoneyAccount& account, const MyMoneyForecast &forecast, const MyMoneySecurity& security = MyMoneySecurity(), const QString& name = QString());
+
+ ~KMyMoneyAccountTreeForecastItem();
+
+ /**
+ * Sets the forecast object
+ */
+ void setForecast(const MyMoneyForecast& forecast);
+
+ /**
+ * updates the item with summary information. Used in Summary tab of Forecast View
+ */
+ void updateSummary(void);
+
+ /**
+ * updates the item with detailed information. Used in Detailed tab of Forecast View
+ */
+ void updateDetailed(void);
+
+ /**
+ * updates the item with budget forecast information. Used in Budget tab of Forecast View
+ */
+ void updateBudget(void);
+
+ /**
+ * sets when to begin a forecast cycle. This is used when showing forecast information per cycle, eg.
+ * on the summary tab of forecast view.
+ */
+ void setDaysToBeginDay(int _days) {m_daysToBeginDay = _days;}
+
+ /**
+ * sets the type of forecast that the time will show, eg. summary, detailed, budget
+ */
+ void setForecastViewType(EForecastViewType forecastType) { m_forecastType = forecastType; }
+
+ /**
+ * returns the forecast type of the item
+ */
+ EForecastViewType forecastViewType(void) { return m_forecastType; }
+
+ /**
+ * it executes some logic specific to this class before calling the same method on the base class
+ */
+ virtual void setOpen(bool o);
+
+protected:
+ /**
+ * Returns the current balance of this account.
+ *
+ * This is a pure virtual function, to allow subclasses to calculate
+ * the balance in different ways.
+ *
+ * Parent items in the tree will only be recomputed if the balance() for
+ * a son changes.
+ * @param account Account to get the balance for
+ * @return Balance of this account
+ */
+ MyMoneyMoney balance() const;
+ void showAmount(int column, const MyMoneyMoney amount, const MyMoneySecurity security);
+ void adjustParentValue(int column, const MyMoneyMoney& value);
+ void setValue(int column, MyMoneyMoney amount, QDate forecastDate);
+ void setAmount(int column, MyMoneyMoney amount);
+
+private:
+ MyMoneyForecast m_forecast;
+ int m_daysToBeginDay;
+ QMap<int, MyMoneyMoney> m_values;
+ QMap<int, MyMoneyMoney> m_amounts;
+ EForecastViewType m_forecastType;
+};
+
+#endif
+
diff --git a/kmymoney2/widgets/kmymoneybriefschedule.cpp b/kmymoney2/widgets/kmymoneybriefschedule.cpp
new file mode 100644
index 0000000..82776af
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneybriefschedule.cpp
@@ -0,0 +1,191 @@
+/***************************************************************************
+ kmymoneybriefschedule.cpp - description
+ -------------------
+ begin : Sun Jul 6 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qtextedit.h>
+#include <qtoolbutton.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyscheduled.h>
+#include "kmymoneybriefschedule.h"
+#include "../kmymoneyutils.h"
+
+KMyMoneyBriefSchedule::KMyMoneyBriefSchedule(QWidget *parent, const char *name )
+ : kScheduleBriefWidget(parent,name, WStyle_Customize | WStyle_NoBorder)
+{
+ KIconLoader *ic = KGlobal::iconLoader();
+ m_nextButton->setPixmap(BarIcon(QString::fromLatin1("1rightarrow")));
+ m_prevButton->setPixmap(BarIcon(QString::fromLatin1("1leftarrow")));
+
+ connect(m_prevButton, SIGNAL(clicked()), this, SLOT(slotPrevClicked()));
+ connect(m_nextButton, SIGNAL(clicked()), this, SLOT(slotNextClicked()));
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(hide()));
+ connect(m_skipButton, SIGNAL(clicked()), this, SLOT(slotSkipClicked()));
+ connect(m_buttonEnter, SIGNAL(clicked()), this, SLOT(slotEnterClicked()));
+
+ KGuiItem skipGuiItem( i18n("&Skip"),
+ QIconSet(ic->loadIcon("player_fwd", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Skip this transaction"),
+ i18n("Use this button to skip this transaction"));
+ m_skipButton->setGuiItem(skipGuiItem);
+
+ KGuiItem enterGuiItem( i18n("&Enter"),
+ QIconSet(ic->loadIcon("key_enter", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Record this transaction into the register"),
+ i18n("Use this button to record this transaction"));
+ m_buttonEnter->setGuiItem(enterGuiItem);
+}
+
+KMyMoneyBriefSchedule::~KMyMoneyBriefSchedule()
+{
+}
+
+void KMyMoneyBriefSchedule::setSchedules(QValueList<MyMoneySchedule> list, const QDate& date)
+{
+ m_scheduleList = list;
+ m_date = date;
+
+ m_index = 0;
+ if (list.count() >= 1)
+ {
+ loadSchedule();
+ }
+}
+
+void KMyMoneyBriefSchedule::loadSchedule()
+{
+ try
+ {
+ if (m_index < m_scheduleList.count())
+ {
+ MyMoneySchedule sched = m_scheduleList[m_index];
+
+ m_indexLabel->setText(i18n("%1 of %2")
+ .arg(QString::number(m_index+1))
+ .arg(QString::number(m_scheduleList.count())));
+ m_name->setText(sched.name());
+ m_type->setText(KMyMoneyUtils::scheduleTypeToString(sched.type()));
+ m_account->setText(sched.account().name());
+ QString text;
+ MyMoneyMoney amount = sched.transaction().splitByAccount(sched.account().id()).value();
+ amount = amount.abs();
+
+ if (sched.willEnd())
+ {
+ int transactions = sched.paymentDates(m_date, sched.endDate()).count()-1;
+ text = i18n("Payment on %1 for %2 with %3 transactions remaining occuring %4.")
+ .arg(KGlobal::locale()->formatDate(m_date, true))
+ .arg(amount.formatMoney(sched.account().fraction()))
+ .arg(QString::number(transactions))
+ .arg(i18n(sched.occurenceToString()));
+ } else {
+ text = i18n("Payment on %1 for %2 occuring %4.")
+ .arg(KGlobal::locale()->formatDate(m_date, true))
+ .arg(amount.formatMoney(sched.account().fraction()))
+ .arg(i18n(sched.occurenceToString()));
+ }
+
+ if (m_date < QDate::currentDate())
+ {
+ if (sched.isOverdue())
+ {
+ QDate startD = (sched.lastPayment().isValid()) ?
+ sched.lastPayment() :
+ sched.startDate();
+
+ if (m_date.isValid())
+ startD = m_date;
+
+ int days = startD.daysTo(QDate::currentDate());
+ int transactions = sched.paymentDates(startD, QDate::currentDate()).count();
+
+ text += "<br><font color=red>";
+ text += i18n("%1 days overdue (%2 occurences).")
+ .arg(QString::number(days))
+ .arg(QString::number(transactions));
+ text += "</color>";
+ }
+ }
+
+ m_details->setText(text);
+
+ m_prevButton->setEnabled(true);
+ m_nextButton->setEnabled(true);
+ m_skipButton->setEnabled(sched.occurencePeriod() != MyMoneySchedule::OCCUR_ONCE);
+
+ if (m_index == 0)
+ m_prevButton->setEnabled(false);
+ if (m_index == (m_scheduleList.count()-1))
+ m_nextButton->setEnabled(false);
+ }
+ }
+ catch (MyMoneyException *e)
+ {
+ delete e;
+ }
+}
+
+void KMyMoneyBriefSchedule::slotPrevClicked()
+{
+ if (m_index >= 1)
+ {
+ --m_index;
+ loadSchedule();
+ }
+}
+
+void KMyMoneyBriefSchedule::slotNextClicked()
+{
+ if (m_index < (m_scheduleList.count()-1))
+ {
+ m_index++;
+ loadSchedule();
+ }
+}
+
+void KMyMoneyBriefSchedule::slotEnterClicked()
+{
+ hide();
+ emit enterClicked(m_scheduleList[m_index], m_date);
+}
+
+void KMyMoneyBriefSchedule::slotSkipClicked()
+{
+ hide();
+ emit skipClicked(m_scheduleList[m_index], m_date);
+}
+
+#include "kmymoneybriefschedule.moc"
diff --git a/kmymoney2/widgets/kmymoneybriefschedule.h b/kmymoney2/widgets/kmymoneybriefschedule.h
new file mode 100644
index 0000000..f910e35
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneybriefschedule.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ kmymoneybriefschedule.h - description
+ -------------------
+ begin : Sun Jul 6 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KMYMONEYBRIEFSCHEDULE_H
+#define KMYMONEYBRIEFSCHEDULE_H
+
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qwidget.h>
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../widgets/kschedulebriefwidget.h"
+#include "../mymoney/mymoneyfile.h"
+
+/**
+ *@author Michael Edwardes
+ */
+
+class KMyMoneyBriefSchedule : public kScheduleBriefWidget {
+ Q_OBJECT
+public:
+ KMyMoneyBriefSchedule(QWidget *parent=0, const char *name=0);
+ ~KMyMoneyBriefSchedule();
+ void setSchedules(QValueList<MyMoneySchedule> list, const QDate& date);
+
+signals:
+ void enterClicked(const MyMoneySchedule&, const QDate&);
+ void skipClicked(const MyMoneySchedule&, const QDate&);
+
+protected slots:
+ void slotPrevClicked();
+ void slotNextClicked();
+ void slotEnterClicked();
+ void slotSkipClicked();
+
+private:
+ QValueList<MyMoneySchedule> m_scheduleList;
+ unsigned int m_index;
+ QDate m_date;
+
+ void loadSchedule();
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneycalculator.cpp b/kmymoney2/widgets/kmymoneycalculator.cpp
new file mode 100644
index 0000000..3e59331
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycalculator.cpp
@@ -0,0 +1,448 @@
+/***************************************************************************
+ kmymoneycalculator.cpp - description
+ -------------------
+ begin : Sat Oct 19 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qsignalmapper.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneycalculator.h"
+
+kMyMoneyCalculator::kMyMoneyCalculator(QWidget* parent, const char *name)
+ : QFrame(parent, name)
+{
+ m_comma = KGlobal::locale()->monetaryDecimalSymbol()[0];
+ m_clearOperandOnDigit = false;
+
+ QGridLayout* grid = new QGridLayout(this, 5, 5, 1, 2);
+
+ display = new QLabel(this);
+ display->setBackgroundColor(QColor("#BDFFB4"));
+
+ display->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ display->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ grid->addMultiCellWidget(display, 0, 0, 0, 4);
+
+ buttons[0] = new KPushButton("0", this);
+ buttons[1] = new KPushButton("1", this);
+ buttons[2] = new KPushButton("2", this);
+ buttons[3] = new KPushButton("3", this);
+ buttons[4] = new KPushButton("4", this);
+ buttons[5] = new KPushButton("5", this);
+ buttons[6] = new KPushButton("6", this);
+ buttons[7] = new KPushButton("7", this);
+ buttons[8] = new KPushButton("8", this);
+ buttons[9] = new KPushButton("9", this);
+ buttons[PLUS] = new KPushButton("+", this);
+ buttons[MINUS] = new KPushButton("-", this);
+ buttons[STAR] = new KPushButton("X", this);
+ buttons[COMMA] = new KPushButton(m_comma, this);
+ buttons[EQUAL] = new KPushButton("=", this);
+ buttons[SLASH] = new KPushButton("/", this);
+ buttons[CLEAR] = new KPushButton("C", this);
+ buttons[CLEARALL] = new KPushButton("AC", this);
+ buttons[PLUSMINUS] = new KPushButton("+-", this);
+ buttons[PERCENT] = new KPushButton("%", this);
+
+ grid->addWidget(buttons[7], 1, 0);
+ grid->addWidget(buttons[8], 1, 1);
+ grid->addWidget(buttons[9], 1, 2);
+ grid->addWidget(buttons[4], 2, 0);
+ grid->addWidget(buttons[5], 2, 1);
+ grid->addWidget(buttons[6], 2, 2);
+ grid->addWidget(buttons[1], 3, 0);
+ grid->addWidget(buttons[2], 3, 1);
+ grid->addWidget(buttons[3], 3, 2);
+ grid->addWidget(buttons[0], 4, 1);
+
+ grid->addWidget(buttons[COMMA], 4, 0);
+ grid->addWidget(buttons[PLUS], 3, 3);
+ grid->addWidget(buttons[MINUS], 4, 3);
+ grid->addWidget(buttons[STAR], 3, 4);
+ grid->addWidget(buttons[SLASH], 4, 4);
+ grid->addWidget(buttons[EQUAL], 4, 2);
+ grid->addWidget(buttons[PLUSMINUS], 2, 3);
+ grid->addWidget(buttons[PERCENT], 2, 4);
+ grid->addWidget(buttons[CLEAR], 1, 3);
+ grid->addWidget(buttons[CLEARALL], 1, 4);
+
+ buttons[EQUAL]->setFocus();
+
+ op1 = 0.0;
+ stackedOp = op = 0;
+ operand = QString();
+ changeDisplay("0");
+
+ // connect the digit signals through a signal mapper
+ QSignalMapper* mapper = new QSignalMapper(this);
+ for(int i = 0; i < 10; ++i) {
+ mapper->setMapping(buttons[i], i);
+ connect(buttons[i], SIGNAL(clicked()), mapper, SLOT(map()));
+ }
+ connect(mapper, SIGNAL(mapped(int)), this, SLOT(digitClicked(int)));
+
+ // connect the calculation operations through another mapper
+ mapper = new QSignalMapper(this);
+ for(int i = PLUS; i <= EQUAL; ++i) {
+ mapper->setMapping(buttons[i], i);
+ connect(buttons[i], SIGNAL(clicked()), mapper, SLOT(map()));
+ }
+ connect(mapper, SIGNAL(mapped(int)), this, SLOT(calculationClicked(int)));
+
+ // connect all remaining signals
+ connect(buttons[COMMA], SIGNAL(clicked()), SLOT(commaClicked()));
+ connect(buttons[PLUSMINUS], SIGNAL(clicked()), SLOT(plusminusClicked()));
+ connect(buttons[PERCENT], SIGNAL(clicked()), SLOT(percentClicked()));
+ connect(buttons[CLEAR], SIGNAL(clicked()), SLOT(clearClicked()));
+ connect(buttons[CLEARALL], SIGNAL(clicked()), SLOT(clearAllClicked()));
+
+ for(int i = 0; i < MAX_BUTTONS; ++i) {
+ buttons[i]->setMinimumSize(40, 30);
+ buttons[i]->setMaximumSize(40, 30);
+ }
+ int height = 4 * (buttons[0]->minimumHeight()+6) + 15;
+ int width = 5 * (buttons[0]->minimumWidth()+6);
+
+ setMinimumSize(width, height);
+ setMaximumSize(width, height);
+
+ show();
+}
+
+kMyMoneyCalculator::~kMyMoneyCalculator()
+{
+}
+
+void kMyMoneyCalculator::digitClicked(int button)
+{
+ if(m_clearOperandOnDigit) {
+ operand = QString();
+ m_clearOperandOnDigit = false;
+ }
+
+ operand += QChar(button + 0x30);
+ if(operand.length() > 16)
+ operand = operand.left(16);
+ changeDisplay(operand);
+}
+
+void kMyMoneyCalculator::commaClicked(void)
+{
+ if(operand.length() == 0)
+ operand = "0";
+ if(operand.contains('.', FALSE) == 0)
+ operand.append('.');
+
+ if(operand.length() > 16)
+ operand = operand.left(16);
+ changeDisplay(operand);
+}
+
+void kMyMoneyCalculator::plusminusClicked(void)
+{
+ if(operand.length() == 0 && m_result.length() > 0)
+ operand = m_result;
+
+ if(operand.length() > 0) {
+ if(operand.find('-') != -1)
+ operand.replace('-', QString());
+ else
+ operand.prepend('-');
+ changeDisplay(operand);
+ }
+}
+
+void kMyMoneyCalculator::calculationClicked(int button)
+{
+ if(operand.length() == 0 && op != 0 && button == EQUAL) {
+ op = 0;
+ m_result = normalizeString(op1);
+ changeDisplay(m_result);
+
+ } else if(operand.length() > 0 && op != 0) {
+ // perform operation
+ double op2 = operand.toDouble();
+ bool error = false;
+
+ // if the pending operation is addition and we now do multiplication
+ // we just stack op1 and remember the operation in
+ if((op == PLUS || op == MINUS) && (button == STAR || button == SLASH)) {
+ op0 = op1;
+ stackedOp = op;
+ op = 0;
+ }
+
+ switch(op) {
+ case PLUS:
+ op2 = op1 + op2;
+ break;
+ case MINUS:
+ op2 = op1 - op2;
+ break;
+ case STAR:
+ op2 = op1 * op2;
+ break;
+ case SLASH:
+ if(op2 == 0.0)
+ error = true;
+ else
+ op2 = op1 / op2;
+ break;
+ }
+
+ // if we have a pending addition operation, and the next operation is
+ // not multiplication, we calculate the stacked operation
+ if(stackedOp && button != STAR && button != SLASH) {
+ switch(stackedOp) {
+ case PLUS:
+ op2 = op0 + op2;
+ break;
+ case MINUS:
+ op2 = op0 - op2;
+ break;
+ }
+ stackedOp = 0;
+ }
+
+ if(error) {
+ op = 0;
+ changeDisplay("Error");
+ operand = QString();
+ } else {
+ op1 = op2;
+ m_result = normalizeString(op1);
+ changeDisplay(m_result);
+ }
+ } else if(operand.length() > 0 && op == 0) {
+ op1 = operand.toDouble();
+ m_result = normalizeString(op1);
+ changeDisplay(m_result);
+ }
+
+ if(button != EQUAL) {
+ op = button;
+ } else {
+ op = 0;
+ emit signalResultAvailable();
+ }
+ operand = QString();
+}
+
+QString kMyMoneyCalculator::normalizeString(const double& val)
+{
+ QString str;
+ str.setNum(val, 'f');
+ int i = str.length();
+ while(i > 1 && str[i-1] == '0') {
+ --i;
+ }
+ // cut off trailing 0's
+ str.remove(i, str.length());
+ if(str.length() > 0) {
+ // possibly remove trailing period
+ if(str[str.length()-1] == '.') {
+ str.remove(str.length()-1, 1);
+ }
+ }
+ return str;
+}
+
+void kMyMoneyCalculator::clearClicked(void)
+{
+ if(operand.length() > 0) {
+ operand = operand.left(operand.length() - 1);
+ }
+ if(operand.length() == 0)
+ changeDisplay("0");
+ else
+ changeDisplay(operand);
+}
+
+void kMyMoneyCalculator::clearAllClicked(void)
+{
+ operand = QString();
+ op = 0;
+ changeDisplay("0");
+}
+
+void kMyMoneyCalculator::percentClicked(void)
+{
+ if(op != 0) {
+ double op2 = operand.toDouble();
+ switch(op) {
+ case PLUS:
+ case MINUS:
+ op2 = (op1 * op2) / 100;
+ break;
+
+ case STAR:
+ case SLASH:
+ op2 /= 100;
+ break;
+ }
+ operand = normalizeString(op2);
+ changeDisplay(operand);
+ }
+}
+
+const QString kMyMoneyCalculator::result(void) const
+{
+ QString txt = m_result;
+ txt.replace(QRegExp("\\."), m_comma);
+ if(txt[0] == '-') {
+ txt = txt.mid(1); // get rid of the minus sign
+ QString mask;
+ switch(KGlobal::locale()->negativeMonetarySignPosition()) {
+ case KLocale::ParensAround:
+ mask = "(%1)";
+ break;
+ case KLocale::AfterQuantityMoney:
+ mask = "%1-";
+ break;
+ case KLocale::AfterMoney:
+ case KLocale::BeforeMoney:
+ mask = "%1 -";
+ break;
+ case KLocale::BeforeQuantityMoney:
+ mask = "-%1";
+ break;
+ }
+ txt = QString(mask).arg(txt);
+ }
+ return txt;
+}
+
+void kMyMoneyCalculator::changeDisplay(const QString& str)
+{
+ QString txt = str;
+ txt.replace(QRegExp("\\."), m_comma);
+ display->setText("<b>" + txt + "</b>");
+}
+
+void kMyMoneyCalculator::keyPressEvent(QKeyEvent* ev)
+{
+ int button = -1;
+
+ switch(ev->key()) {
+ case Qt::Key_0:
+ case Qt::Key_1:
+ case Qt::Key_2:
+ case Qt::Key_3:
+ case Qt::Key_4:
+ case Qt::Key_5:
+ case Qt::Key_6:
+ case Qt::Key_7:
+ case Qt::Key_8:
+ case Qt::Key_9:
+ if(m_clearOperandOnDigit) {
+ operand = QString();
+ m_clearOperandOnDigit = false;
+ }
+ button = ev->key() - Qt::Key_0;
+ break;
+ case Qt::Key_Plus:
+ button = PLUS;
+ break;
+ case Qt::Key_Minus:
+ button = MINUS;
+ break;
+ case Qt::Key_Comma:
+ case Qt::Key_Period:
+ if(m_clearOperandOnDigit) {
+ operand = QString();
+ m_clearOperandOnDigit = false;
+ }
+ button = COMMA;
+ break;
+ case Qt::Key_Slash:
+ button = SLASH;
+ break;
+ case Qt::Key_Backspace:
+ button = CLEAR;
+ break;
+ case Qt::Key_Asterisk:
+ button = STAR;
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Equal:
+ button = EQUAL;
+ break;
+ case Qt::Key_Escape:
+ button = CLEARALL;
+ break;
+ case Qt::Key_Percent:
+ button = PERCENT;
+ break;
+ default:
+ ev->ignore();
+ break;
+ }
+ if(button != -1)
+ buttons[button]->animateClick();
+
+ m_clearOperandOnDigit = false;
+}
+
+void kMyMoneyCalculator::setInitialValues(const QString& value, QKeyEvent* ev)
+{
+ bool negative = false;
+ // setup operand
+ operand = value;
+ operand.replace(QRegExp(QString("\\")+KGlobal::locale()->thousandsSeparator()), QString());
+ operand.replace(QRegExp(QString("\\")+m_comma), ".");
+ if(operand.contains('(')) {
+ negative = true;
+ operand.replace("(", QString());
+ operand.replace(")", QString());
+ }
+ if(operand.contains('-')) {
+ negative = true;
+ operand.replace("-", QString());
+ }
+ if(operand.isEmpty())
+ operand = "0";
+ else if(negative)
+ operand = QString("-%1").arg(operand);
+
+ changeDisplay(operand);
+
+ // and operation
+ op = 0;
+ if(ev)
+ keyPressEvent(ev);
+ else
+ m_clearOperandOnDigit = true;
+}
+
+#include "kmymoneycalculator.moc"
diff --git a/kmymoney2/widgets/kmymoneycalculator.h b/kmymoney2/widgets/kmymoneycalculator.h
new file mode 100644
index 0000000..594d6c7
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycalculator.h
@@ -0,0 +1,249 @@
+/***************************************************************************
+ kmymoneycalculator.h - description
+ -------------------
+ begin : Sat Oct 19 2002
+ copyright : (C) 2000-2002 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYCALCULATOR_H
+#define KMYMONEYCALCULATOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qframe.h>
+#include <qlayout.h>
+#include <qgrid.h>
+#include <qlcdnumber.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ *@author Thomas Baumgart
+ */
+
+/**
+ * This class implements a simple electronic calculator with the
+ * ability of addition, subtraction, multiplication and division
+ * and percentage calculation. Memory locations are not available.
+ *
+ * The first operand and operation can be loaded from an external
+ * source to switch from an edit-widget to the calculator widget
+ * without having the user to re-type the data. See setInitialValues()
+ * for details.
+ */
+class kMyMoneyCalculator : public QFrame {
+ Q_OBJECT
+public:
+ kMyMoneyCalculator(QWidget* parent = 0, const char *name = 0);
+ ~kMyMoneyCalculator();
+
+ /**
+ * This methods is used to extract the result of the last
+ * calculation. The fractional part is separated from the
+ * integral part by the character setup using setComma().
+ *
+ * @return QString representing the result of the
+ * last operation
+ */
+ const QString result(void) const;
+
+ /**
+ * This method is used to set the character to be used
+ * as the separator between the integer and fractional part
+ * of an operand. Upon creation of the object, m_comma is
+ * set to the current locale setting of KDE's decimalSymbol.
+ *
+ * @param ch QChar representing the character to be used
+ */
+ void setComma(const QChar ch) { m_comma = ch; };
+
+ /**
+ * This method is used to preset the first operand and start
+ * execution of an operation. This method is currently used
+ * by kMyMoneyEdit. If @p ev is 0, then no operation will be
+ * started.
+ *
+ * @param value reference to QString representing the operands value
+ * @param ev pointer to QKeyEvent representing the operation's key
+ */
+ void setInitialValues(const QString& value, QKeyEvent* ev);
+
+signals:
+ /**
+ * This signal is emitted, when a new result is available
+ */
+ void signalResultAvailable();
+
+protected:
+ void keyPressEvent(QKeyEvent* ev);
+
+ /**
+ * This method is used to transform a double into a QString
+ * and removing any trailing 0's and decimal seperators
+ *
+ * @param val reference to double value to be converted
+ * @return QString object containing the converted value
+ */
+ QString normalizeString(const double& val);
+
+protected slots:
+ /**
+ * This method appends the digit represented by the parameter
+ * to the current operand
+ *
+ * @param button integer value of the digit to be added in the
+ * range [0..9]
+ */
+ void digitClicked(int button);
+
+ /**
+ * This methods starts the operation contained in the parameter
+ *
+ * @param button The Qt::Keycode for the button pressed or clicked
+ */
+ void calculationClicked(int button);
+
+ /**
+ * This method appends a period (comma) to initialize the fractional
+ * part of an operand. The period is only appended once.
+ */
+ void commaClicked(void);
+
+ /**
+ * This method reverses the sign of the current operand
+ */
+ void plusminusClicked(void);
+
+ /**
+ * This method clears the current operand
+ */
+ void clearClicked(void);
+
+ /**
+ * This method clears all registers
+ */
+ void clearAllClicked(void);
+
+ /**
+ * This method executes the percent operation
+ */
+ void percentClicked(void);
+
+ /**
+ * This method updates the display of the calculator with
+ * the text passed as argument
+ *
+ * @param str reference to QString containing the new display contents
+ */
+ void changeDisplay(const QString& str);
+
+private:
+ /**
+ * This member variable stores the current (second) operand
+ */
+ QString operand;
+
+ /**
+ * This member variable stores the last result
+ */
+ QString m_result;
+
+ /**
+ * This member variable stores the representation of the
+ * character to be used to separate the integer and fractional
+ * part of numbers. The internal representation is always a period.
+ */
+ QChar m_comma;
+
+ /**
+ * The numeric representation of a stacked first operand
+ */
+ double op0;
+
+ /**
+ * The numeric representation of the first operand
+ */
+ double op1;
+
+ /**
+ * This member stores the operation to be performed between
+ * the first and the second operand.
+ */
+ int op;
+
+ /**
+ * This member stores a pending addition operation
+ */
+ int stackedOp;
+
+ /**
+ * This member stores a pointer to the display area
+ */
+ QLabel *display;
+
+ /**
+ * This member array stores the pointers to the various
+ * buttons of the calculator. It is setup during the
+ * constructor of this object
+ */
+ KPushButton *buttons[20];
+
+ /**
+ * This enumeration type stores the values used for the
+ * various keys internally
+ */
+ enum {
+ /* 0-9 are used by digits */
+ COMMA = 10,
+ /*
+ * make sure, that PLUS through EQUAL remain in
+ * the order they are. Otherwise, check the calculation
+ * signal mapper
+ */
+ PLUS,
+ MINUS,
+ SLASH,
+ STAR,
+ EQUAL,
+ PLUSMINUS,
+ PERCENT,
+ CLEAR,
+ CLEARALL,
+ /* insert new buttons before this line */
+ MAX_BUTTONS
+ };
+
+ /**
+ * This flag signals, if the operand should be replaced upon
+ * a digit key pressure. Defaults to false and will be set, if
+ * setInitialValues() is called without an operation.
+ */
+ bool m_clearOperandOnDigit;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneycalendar.cpp b/kmymoney2/widgets/kmymoneycalendar.cpp
new file mode 100644
index 0000000..8f5291f
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycalendar.cpp
@@ -0,0 +1,661 @@
+/***************************************************************************
+ kmymoneycalendar.cpp - description
+ -------------------
+ begin : Wed Jul 2 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * Contains code from KDatePicker in kdelibs-3.1.2.
+ * Original license message:
+ *
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
+ (C) 1998-2001 Mirko Boehm (mirko@kde.org)
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ ****************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qpainter.h>
+#include <qdrawutil.h>
+#include <qframe.h>
+#include <qpainter.h>
+#include <qdialog.h>
+#include <qstyle.h>
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+#include <qfont.h>
+#include <qvalidator.h>
+#include <qpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include "kdecompat.h"
+#include <kglobal.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <kdebug.h>
+#include <knotifyclient.h>
+#include <kdatetbl.h> // for maximum re-use
+#include <kpopupmenu.h>
+
+#if KDE_IS_VERSION(3,2,0)
+#include <kcalendarsystem.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kmymoneycalendar.h"
+#include "kmymoneydatetbl.h"
+
+class kMyMoneyCalendar::kMyMoneyCalendarPrivate
+{
+public:
+ kMyMoneyCalendarPrivate()
+ : closeButton(0L), selectWeek(0L), userButton1(0), userButton2(0) {}
+
+ QToolButton *closeButton;
+ QToolButton *selectWeek;
+ QPushButton *userButton1;
+ QPushButton *userButton2;
+};
+
+kMyMoneyCalendar::kMyMoneyCalendar(QWidget *parent, const char *name ) :
+ QFrame(parent,name),
+ table(0),
+ d(new kMyMoneyCalendarPrivate)
+{
+}
+
+kMyMoneyCalendar::~kMyMoneyCalendar()
+{
+ delete d;
+}
+
+void kMyMoneyCalendar::init( const QDate &dt )
+{
+ styleControl = new QPushButton(i18n("Select Style"), this);
+ yearForward = new QToolButton(this);
+ yearBackward = new QToolButton(this);
+ monthForward = new QToolButton(this);
+ monthBackward = new QToolButton(this);
+ selectMonth = new QToolButton(this);
+ selectYear = new QToolButton(this);
+ line = new KLineEdit(this);
+ val = new KDateValidator(this);
+ fontsize = 10;
+
+ d->selectWeek = new QToolButton( this );
+
+// KIconLoader *kiconloader = KGlobal::iconLoader();
+ KPopupMenu* kpopupmenuNew = new KPopupMenu(this);
+ kpopupmenuNew->insertItem(i18n("Week"), this, SLOT(slotSetStyleWeekly()));
+ kpopupmenuNew->insertItem(i18n("Month"), this, SLOT(slotSetStyleMonthly()));
+/* kpopupmenuNew->insertItem(i18n("3 Months"), this, SLOT(slotSetStyleQuarterly())); */
+ styleControl->setPopup(kpopupmenuNew);
+
+ QToolTip::add(styleControl, i18n("Choose Style"));
+ QToolTip::add(yearForward, i18n("Next year"));
+ QToolTip::add(yearBackward, i18n("Previous year"));
+ QToolTip::add(monthForward, i18n("Next month"));
+ QToolTip::add(monthBackward, i18n("Previous month"));
+ QToolTip::add(d->selectWeek, i18n("Select a week"));
+ QToolTip::add(selectMonth, i18n("Select a month"));
+ QToolTip::add(selectYear, i18n("Select a year"));
+
+ // -----
+ setFontSize(10);
+ line->setValidator(val);
+ line->installEventFilter( this );
+ yearForward->setPixmap(BarIcon(QString::fromLatin1("2rightarrow")));
+ yearBackward->setPixmap(BarIcon(QString::fromLatin1("2leftarrow")));
+ monthForward->setPixmap(BarIcon(QString::fromLatin1("1rightarrow")));
+ monthBackward->setPixmap(BarIcon(QString::fromLatin1("1leftarrow")));
+ setDate(dt); // set button texts
+ connect(table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate)));
+ connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot()));
+ connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked()));
+ connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked()));
+ connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked()));
+ connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked()));
+ connect(d->selectWeek, SIGNAL(clicked()), SLOT(selectWeekClicked()));
+ connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked()));
+ connect(selectYear, SIGNAL(clicked()), SLOT(selectYearClicked()));
+ connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed()));
+ if (table)
+ table->setFocus();
+}
+
+bool
+kMyMoneyCalendar::eventFilter(QObject *o, QEvent *e )
+{
+ if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent *k = (QKeyEvent *)e;
+
+ if ( (k->key() == Qt::Key_Prior) ||
+ (k->key() == Qt::Key_Next) ||
+ (k->key() == Qt::Key_Up) ||
+ (k->key() == Qt::Key_Down) )
+ {
+ QApplication::sendEvent( table, e );
+ table->setFocus();
+ return TRUE; // eat event
+ }
+ }
+ return QFrame::eventFilter( o, e );
+}
+
+void
+kMyMoneyCalendar::resizeEvent(QResizeEvent*)
+{
+ QWidget *buttons[] = {
+ styleControl,
+ d->userButton1,
+ d->userButton2,
+ yearBackward,
+ monthBackward,
+ selectMonth,
+ selectYear,
+ monthForward,
+ yearForward,
+ d->closeButton
+ };
+ const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
+ QSize sizes[NoOfButtons];
+ int buttonHeight=0;
+ int count;
+ int w;
+ int x=0;
+ // ----- calculate button row height:
+ for(count=0; count<NoOfButtons; ++count) {
+ if ( buttons[count] ) { // closeButton may be 0L
+ sizes[count]=buttons[count]->sizeHint();
+ buttonHeight=QMAX(buttonHeight, sizes[count].height());
+ }
+ else
+ sizes[count] = QSize(0,0); // closeButton
+ }
+
+ // ----- calculate size of the month button:
+ for(count=0; count<NoOfButtons; ++count) {
+ if(buttons[count]==selectMonth) {
+ QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect);
+ sizes[count].setWidth(QMAX(metricBound.width(), maxMonthRect.width()+2*QApplication::style().pixelMetric(QStyle::PM_ButtonMargin)));
+ }
+ }
+ // ----- place the buttons:
+ // Put the style button and user buttons to the left and the rest to the right
+ x = 0;
+ int noUserButtons=2;
+ buttons[0]->setGeometry(x, 0, sizes[0].width(), buttonHeight);
+ x += sizes[0].width();
+ for (count=1; count<=noUserButtons; ++count)
+ {
+ if (buttons[count])
+ {
+ buttons[count]->setGeometry(x, 0, sizes[count].width(), buttonHeight);
+ x += sizes[count].width();
+ }
+ }
+
+ x = width();
+ for(count=(1+noUserButtons); count<NoOfButtons; ++count)
+ {
+ w=sizes[count].width();
+ x -= w;
+ }
+
+ for(count=(1+noUserButtons); count<NoOfButtons; ++count)
+ {
+ w=sizes[count].width();
+ if ( buttons[count] )
+ buttons[count]->setGeometry(x, 0, w, buttonHeight);
+ x+=w;
+ }
+
+ // ----- place the line edit for direct input:
+ sizes[0]=line->sizeHint();
+ int week_width=d->selectWeek->fontMetrics().width(i18n("Week XX"))+((d->closeButton != 0L) ? 50 : 20);
+ line->setGeometry(0, height()-sizes[0].height(), width()-week_width, sizes[0].height());
+ d->selectWeek->setGeometry(width()-week_width, height()-sizes[0].height(), week_width, sizes[0].height());
+ // ----- adjust the table:
+ table->setGeometry(0, buttonHeight, width(),
+ height()-buttonHeight-sizes[0].height());
+
+ table->setFocus();
+}
+
+void
+kMyMoneyCalendar::dateChangedSlot(QDate date)
+{
+ kdDebug() << "kMyMoneyCalendar::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl;
+ line->setText(KGlobal::locale()->formatDate(date, true));
+ d->selectWeek->setText(i18n("Week %1").arg(weekOfYear(date)));
+ selectMonth->setText(MONTH_NAME(date.month(), date.year(), false));
+ selectYear->setText(date.toString("yyyy"));
+ emit(dateChanged(date));
+}
+
+void
+kMyMoneyCalendar::tableClickedSlot()
+{
+ kdDebug() << "kMyMoneyCalendar::tableClickedSlot: table clicked." << endl;
+ emit(dateSelected(table->getDate()));
+ emit(tableClicked());
+}
+
+const QDate&
+kMyMoneyCalendar::getDate() const
+{
+ return table->getDate();
+}
+
+const QDate &
+kMyMoneyCalendar::date() const
+{
+ return table->getDate();
+}
+
+bool
+kMyMoneyCalendar::setDate(const QDate& date)
+{
+ if (!table)
+ return true; // hack
+
+ if(date.isValid()) {
+ QString temp;
+ // -----
+ table->setDate(date);
+ d->selectWeek->setText(i18n("Week %1").arg(weekOfYear(date)));
+ selectMonth->setText(MONTH_NAME(date.month(), date.year(), false));
+ temp.setNum(date.year());
+ selectYear->setText(temp);
+ line->setText(KGlobal::locale()->formatDate(date, true));
+ return true;
+ } else {
+ kdDebug() << "kMyMoneyCalendar::setDate: refusing to set invalid date." << endl;
+ return false;
+ }
+}
+
+void
+kMyMoneyCalendar::monthForwardClicked()
+{
+ setDate( table->getDate().addMonths(1) );
+}
+
+void
+kMyMoneyCalendar::monthBackwardClicked()
+{
+ setDate( table->getDate().addMonths(-1) );
+}
+
+void
+kMyMoneyCalendar::yearForwardClicked()
+{
+ setDate( table->getDate().addYears(1) );
+}
+
+void
+kMyMoneyCalendar::yearBackwardClicked()
+{
+ setDate( table->getDate().addYears(-1) );
+}
+
+void
+kMyMoneyCalendar::selectWeekClicked()
+{
+#if KDE_VERSION >= 310 && KDE_VERSION <= 314
+ int week;
+ KPopupFrame* popup = new KPopupFrame(this);
+ KDateInternalWeekSelector* picker = new KDateInternalWeekSelector(/*fontsize, */popup);
+ // -----
+ picker->resize(picker->sizeHint());
+ popup->setMainWidget(picker);
+ connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
+ picker->setFocus();
+ if(popup->exec(d->selectWeek->mapToGlobal(QPoint(0, d->selectWeek->height()))))
+ {
+ QDate date;
+ int year;
+ // -----
+ week=picker->getWeek();
+ date=table->getDate();
+ year=date.year();
+ // ----- find the first selectable day in this week (hacky solution :)
+ date.setYMD(year, 1, 1);
+ while (weekOfYear(date)>50)
+ date=date.addDays(1);
+ while (weekOfYear(date)<week && (week!=53 || (week==53 &&
+ (weekOfYear(date)!=52 || weekOfYear(date.addDays(1))!=1))))
+ date=date.addDays(1);
+ if (week==53 && weekOfYear(date)==52)
+ while (weekOfYear(date.addDays(-1))==52)
+ date=date.addDays(-1);
+ // ----- set this date
+ setDate(date);
+ } else {
+ KNotifyClient::beep();
+ }
+ delete popup;
+#endif
+}
+
+void
+kMyMoneyCalendar::selectMonthClicked()
+{
+#if KDE_VERSION >= 310 && KDE_VERSION <= 314
+ int month;
+ KPopupFrame* popup = new KPopupFrame(this);
+ KDateInternalMonthPicker* picker = new KDateInternalMonthPicker(/*fontsize, */popup);
+ // -----
+ picker->resize(picker->sizeHint());
+ popup->setMainWidget(picker);
+ picker->setFocus();
+ connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
+ if(popup->exec(selectMonth->mapToGlobal(QPoint(0, selectMonth->height()))))
+ {
+ QDate date;
+ int day;
+ // -----
+ month=picker->getResult();
+ date=table->getDate();
+ day=date.day();
+ // ----- construct a valid date in this month:
+ date.setYMD(date.year(), month, 1);
+ date.setYMD(date.year(), month, QMIN(day, date.daysInMonth()));
+ // ----- set this month
+ setDate(date);
+ } else {
+ KNotifyClient::beep();
+ }
+ delete popup;
+#endif
+}
+
+void
+kMyMoneyCalendar::selectYearClicked()
+{
+#if KDE_VERSION >= 310 && KDE_VERSION <= 314
+ int year;
+ KPopupFrame* popup = new KPopupFrame(this);
+ KDateInternalYearSelector* picker = new KDateInternalYearSelector(fontsize, popup);
+ // -----
+ picker->resize(picker->sizeHint());
+ popup->setMainWidget(picker);
+ connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int)));
+ picker->setFocus();
+ if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height()))))
+ {
+ QDate date;
+ int day;
+ // -----
+ year=picker->getYear();
+ date=table->getDate();
+ day=date.day();
+ // ----- construct a valid date in this month:
+ date.setYMD(year, date.month(), 1);
+ date.setYMD(year, date.month(), QMIN(day, date.daysInMonth()));
+ // ----- set this month
+ setDate(date);
+ } else {
+ KNotifyClient::beep();
+ }
+ delete popup;
+#endif
+}
+
+void
+kMyMoneyCalendar::setEnabled(bool enable)
+{
+ QWidget *widgets[]= {
+ styleControl, yearForward, yearBackward, monthForward, monthBackward,
+ selectMonth, selectYear,
+ line, table, d->selectWeek, d->userButton1, d->userButton2 };
+ const int Size=sizeof(widgets)/sizeof(widgets[0]);
+ int count;
+ // -----
+ for(count=0; count<Size; ++count)
+ {
+ if (widgets[count])
+ widgets[count]->setEnabled(enable);
+ }
+}
+
+void
+kMyMoneyCalendar::lineEnterPressed()
+{
+ QDate temp;
+ // -----
+ if(val->date(line->text(), temp)==QValidator::Acceptable)
+ {
+ kdDebug() << "kMyMoneyCalendar::lineEnterPressed: valid date entered." << endl;
+ emit(dateEntered(temp));
+ setDate(temp);
+ } else {
+ KNotifyClient::beep();
+ kdDebug() << "kMyMoneyCalendar::lineEnterPressed: invalid date entered." << endl;
+ }
+}
+
+QSize
+kMyMoneyCalendar::sizeHint() const
+{
+ QSize tableSize=table->sizeHint();
+ QWidget *buttons[]={
+ styleControl,
+ yearBackward,
+ monthBackward,
+ selectMonth,
+ selectYear,
+ monthForward,
+ yearForward,
+ d->closeButton,
+ d->userButton1,
+ d->userButton2
+ };
+ const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
+ QSize sizes[NoOfButtons];
+ int cx=0, cy=0, count;
+ // ----- store the size hints:
+ for(count=0; count<NoOfButtons; ++count)
+ {
+ if ( buttons[count] )
+ sizes[count]=buttons[count]->sizeHint();
+ else
+ sizes[count] = QSize(0,0);
+
+ if(buttons[count]==selectMonth)
+ {
+ QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect);
+ cx+=QMAX(metricBound.width(), maxMonthRect.width()+2*QApplication::style().pixelMetric(QStyle::PM_ButtonMargin));
+ } else {
+ cx+=sizes[count].width();
+ }
+ cy=QMAX(sizes[count].height(), cy);
+ }
+ // ----- calculate width hint:
+ cx=QMAX(cx, tableSize.width()); // line edit ignored
+ // ----- calculate height hint:
+ cy+=tableSize.height()+line->sizeHint().height();
+ return QSize(cx, cy);
+}
+
+void
+kMyMoneyCalendar::setFontSize(int s)
+{
+ if (table)
+ {
+ QWidget *buttons[]= {
+ // styleControl
+ // yearBackward,
+ // monthBackward,
+ selectMonth,
+ selectYear,
+ // monthForward,
+ // yearForward
+ };
+ const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
+ int count;
+ QFont font;
+ QRect r;
+ // -----
+ fontsize=s;
+ for(count=0; count<NoOfButtons; ++count)
+ {
+ font=buttons[count]->font();
+ font.setPointSize(s);
+ buttons[count]->setFont(font);
+ }
+ QFontMetrics metrics(selectMonth->fontMetrics());
+ for(int i=1; i <= 12; ++i)
+ { // maxMonthRect is used by sizeHint()
+ r=metrics.boundingRect(MONTH_NAME(i, 2000, false));
+ maxMonthRect.setWidth(QMAX(r.width(), maxMonthRect.width()));
+ maxMonthRect.setHeight(QMAX(r.height(), maxMonthRect.height()));
+ }
+ table->setFontSize(s);
+ }
+}
+
+void
+kMyMoneyCalendar::setCloseButton( bool enable )
+{
+ if ( enable == (d->closeButton != 0L) )
+ return;
+
+ if ( enable ) {
+ d->closeButton = new QToolButton( this );
+ QToolTip::add(d->closeButton, i18n("Close"));
+ d->closeButton->setPixmap( SmallIcon("remove") );
+ connect( d->closeButton, SIGNAL( clicked() ),
+ topLevelWidget(), SLOT( close() ) );
+ }
+ else {
+ delete d->closeButton;
+ d->closeButton = 0L;
+ }
+
+ updateGeometry();
+}
+
+bool kMyMoneyCalendar::hasCloseButton() const
+{
+ return (d->closeButton != 0L);
+}
+
+int kMyMoneyCalendar::weekOfYear(QDate date)
+{
+ // Calculate ISO 8601 week number (taken from glibc/Gnumeric)
+ int year, week, wday, jan1wday, nextjan1wday;
+ QDate jan1date, nextjan1date;
+
+ year=date.year();
+ wday=date.dayOfWeek();
+
+ jan1date=QDate(year,1,1);
+ jan1wday=jan1date.dayOfWeek();
+
+ week = (date.dayOfYear()-1 + jan1wday-1)/7 + ((jan1wday-1) == 0 ? 1 : 0);
+
+ /* Does date belong to last week of previous year? */
+ if ((week == 0) && (jan1wday > 4 /*THURSDAY*/)) {
+ QDate tmpdate=QDate(year-1,12,31);
+ return weekOfYear(tmpdate);
+ }
+
+ if ((jan1wday <= 4 /*THURSDAY*/) && (jan1wday > 1 /*MONDAY*/))
+ week++;
+
+ if (week == 53) {
+ nextjan1date=QDate(year+1, 1, 1);
+ nextjan1wday = nextjan1date.dayOfWeek();
+ if (nextjan1wday <= 4 /*THURSDAY*/)
+ week = 1;
+ }
+
+ return week;
+}
+
+void kMyMoneyCalendar::virtual_hook( int /*id*/, void* /*data*/ )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void kMyMoneyCalendar::slotSetStyleWeekly()
+{
+ setType(kMyMoneyDateTbl::WEEKLY);
+}
+
+void kMyMoneyCalendar::slotSetStyleMonthly()
+{
+ setType(kMyMoneyDateTbl::MONTHLY);
+}
+
+void kMyMoneyCalendar::slotSetStyleQuarterly()
+{
+ setType(kMyMoneyDateTbl::QUARTERLY);
+}
+
+void kMyMoneyCalendar::setUserButton1(bool enable, QPushButton* pb)
+{
+ if ( enable == (d->userButton1 != 0L) )
+ return;
+
+ if ( enable ) {
+ d->userButton1 = pb;
+ }
+ else {
+ delete d->userButton1;
+ d->userButton1 = 0L;
+ }
+
+ updateGeometry();
+}
+
+void kMyMoneyCalendar::setUserButton2(bool enable, QPushButton* pb)
+{
+ if ( enable == (d->userButton2 != 0L) )
+ return;
+
+ if ( enable ) {
+ d->userButton2 = pb;
+ }
+ else {
+ delete d->userButton2;
+ d->userButton2 = 0L;
+ }
+
+ updateGeometry();
+}
+
+#include "kmymoneycalendar.moc"
diff --git a/kmymoney2/widgets/kmymoneycalendar.h b/kmymoney2/widgets/kmymoneycalendar.h
new file mode 100644
index 0000000..b0e2328
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycalendar.h
@@ -0,0 +1,262 @@
+/***************************************************************************
+ kmymoneycalendar.h - description
+ -------------------
+ begin : Wed Jul 2 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+/***************************************************************************
+ * Contains code from KDatePicker in kdelibs-3.1.2.
+ * Original license message:
+ *
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
+ (C) 1998-2001 Mirko Boehm (mirko@kde.org)
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ ****************************************************************************/
+
+
+#ifndef KMYMONEYCALENDAR_H
+#define KMYMONEYCALENDAR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qframe.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kmymoneydatetbl.h"
+
+class QLineEdit;
+class QToolButton;
+class KDateValidator;
+class kMyMoneyDateTbl;
+class QPushButton;
+
+/**
+ * A representation of a calendar.
+ *
+ * @author Michael Edwardes 2003
+ *
+**/
+class kMyMoneyCalendar : public QFrame {
+ Q_OBJECT
+public:
+
+public:
+ /**
+ * Standard constructor.
+ **/
+ kMyMoneyCalendar(QWidget *parent=0, const char *name=0);
+
+ /**
+ * Standard destructor.
+ **/
+ ~kMyMoneyCalendar();
+
+ /**
+ * Sets the calendar type.
+ **/
+ void setType(kMyMoneyDateTbl::calendarType type) { table->setType(type); }
+
+ /**
+ * Get the calendar type.
+ **/
+ kMyMoneyDateTbl::calendarType type(void) const { return table->type(); }
+
+ /** The size hint for date pickers. The size hint recommends the
+ * minimum size of the widget so that all elements may be placed
+ * without clipping. This sometimes looks ugly, so when using the
+ * size hint, try adding 28 to each of the reported numbers of
+ * pixels.
+ **/
+ QSize sizeHint() const;
+
+ /**
+ * Sets the date.
+ *
+ * @returns @p false and does not change anything
+ * if the date given is invalid.
+ **/
+ bool setDate(const QDate&);
+
+ /**
+ * Returns the selected date.
+ * @deprecated
+ **/
+ const QDate& getDate() const;
+
+ /**
+ * @returns the selected date.
+ */
+ const QDate &date() const;
+
+ /**
+ * Enables or disables the widget.
+ **/
+ void setEnabled(bool);
+
+ /**
+ * Sets the font size of the widgets elements.
+ **/
+ void setFontSize(int);
+ /**
+ * Returns the font size of the widget elements.
+ */
+ int fontSize() const
+ { return fontsize; }
+
+ /**
+ * By calling this method with @p enable = true, KDatePicker will show
+ * a little close-button in the upper button-row. Clicking the
+ * close-button will cause the KDatePicker's topLevelWidget()'s close()
+ * method being called. This is mostly useful for toplevel datepickers
+ * without a window manager decoration.
+ * @see #hasCloseButton
+ * @since 3.1
+ */
+ void setCloseButton( bool enable );
+
+ /**
+ * @returns true if a KDatePicker shows a close-button.
+ * @see #setCloseButton
+ * @since 3.1
+ */
+ bool hasCloseButton() const;
+
+ /**
+ * Dynamically set the Date Table
+ **/
+ virtual void setDateTable(kMyMoneyDateTbl *tbl) = 0;
+
+ void setUserButton1(bool enable, QPushButton* pb);
+ void setUserButton2(bool enable, QPushButton* pb);
+
+protected:
+ /// to catch move keyEvents when QLineEdit has keyFocus
+ virtual bool eventFilter(QObject *o, QEvent *e );
+ /// the resize event
+ virtual void resizeEvent(QResizeEvent*);
+ /// the style control button
+ QPushButton *styleControl;
+ /// the year forward button
+ QToolButton *yearForward;
+ /// the year backward button
+ QToolButton *yearBackward;
+ /// the month forward button
+ QToolButton *monthForward;
+ /// the month backward button
+ QToolButton *monthBackward;
+ /// the button for selecting the month directly
+ QToolButton *selectMonth;
+ /// the button for selecting the year directly
+ QToolButton *selectYear;
+ /// the line edit to enter the date directly
+ QLineEdit *line;
+ /// the validator for the line edit:
+ KDateValidator *val;
+ /// the date table
+ kMyMoneyDateTbl *table;
+ /// the size calculated during resize events
+ // QSize sizehint;
+ /// the widest month string in pixels:
+ QSize maxMonthRect;
+
+protected slots:
+ void dateChangedSlot(QDate);
+ void tableClickedSlot();
+ void monthForwardClicked();
+ void monthBackwardClicked();
+ void yearForwardClicked();
+ void yearBackwardClicked();
+ /// @since 3.1
+ void selectWeekClicked();
+ void selectMonthClicked();
+ void selectYearClicked();
+ void lineEnterPressed();
+
+ void slotSetStyleWeekly();
+ void slotSetStyleMonthly();
+ void slotSetStyleQuarterly();
+
+signals:
+ /** This signal is emitted each time the selected date is changed.
+ * Usually, this does not mean that the date has been entered,
+ * since the date also changes, for example, when another month is
+ * selected.
+ * @see dateSelected
+ */
+ void dateChanged(QDate);
+ /** This signal is emitted each time a day has been selected by
+ * clicking on the table (hitting a day in the current month). It
+ * has the same meaning as dateSelected() in older versions of
+ * KDatePicker.
+ */
+ void dateSelected(QDate);
+ /** This signal is emitted when enter is pressed and a VALID date
+ * has been entered before into the line edit. Connect to both
+ * dateEntered() and dateSelected() to receive all events where the
+ * user really enters a date.
+ */
+ void dateEntered(QDate);
+ /** This signal is emitted when the day has been selected by
+ * clicking on it in the table.
+ */
+ void tableClicked();
+
+private:
+ /// the font size for the widget
+ int fontsize;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+ void init( const QDate &dt );
+
+private:
+ class kMyMoneyCalendarPrivate;
+ kMyMoneyCalendarPrivate* const d;
+ // calculate ISO 8601 week number
+ int weekOfYear(QDate);
+
+#if KDE_IS_VERSION(3,2,0)
+ #define MONTH_NAME(a,b,c) KGlobal::locale()->calendar()->monthName(a,b,c)
+#else
+ #define MONTH_NAME(a,b,c) KGlobal::locale()->monthName(a,c)
+#endif
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneycategory.cpp b/kmymoney2/widgets/kmymoneycategory.cpp
new file mode 100644
index 0000000..e14a5a5
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycategory.cpp
@@ -0,0 +1,203 @@
+/***************************************************************************
+ kmymoneycategory.cpp - description
+ -------------------
+ begin : Mon Jul 10 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qrect.h>
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qlayout.h>
+#include <qtimer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneycategory.h"
+#include <kmymoney/mymoneyfile.h>
+#include "kmymoneyaccountcompletion.h"
+
+class KMyMoneyCategory::Private
+{
+public:
+ Private() :
+ splitButton(0),
+ frame(0),
+ recursive(false) {}
+
+ KPushButton* splitButton;
+ QFrame* frame;
+ bool recursive;
+};
+
+KMyMoneyCategory::KMyMoneyCategory(QWidget* parent, const char * name, bool splitButton) :
+ KMyMoneyCombo(true, parent, name),
+ d(new Private)
+{
+ if(splitButton) {
+ d->frame = new QFrame(0);
+ d->frame->setFocusProxy(this);
+ QHBoxLayout* layout = new QHBoxLayout(d->frame);
+ // make sure not to use our own overridden version of reparent() here
+ KMyMoneyCombo::reparent(d->frame, getWFlags() & ~WType_Mask, QPoint(0, 0), true);
+ if(parent)
+ d->frame->reparent(parent, QPoint(0, 0), true);
+
+ // create button
+ KGuiItem splitButtonItem("",
+ QIconSet(KGlobal::iconLoader()->loadIcon("split_transaction", KIcon::Small,
+ KIcon::SizeSmall)), "", "");
+ d->splitButton = new KPushButton(splitButtonItem, d->frame, "splitButton");
+
+ layout->addWidget(this, 5);
+ layout->addWidget(d->splitButton);
+ }
+
+ m_completion = new kMyMoneyAccountCompletion(this, 0);
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotItemSelected(const QString&)));
+ connect(this, SIGNAL(textChanged(const QString&)), m_completion, SLOT(slotMakeCompletion(const QString&)));
+}
+
+KMyMoneyCategory::~KMyMoneyCategory()
+{
+ // make sure to wipe out the frame, button and layout
+ if(d->frame && !d->frame->parentWidget())
+ d->frame->deleteLater();
+
+ delete d;
+}
+
+KPushButton* KMyMoneyCategory::splitButton(void) const
+{
+ return d->splitButton;
+}
+
+void KMyMoneyCategory::setPalette(const QPalette& palette)
+{
+ if(d->frame)
+ d->frame->setPalette(palette);
+ KMyMoneyCombo::setPalette(palette);
+}
+
+void KMyMoneyCategory::reparent(QWidget *parent, WFlags w, const QPoint& pos, bool showIt)
+{
+ if(d->frame)
+ d->frame->reparent(parent, w, pos, showIt);
+ else
+ KMyMoneyCombo::reparent(parent, w, pos, showIt);
+}
+
+kMyMoneyAccountSelector* KMyMoneyCategory::selector(void) const
+{
+ return dynamic_cast<kMyMoneyAccountSelector*>(KMyMoneyCombo::selector());
+}
+
+void KMyMoneyCategory::setCurrentTextById(const QString& id)
+{
+ if(!id.isEmpty())
+ setCurrentText(MyMoneyFile::instance()->accountToCategory(id));
+ else
+ setCurrentText();
+ setSuppressObjectCreation(false);
+}
+
+void KMyMoneyCategory::slotItemSelected(const QString& id)
+{
+ setCurrentTextById(id);
+
+ m_completion->hide();
+
+ if(m_id != id) {
+ m_id = id;
+ emit itemSelected(id);
+ }
+}
+
+void KMyMoneyCategory::focusOutEvent(QFocusEvent *ev)
+{
+ if(isSplitTransaction()) {
+ KComboBox::focusOutEvent(ev);
+ } else {
+ KMyMoneyCombo::focusOutEvent(ev);
+ }
+}
+
+void KMyMoneyCategory::focusInEvent(QFocusEvent *ev)
+{
+ KMyMoneyCombo::focusInEvent(ev);
+
+ // make sure, we get a clean state before we automagically move the focus to
+ // some other widget (like for 'split transaction'). We do this by delaying
+ // the emission of the focusIn signal until the next run of the event loop.
+ QTimer::singleShot(0, this, SIGNAL(focusIn()));
+}
+
+void KMyMoneyCategory::setSplitTransaction(void)
+{
+ setCurrentText(i18n("Split transaction (category replacement)", "Split transaction"));
+ setSuppressObjectCreation(true);
+}
+
+bool KMyMoneyCategory::isSplitTransaction(void) const
+{
+ return currentText() == i18n("Split transaction (category replacement)", "Split transaction");
+}
+
+void KMyMoneyCategory::setEnabled(bool enable)
+{
+ if(d->recursive || !d->frame) {
+ KMyMoneyCombo::setEnabled(enable);
+
+ } else if(d->frame) {
+ d->recursive = true;
+ d->frame->setEnabled(enable);
+ d->recursive = false;
+ }
+}
+
+void KMyMoneyCategory::setDisabled(bool disable)
+{
+ setEnabled(!disable);
+}
+
+KMyMoneySecurity::KMyMoneySecurity(QWidget* parent, const char * name) :
+ KMyMoneyCategory(parent, name, false)
+{
+}
+
+KMyMoneySecurity::~KMyMoneySecurity()
+{
+}
+
+void KMyMoneySecurity::setCurrentTextById(const QString& id)
+{
+ if(!id.isEmpty())
+ KMyMoneyCategory::setCurrentText(MyMoneyFile::instance()->account(id).name());
+ else
+ KMyMoneyCategory::setCurrentText();
+}
+
+#include "kmymoneycategory.moc"
diff --git a/kmymoney2/widgets/kmymoneycategory.h b/kmymoney2/widgets/kmymoneycategory.h
new file mode 100644
index 0000000..474062d
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycategory.h
@@ -0,0 +1,196 @@
+/***************************************************************************
+ kmymoneycategory.h
+ -------------------
+ begin : Mon Jul 10 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYCATEGORY_H
+#define KMYMONEYCATEGORY_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QWidget;
+class QFrame;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+#include <kcombobox.h>
+class KPushButton;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneycombo.h>
+
+class kMyMoneyAccountSelector;
+
+/**
+ * This class implements a text based account/category selector.
+ * When initially used, the widget has the functionality of a KComboBox object.
+ * Whenever a key is pressed, the set of loaded accounts is searched for
+ * accounts which match the currently entered text.
+ *
+ * If any match is found a list selection box is opened and the user can use
+ * the up/down, page-up/page-down keys or the mouse to navigate in the list. If
+ * an account is selected, the selection box is closed. Other key-strokes are
+ * directed to the parent object to manipulate the text. The visible contents of
+ * the selection box is updated with every key-stroke.
+ *
+ * This object is a replacement of the kMyMoneyCategory object and should be used
+ * for new code.
+ *
+ * @author Thomas Baumgart
+ */
+class KMyMoneyCategory : public KMyMoneyCombo
+{
+ Q_OBJECT
+public:
+ /**
+ * Standard constructor for the account selection object.
+ *
+ * If parameter @a splitButton is @a true, the widget
+ * will construct a surrounding QFrame and reparent itself to be a child of this
+ * QFrame. It also adds a KPushButton with the "Split" icon to the right of the
+ * input field. In this case it is important not to use the pointer to this widget
+ * but it's parent when placing the object in a QLayout, QTable or some such. The
+ * parent widget (the QFrame in this case) can be extracted with the parentWidget()
+ * method.
+ *
+ * Reparenting is handled by the object transparently for both cases.
+ *
+ * Standard usage example (no split button):
+ *
+ * @code
+ * KMyMoneyCategory* category = new KMyMoneyCategory;
+ * category->reparent(newParent);
+ * layout->addWidget(category);
+ * table->setCellWidget(category);
+ * @endcode
+ *
+ * Enhanced usage example (with split button):
+ *
+ * @code
+ * KMyMoneyCategory* category = new KMyMoneyCategory(0, 0, true);
+ * category->reparent(newParent);
+ * layout->addWidget(category->parentWidget());
+ * table->setCellWidget(category->parentWidget());
+ * @endcode
+ */
+ KMyMoneyCategory(QWidget* parent = 0, const char* name = 0, bool splitButton = false);
+
+ virtual ~KMyMoneyCategory();
+
+ /**
+ * This member returns a pointer to the completion object.
+ *
+ * @return pointer to completion's selector object
+ */
+ kMyMoneyAccountSelector* selector(void) const;
+
+ /**
+ * This member returns a pointer to the split button. In case the @a splitButton parameter
+ * of the constructor was @a false, this method prints a warning to stderr and returns 0.
+ */
+ KPushButton* splitButton(void) const;
+
+ /**
+ * Reimplemented for internal reasons. No API change
+ */
+ virtual void reparent( QWidget *parent, WFlags, const QPoint &, bool showIt = FALSE );
+
+ /**
+ * Reimplemented for internal reasons. No API change.
+ */
+ virtual void setPalette(const QPalette& palette);
+
+ /**
+ * Force the text field to show the text for split transaction.
+ */
+ void setSplitTransaction(void);
+
+ /**
+ * Check if the text field contains the text for a split transaction
+ */
+ bool isSplitTransaction(void) const;
+
+ /**
+ * overridden for internal reasons, no API change
+ */
+ void setCurrentText(const QString& txt = QString()) { KMyMoneyCombo::setCurrentText(txt); }
+
+protected:
+ /**
+ * Reimplemented to support protected category text ("split transactions")
+ *
+ * @sa focusIn()
+ */
+ virtual void focusInEvent(QFocusEvent* ev);
+
+ /**
+ * Reimplemented to support protected category text ("split transactions")
+ */
+ virtual void focusOutEvent(QFocusEvent* ev);
+
+ /**
+ * set the widgets text area based on the item with the given @a id.
+ */
+ virtual void setCurrentTextById(const QString& id);
+
+public slots:
+ virtual void slotItemSelected(const QString& id);
+ virtual void setEnabled(bool);
+ virtual void setDisabled(bool);
+
+signals:
+ /**
+ * Signal to inform other objects that this object has reached focus.
+ * Used for e.g. to open the split dialog when the focus reaches this
+ * object and it contains the text 'Split transaction'.
+ *
+ * @sa focusInEvent()
+ */
+ void focusIn(void);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+
+class KMyMoneySecurity : public KMyMoneyCategory
+{
+ Q_OBJECT
+public:
+ KMyMoneySecurity(QWidget* parent = 0, const char* name = 0);
+ virtual ~KMyMoneySecurity();
+
+ /**
+ * overridden for internal reasons, no API change
+ */
+ void setCurrentText(const QString& txt = QString()) { KMyMoneyCategory::setCurrentText(txt); }
+
+protected:
+ /**
+ * set the widgets text area based on the item with the given @a id.
+ */
+ virtual void setCurrentTextById(const QString& id);
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneychecklistitem.cpp b/kmymoney2/widgets/kmymoneychecklistitem.cpp
new file mode 100644
index 0000000..8992beb
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneychecklistitem.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ kmymoneychecklistitem
+ -------------------
+ begin : Wed Jun 28 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfont.h>
+#include <qpainter.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneychecklistitem.h"
+#include "kmymoneylistviewitem.h"
+#include "../kmymoneyglobalsettings.h"
+
+KMyMoneyCheckListItem::KMyMoneyCheckListItem(QListView* parent, const QString& txt, const QString& key, const QString& id, Type type) :
+ QCheckListItem(parent, txt, type),
+ m_key(key),
+ m_id(id),
+ m_isOdd(0),
+ m_isKnown(0)
+{
+ setOn(true);
+ if(key.isEmpty())
+ m_key = txt;
+}
+
+KMyMoneyCheckListItem::KMyMoneyCheckListItem(QListViewItem* parent, const QString& txt, const QString& key, const QString& id, Type type) :
+ QCheckListItem(parent, txt, type),
+ m_key(key),
+ m_id(id),
+ m_isOdd(0),
+ m_isKnown(0)
+{
+ setOn(true);
+ if(key.isEmpty())
+ m_key = txt;
+}
+
+KMyMoneyCheckListItem::KMyMoneyCheckListItem(QListView* parent, QListViewItem* after, const QString& txt, const QString& key, const QString& id, Type type) :
+ QCheckListItem(parent, after, txt, type),
+ m_key(key),
+ m_id(id),
+ m_isOdd(0),
+ m_isKnown(0)
+{
+ setOn(true);
+ if(key.isEmpty())
+ m_key = txt;
+}
+
+KMyMoneyCheckListItem::~KMyMoneyCheckListItem()
+{
+}
+
+QString KMyMoneyCheckListItem::key(int column, bool ascending) const
+{
+ Q_UNUSED(ascending);
+
+ if(column == 0)
+ return m_key[0] + text(0);
+ return m_key.mid(1);
+}
+
+void KMyMoneyCheckListItem::stateChange(bool state)
+{
+ emit stateChanged(state);
+}
+
+void KMyMoneyCheckListItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
+{
+ QColorGroup _cg = cg;
+ _cg.setColor(QColorGroup::Base, backgroundColor());
+
+ // write the groups in bold
+ QFont f = p->font();
+ f.setBold(!isSelectable());
+ p->setFont(f);
+
+ QCheckListItem::paintCell(p, _cg, column, width, alignment);
+}
+
+const QColor KMyMoneyCheckListItem::backgroundColor()
+{
+ return isAlternate() ? KMyMoneyGlobalSettings::listBGColor() : KMyMoneyGlobalSettings::listColor();
+}
+
+bool KMyMoneyCheckListItem::isAlternate(void)
+{
+// logic taken from KListViewItem::isAlternate()
+ KMyMoneyCheckListItem* ciAbove;
+ KMyMoneyListViewItem* liAbove;
+ ciAbove = dynamic_cast<KMyMoneyCheckListItem*> (itemAbove());
+ liAbove = dynamic_cast<KMyMoneyListViewItem*> (itemAbove());
+
+ m_isKnown = ciAbove ? ciAbove->m_isKnown : (liAbove ? liAbove->m_isKnown : true);
+ if(m_isKnown) {
+ m_isOdd = ciAbove ? !ciAbove->m_isOdd : (liAbove ? !liAbove->m_isOdd : false);
+ } else {
+ KMyMoneyCheckListItem* clItem;
+ KMyMoneyListViewItem* liItem;
+ bool previous = true;
+ if(QListViewItem::parent()) {
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(QListViewItem::parent());
+ liItem = dynamic_cast<KMyMoneyListViewItem*>(QListViewItem::parent());
+ if(clItem)
+ previous = clItem->m_isOdd;
+ else
+ previous = liItem->m_isOdd;
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(QListViewItem::parent()->firstChild());
+ liItem = dynamic_cast<KMyMoneyListViewItem*>(QListViewItem::parent()->firstChild());
+ } else {
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(listView()->firstChild());
+ liItem = dynamic_cast<KMyMoneyListViewItem*>(listView()->firstChild());
+ }
+ while(clItem || liItem) {
+ if(clItem) {
+ clItem->m_isOdd = previous = !previous;
+ clItem->m_isKnown = true;
+ liItem = dynamic_cast<KMyMoneyListViewItem *>(clItem->nextSibling());
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(clItem->nextSibling());
+ } else if(liItem) {
+ liItem->m_isOdd = previous = !previous;
+ liItem->m_isKnown = true;
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(liItem->nextSibling());
+ liItem = dynamic_cast<KMyMoneyListViewItem *>(liItem->nextSibling());
+ }
+ }
+ }
+ return m_isOdd;
+}
+
+#include "kmymoneychecklistitem.moc"
diff --git a/kmymoney2/widgets/kmymoneychecklistitem.h b/kmymoney2/widgets/kmymoneychecklistitem.h
new file mode 100644
index 0000000..6a22ec9
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneychecklistitem.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ kmymoneychecklistitem - description
+ -------------------
+ begin : Wed Jun 28 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYCHECKLISTITEM_H
+#define KMYMONEYCHECKLISTITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qlistview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KMyMoneyListViewItem;
+
+/**
+ * This class implements a derived version of a QCheckListItem that
+ * allows the storage of an engine object id with the object and emits
+ * a signal upon state change.
+ *
+ * @author Thomas Baumgart
+ */
+class KMyMoneyCheckListItem : public QObject, public QCheckListItem
+{
+ friend class KMyMoneyListViewItem;
+
+ Q_OBJECT
+public:
+ KMyMoneyCheckListItem(QListView *parent, const QString& txt, const QString& key, const QString& id, Type type = QCheckListItem::CheckBox);
+ KMyMoneyCheckListItem(QListView *parent, QListViewItem* after, const QString& txt, const QString& key, const QString& id, Type type = QCheckListItem::CheckBox);
+ KMyMoneyCheckListItem(QListViewItem *parent, const QString& txt, const QString& key, const QString& id, Type type = QCheckListItem::CheckBox);
+ ~KMyMoneyCheckListItem();
+
+ const QString& id(void) const { return m_id; };
+
+ /**
+ * use my own paint method
+ */
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment);
+
+ /**
+ * use my own backgroundColor method
+ */
+ const QColor backgroundColor();
+
+ /**
+ * see KListViewItem::isAlternate()
+ */
+ bool isAlternate(void);
+
+ /**
+ * This method returns a const reference to the key passed to the constructor. The column
+ * defines what is returned: For @a column equals 0, the first character passed as @a key to
+ * the constructor concatenated with the value returned by text(0) is returned. For @a column
+ * equals to 1, the @a key as passed to the constructor except the first character is returned.
+ */
+ QString key(int column, bool ascending) const;
+
+signals:
+ void stateChanged(bool);
+
+protected:
+ virtual void stateChange(bool);
+
+private:
+ QString m_key;
+ QString m_id;
+ // copied from KListViewItem()
+ unsigned int m_isOdd : 1;
+ unsigned int m_isKnown : 1;
+ unsigned int m_unused : 30;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneycombo.cpp b/kmymoney2/widgets/kmymoneycombo.cpp
new file mode 100644
index 0000000..8bbec10
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycombo.cpp
@@ -0,0 +1,778 @@
+/***************************************************************************
+ kmymoneycombo.cpp - description
+ -------------------
+ begin : Mon Mar 12 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qrect.h>
+#include <qstyle.h>
+#include <qpainter.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <klistview.h>
+#include <kdebug.h>
+#include <kconfig.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneycombo.h"
+#include "kmymoneyselector.h"
+#include <kmymoney/kmymoneycompletion.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/registeritem.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include "../kmymoneyutils.h"
+
+KMyMoneyCombo::KMyMoneyCombo(QWidget *w, const char *name) :
+ KComboBox(w, name),
+ m_completion(0),
+ m_edit(0),
+ m_canCreateObjects(false),
+ m_inFocusOutEvent(false)
+{
+}
+
+KMyMoneyCombo::KMyMoneyCombo(bool rw, QWidget *w, const char *name) :
+ KComboBox(rw, w, name),
+ m_completion(0),
+ m_edit(0),
+ m_canCreateObjects(false),
+ m_inFocusOutEvent(false)
+{
+ if(rw) {
+ m_edit = new kMyMoneyLineEdit(this, "combo edit");
+ setLineEdit(m_edit);
+ }
+}
+
+void KMyMoneyCombo::setCurrentTextById(const QString& id)
+{
+ setCurrentText();
+ if(!id.isEmpty()) {
+ QListViewItem* item = selector()->item(id);
+ if(item)
+ setCurrentText(item->text(0));
+ }
+}
+
+void KMyMoneyCombo::slotItemSelected(const QString& id)
+{
+ if(editable()) {
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ setCurrentTextById(id);
+ blockSignals(blocked);
+ }
+
+ m_completion->hide();
+
+ if(m_id != id) {
+ m_id = id;
+ emit itemSelected(id);
+ }
+}
+
+void KMyMoneyCombo::setEditable(bool y)
+{
+ if(y == editable())
+ return;
+
+ KComboBox::setEditable(y);
+
+ // make sure we use our own line edit style
+ if(y) {
+ m_edit = new kMyMoneyLineEdit(this, "combo edit");
+ setLineEdit(m_edit);
+ m_edit->setPaletteBackgroundColor(paletteBackgroundColor());
+
+ } else {
+ m_edit = 0;
+ }
+}
+
+void KMyMoneyCombo::setHint(const QString& hint) const
+{
+ if(m_edit)
+ m_edit->setHint(hint);
+}
+
+void KMyMoneyCombo::paintEvent(QPaintEvent* ev)
+{
+ KComboBox::paintEvent(ev);
+
+ // if we don't have an edit field, we need to paint the text onto the button
+ if(!m_edit) {
+ if(m_completion) {
+ QStringList list;
+ selector()->selectedItems(list);
+ if(!list.isEmpty()) {
+ QString str = selector()->item(list[0])->text(0);
+ // we only paint, if the text is longer than 1 char. Assumption
+ // is that length 1 is the blank case so no need to do painting
+ if(str.length() > 1) {
+ QPainter p( this );
+ const QColorGroup & g = colorGroup();
+ p.setPen(g.text());
+
+ QRect re = style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxEditField );
+ re = QStyle::visualRect(re, this);
+ p.setClipRect( re );
+ p.save();
+ p.setFont(font());
+ QFontMetrics fm(font());
+ int x = re.x(), y = re.y() + fm.ascent();
+ p.drawText( x, y, str );
+ p.restore();
+ }
+ }
+ }
+ }
+}
+
+void KMyMoneyCombo::setPaletteBackgroundColor(const QColor& color)
+{
+ KComboBox::setPaletteBackgroundColor(color);
+ if(m_edit) {
+ m_edit->setPaletteBackgroundColor(color);
+ }
+}
+
+void KMyMoneyCombo::mousePressEvent(QMouseEvent *e)
+{
+ // mostly copied from QCombo::mousePressEvent() and adjusted for our needs
+ if(e->button() != LeftButton)
+ return;
+
+ if(((!editable() || isInArrowArea(mapToGlobal(e->pos()))) && selector()->itemList().count()) && !m_completion->isVisible()) {
+ m_completion->show();
+ }
+
+ if(m_timer.isActive()) {
+ m_timer.stop();
+ m_completion->slotMakeCompletion("");
+ } else {
+ KConfig config( "kcminputrc", true );
+ config.setGroup("KDE");
+ m_timer.start(config.readNumEntry("DoubleClickInterval", 400), true);
+ }
+}
+
+bool KMyMoneyCombo::isInArrowArea(const QPoint& pos) const
+{
+ QRect arrowRect = style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxArrow);
+ arrowRect = QStyle::visualRect(arrowRect, this);
+
+ // Correction for motif style, where arrow is smaller
+ // and thus has a rect that doesn't fit the button.
+ arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) );
+
+ // if the button is not editable, it covers the whole widget
+ if(!editable())
+ arrowRect = rect();
+
+ return arrowRect.contains(mapFromGlobal(pos));
+}
+
+void KMyMoneyCombo::keyPressEvent(QKeyEvent* e)
+{
+ if((e->key() == Key_F4 && e->state() == 0 ) ||
+ (e->key() == Key_Down && (e->state() & AltButton)) ||
+ (!editable() && e->key() == Key_Space)) {
+ // if we have at least one item in the list, we open the dropdown
+ if(selector()->listView()->firstChild())
+ m_completion->show();
+ e->ignore();
+ return;
+ }
+ KComboBox::keyPressEvent(e);
+}
+
+void KMyMoneyCombo::connectNotify(const char* signal)
+{
+ if(signal && !strcmp(signal, SIGNAL(createItem(const QString&,QString&)))) {
+ m_canCreateObjects = true;
+ }
+}
+
+void KMyMoneyCombo::disconnectNotify(const char* signal)
+{
+ if(signal && !strcmp(signal, SIGNAL(createItem(const QString&,QString&)))) {
+ m_canCreateObjects = false;
+ }
+}
+
+void KMyMoneyCombo::focusOutEvent(QFocusEvent* e)
+{
+ if(m_inFocusOutEvent) {
+ KComboBox::focusOutEvent(e);
+ return;
+ }
+
+ m_inFocusOutEvent = true;
+ if(editable() && !currentText().isEmpty()) {
+ if(m_canCreateObjects) {
+ if(!m_completion->selector()->contains(currentText())) {
+ QString id;
+ // annouce that we go into a possible dialog to create an object
+ // This can be used by upstream widgets to disable filters etc.
+ emit objectCreation(true);
+
+ emit createItem(currentText(), id);
+
+ // Announce that we return from object creation
+ emit objectCreation(false);
+
+ // update the field to a possibly created object
+ m_id = id;
+ setCurrentTextById(id);
+
+ // make sure the completion does not show through
+ m_completion->hide();
+ }
+
+ // else if we cannot create objects, and the current text is not
+ // in the list, then we clear the text and the selection.
+ } else if(!m_completion->selector()->contains(currentText())) {
+ setCurrentText(QString());
+ }
+ }
+
+ KComboBox::focusOutEvent(e);
+
+ // force update of hint and id if there is no text in the widget
+ if(editable() && currentText().isEmpty()) {
+ QString id = m_id;
+ m_id = QString();
+ if(!id.isEmpty())
+ emit itemSelected(m_id);
+ repaint();
+ }
+ m_inFocusOutEvent = false;
+}
+
+KMyMoneySelector* KMyMoneyCombo::selector(void) const
+{
+ return m_completion->selector();
+}
+
+kMyMoneyCompletion* KMyMoneyCombo::completion(void) const
+{
+ return m_completion;
+}
+
+void KMyMoneyCombo::selectedItem(QString& id) const
+{
+ id = m_id;
+}
+
+void KMyMoneyCombo::selectedItems(QStringList& list) const
+{
+ if(lineEdit() && lineEdit()->text().length() == 0) {
+ list.clear();
+ } else {
+ m_completion->selector()->selectedItems(list);
+ }
+}
+
+void KMyMoneyCombo::setSelectedItem(const QString& id)
+{
+ m_completion->selector()->setSelected(id, true);
+ blockSignals(true);
+ slotItemSelected(id);
+ blockSignals(false);
+ update();
+}
+
+QSize KMyMoneyCombo::sizeHint() const
+{
+ return KComboBox::sizeHint();
+
+ // I wanted to use the code below to adjust the size of the combo box
+ // according to the largest item in the selector list. Apparently that
+ // does not work too well in the enter and edit schedule dialog for
+ // the category combo box. So we just use the standard implementation for now.
+#if 0
+ constPolish();
+ int i, w;
+ QFontMetrics fm = fontMetrics();
+
+ int maxW = count() ? 18 : 7 * fm.width(QChar('x')) + 18;
+ int maxH = QMAX( fm.lineSpacing(), 14 ) + 2;
+
+ w = selector()->optimizedWidth();
+ if ( w > maxW )
+ maxW = w;
+
+ QSize sizeHint = (style().sizeFromContents(QStyle::CT_ComboBox, this,
+ QSize(maxW, maxH)).
+ expandedTo(QApplication::globalStrut()));
+
+ return sizeHint;
+#endif
+}
+
+
+
+KMyMoneyReconcileCombo::KMyMoneyReconcileCombo(QWidget* w, const char* name) :
+ KMyMoneyCombo(false, w, name)
+{
+ m_completion = new kMyMoneyCompletion(this, 0);
+ // connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SIGNAL(itemSelected(const QString&)));
+
+ // add the items in reverse order of appearance (see KMyMoneySelector::newItem() for details)
+ // selector()->newTopItem(i18n("Frozen"), QString(), "F");
+ selector()->newTopItem(i18n("Reconciled"), QString(), "R");
+ selector()->newTopItem(i18n("Cleared"), QString(), "C");
+ selector()->newTopItem(i18n("Not reconciled"), QString(), " ");
+ selector()->newTopItem(" ", QString(), "U");
+
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotItemSelected(const QString&)));
+ connect(this, SIGNAL(itemSelected(const QString&)), this, SLOT(slotSetState(const QString&)));
+}
+
+void KMyMoneyReconcileCombo::slotSetState(const QString& state)
+{
+ setSelectedItem(state);
+}
+
+void KMyMoneyReconcileCombo::removeDontCare(void)
+{
+ selector()->removeItem("U");
+}
+
+void KMyMoneyReconcileCombo::setState(MyMoneySplit::reconcileFlagE state)
+{
+ QString id;
+ switch(state) {
+ case MyMoneySplit::NotReconciled:
+ id = " ";
+ break;
+ case MyMoneySplit::Cleared:
+ id = "C";
+ break;
+ case MyMoneySplit::Reconciled:
+ id = "R";
+ break;
+ case MyMoneySplit::Frozen:
+ id = "F";
+ break;
+ case MyMoneySplit::Unknown:
+ id = "U";
+ break;
+ default:
+ kdDebug(2) << "Unknown reconcile state '" << state << "' in KMyMoneyComboReconcile::setState()\n";
+ break;
+ }
+ setSelectedItem(id);
+}
+
+MyMoneySplit::reconcileFlagE KMyMoneyReconcileCombo::state(void) const
+{
+ MyMoneySplit::reconcileFlagE state = MyMoneySplit::NotReconciled;
+
+ QStringList list;
+ selector()->selectedItems(list);
+ if(!list.isEmpty()) {
+ if(list[0] == "C")
+ state = MyMoneySplit::Cleared;
+ if(list[0] == "R")
+ state = MyMoneySplit::Reconciled;
+ if(list[0] == "F")
+ state = MyMoneySplit::Frozen;
+ if(list[0] == "U")
+ state = MyMoneySplit::Unknown;
+ }
+ return state;
+}
+
+
+KMyMoneyComboAction::KMyMoneyComboAction(QWidget* w, const char* name) :
+ KMyMoneyCombo(false, w, name)
+{
+ m_completion = new kMyMoneyCompletion(this, 0);
+ QString num;
+ // add the items in reverse order of appearance (see KMyMoneySelector::newItem() for details)
+ selector()->newTopItem(i18n("ATM"), QString(), num.setNum(KMyMoneyRegister::ActionAtm));
+ selector()->newTopItem(i18n("Withdrawal"), QString(), num.setNum(KMyMoneyRegister::ActionWithdrawal));
+ selector()->newTopItem(i18n("Transfer"), QString(), num.setNum(KMyMoneyRegister::ActionTransfer));
+ selector()->newTopItem(i18n("Deposit"), QString(), num.setNum(KMyMoneyRegister::ActionDeposit));
+ selector()->newTopItem(i18n("Cheque"), QString(), num.setNum(KMyMoneyRegister::ActionCheck));
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotItemSelected(const QString&)));
+ connect(this, SIGNAL(itemSelected(const QString&)), this, SLOT(slotSetAction(const QString&)));
+}
+
+void KMyMoneyComboAction::protectItem(int id, bool protect)
+{
+ QString num;
+ selector()->protectItem(num.setNum(id), protect);
+}
+
+void KMyMoneyComboAction::slotSetAction(const QString& act)
+{
+ setSelectedItem(act);
+ update();
+ emit actionSelected(action());
+}
+
+void KMyMoneyComboAction::setAction(int action)
+{
+ if(action < 0 || action > 5) {
+ kdDebug(2) << "KMyMoneyComboAction::slotSetAction(" << action << ") invalid. Replaced with 2\n";
+ action = 2;
+ }
+ QString act;
+ act.setNum(action);
+ setSelectedItem(act);
+}
+
+int KMyMoneyComboAction::action(void) const
+{
+ QStringList list;
+ selector()->selectedItems(list);
+ if(!list.isEmpty()) {
+ return list[0].toInt();
+ }
+ kdDebug(2) << "KMyMoneyComboAction::action(void): unknown selection\n";
+ return 0;
+}
+
+KMyMoneyCashFlowCombo::KMyMoneyCashFlowCombo(QWidget* w, const char* name, MyMoneyAccount::accountTypeE accountType) :
+ KMyMoneyCombo(false, w, name)
+{
+ m_completion = new kMyMoneyCompletion(this, 0);
+ QString num;
+ // add the items in reverse order of appearance (see KMyMoneySelector::newItem() for details)
+ if(accountType == MyMoneyAccount::Income || accountType == MyMoneyAccount::Expense) {
+ // this is used for income/expense accounts to just show the reverse sense
+ selector()->newTopItem(i18n("Activity for expense categories", "Paid"), QString(), num.setNum(KMyMoneyRegister::Deposit));
+ selector()->newTopItem(i18n("Activity for income categories", "Received"), QString(), num.setNum(KMyMoneyRegister::Payment));
+ } else {
+ selector()->newTopItem(i18n("From"), QString(), num.setNum(KMyMoneyRegister::Deposit));
+ selector()->newTopItem(i18n("Pay to"), QString(), num.setNum(KMyMoneyRegister::Payment));
+ }
+ selector()->newTopItem(" ", QString(), num.setNum(KMyMoneyRegister::Unknown));
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotItemSelected(const QString&)));
+ connect(this, SIGNAL(itemSelected(const QString&)), this, SLOT(slotSetDirection(const QString&)));
+}
+
+void KMyMoneyCashFlowCombo::setDirection(KMyMoneyRegister::CashFlowDirection dir)
+{
+ m_dir = dir;
+ QString num;
+ setSelectedItem(num.setNum(dir));
+}
+
+void KMyMoneyCashFlowCombo::slotSetDirection(const QString& id)
+{
+ QString num;
+ for(int i = KMyMoneyRegister::Deposit; i <= KMyMoneyRegister::Unknown; ++i) {
+ num.setNum(i);
+ if(num == id) {
+ m_dir = static_cast<KMyMoneyRegister::CashFlowDirection>(i);
+ break;
+ }
+ }
+ emit directionSelected(m_dir);
+ update();
+}
+
+void KMyMoneyCashFlowCombo::removeDontCare(void)
+{
+ QString num;
+ selector()->removeItem(num.setNum(KMyMoneyRegister::Unknown));
+}
+
+
+KMyMoneyActivityCombo::KMyMoneyActivityCombo(QWidget* w, const char* name) :
+ KMyMoneyCombo(false, w, name),
+ m_activity(MyMoneySplit::UnknownTransactionType)
+{
+ m_completion = new kMyMoneyCompletion(this, 0);
+ QString num;
+ // add the items in reverse order of appearance (see KMyMoneySelector::newItem() for details)
+ selector()->newTopItem(i18n("Split shares"), QString(), num.setNum(MyMoneySplit::SplitShares));
+ selector()->newTopItem(i18n("Remove shares"), QString(), num.setNum(MyMoneySplit::RemoveShares));
+ selector()->newTopItem(i18n("Add shares"), QString(), num.setNum(MyMoneySplit::AddShares));
+ selector()->newTopItem(i18n("Yield"), QString(), num.setNum(MyMoneySplit::Yield));
+ selector()->newTopItem(i18n("Reinvest dividend"), QString(), num.setNum(MyMoneySplit::ReinvestDividend));
+ selector()->newTopItem(i18n("Dividend"), QString(), num.setNum(MyMoneySplit::Dividend));
+ selector()->newTopItem(i18n("Sell shares"), QString(), num.setNum(MyMoneySplit::SellShares));
+ selector()->newTopItem(i18n("Buy shares"), QString(), num.setNum(MyMoneySplit::BuyShares));
+
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotItemSelected(const QString&)));
+ connect(this, SIGNAL(itemSelected(const QString&)), this, SLOT(slotSetActivity(const QString&)));
+}
+
+void KMyMoneyActivityCombo::setActivity(MyMoneySplit::investTransactionTypeE activity)
+{
+ m_activity = activity;
+ QString num;
+ setSelectedItem(num.setNum(activity));
+}
+
+void KMyMoneyActivityCombo::slotSetActivity(const QString& id)
+{
+ QString num;
+ for(int i = MyMoneySplit::BuyShares; i <= MyMoneySplit::SplitShares; ++i) {
+ num.setNum(i);
+ if(num == id) {
+ m_activity = static_cast<MyMoneySplit::investTransactionTypeE>(i);
+ break;
+ }
+ }
+ emit activitySelected(m_activity);
+ update();
+}
+
+KMyMoneyPayeeCombo::KMyMoneyPayeeCombo(QWidget* parent, const char * name) :
+ KMyMoneyCombo(true, parent, name)
+{
+ m_completion = new kMyMoneyCompletion(this);
+
+ // set to ascending sort
+ selector()->listView()->setSorting(0);
+
+ connect(m_completion, SIGNAL(itemSelected(const QString&)), this, SLOT(slotItemSelected(const QString&)));
+ connect(this, SIGNAL(textChanged(const QString&)), m_completion, SLOT(slotMakeCompletion(const QString&)));
+}
+
+void KMyMoneyPayeeCombo::loadPayees(const QValueList<MyMoneyPayee>& list)
+{
+ selector()->listView()->clear();
+ QValueList<MyMoneyPayee>::const_iterator it;
+ for(it = list.begin(); it != list.end(); ++it) {
+ selector()->newTopItem((*it).name(), QString(), (*it).id());
+ }
+}
+
+
+class KMyMoneyGeneralCombo::Private {
+public:
+ QMap<QString, int> m_strings;
+ void insertItem(const QString& s, int id) { m_strings[s] = id; }
+
+ int itemId(const QString& s) const {
+ QMap<QString, int>::const_iterator it;
+ it = m_strings.find(s);
+ if(it != m_strings.end())
+ return *it;
+ return -1;
+ }
+
+ const QString& itemText(int id) {
+ QMap<QString, int>::const_iterator it;
+ for(it = m_strings.begin(); it != m_strings.end(); ++it) {
+ if(*it == id) {
+ return it.key();
+ }
+ }
+ return QString::null;
+ }
+};
+
+KMyMoneyGeneralCombo::KMyMoneyGeneralCombo(QWidget* w, const char* name) :
+ KComboBox(w, name),
+ d(new Private)
+{
+ connect(this, SIGNAL(highlighted(int)), this, SLOT(slotChangeItem(int)));
+}
+
+KMyMoneyGeneralCombo::~KMyMoneyGeneralCombo()
+{
+ delete d;
+}
+
+void KMyMoneyGeneralCombo::setItem(int id)
+{
+ setCurrentItem(id);
+}
+
+int KMyMoneyGeneralCombo::item(void) const
+{
+ return currentItem();
+}
+
+void KMyMoneyGeneralCombo::setCurrentItem(int id)
+{
+ const QString& txt = d->itemText(id);
+ for(int idx = 0; idx < count(); ++idx) {
+ if(txt == text(idx)) {
+ KComboBox::setCurrentItem(idx);
+ break;
+ }
+ }
+}
+
+int KMyMoneyGeneralCombo::currentItem(void) const
+{
+ return d->itemId(currentText());
+}
+
+void KMyMoneyGeneralCombo::clear(void)
+{
+ d->m_strings.clear();
+ KComboBox::clear();
+}
+
+void KMyMoneyGeneralCombo::insertItem(const QString& txt, int id, int idx)
+{
+ d->insertItem(txt, id);
+ KComboBox::insertItem(txt, idx);
+}
+
+void KMyMoneyGeneralCombo::removeItem(int id)
+{
+ const QString& txt = d->itemText(id);
+ for(int idx = 0; idx < count(); ++idx) {
+ if(txt == text(idx)) {
+ KComboBox::removeItem(idx);
+ break;
+ }
+ }
+}
+
+void KMyMoneyGeneralCombo::slotChangeItem(int idx)
+{
+ emit itemSelected(d->itemId(text(idx)));
+}
+
+KMyMoneyPeriodCombo::KMyMoneyPeriodCombo(QWidget* parent, const char* name) :
+ KMyMoneyGeneralCombo(parent, name)
+{
+ insertItem(i18n("All dates"), MyMoneyTransactionFilter::allDates);
+ insertItem(i18n("As of today"), MyMoneyTransactionFilter::asOfToday);
+ insertItem(i18n("Today"), MyMoneyTransactionFilter::today);
+ insertItem(i18n("Current month"), MyMoneyTransactionFilter::currentMonth);
+ insertItem(i18n("Current quarter"), MyMoneyTransactionFilter::currentQuarter);
+ insertItem(i18n("Current year"), MyMoneyTransactionFilter::currentYear);
+ insertItem(i18n("Current fiscal year"), MyMoneyTransactionFilter::currentFiscalYear);
+ insertItem(i18n("Month to date"), MyMoneyTransactionFilter::monthToDate);
+ insertItem(i18n("Year to date"), MyMoneyTransactionFilter::yearToDate);
+ insertItem(i18n("Year to month"), MyMoneyTransactionFilter::yearToMonth);
+ insertItem(i18n("Last month"), MyMoneyTransactionFilter::lastMonth);
+ insertItem(i18n("Last year"), MyMoneyTransactionFilter::lastYear);
+ insertItem(i18n("Last fiscal year"), MyMoneyTransactionFilter::lastFiscalYear);
+ insertItem(i18n("Last 7 days"), MyMoneyTransactionFilter::last7Days);
+ insertItem(i18n("Last 30 days"), MyMoneyTransactionFilter::last30Days);
+ insertItem(i18n("Last 3 months"), MyMoneyTransactionFilter::last3Months);
+ insertItem(i18n("Last quarter"), MyMoneyTransactionFilter::lastQuarter);
+ insertItem(i18n("Last 6 months"), MyMoneyTransactionFilter::last6Months);
+ insertItem(i18n("Last 11 months"), MyMoneyTransactionFilter::last11Months);
+ insertItem(i18n("Last 12 months"), MyMoneyTransactionFilter::last12Months);
+ insertItem(i18n("Next 7 days"), MyMoneyTransactionFilter::next7Days);
+ insertItem(i18n("Next 30 days"), MyMoneyTransactionFilter::next30Days);
+ insertItem(i18n("Next 3 months"), MyMoneyTransactionFilter::next3Months);
+ insertItem(i18n("Next quarter"), MyMoneyTransactionFilter::lastQuarter);
+ insertItem(i18n("Next 6 months"), MyMoneyTransactionFilter::next6Months);
+ insertItem(i18n("Next 12 months"), MyMoneyTransactionFilter::next12Months);
+ insertItem(i18n("Last 3 months to next 3 months"), MyMoneyTransactionFilter::last3ToNext3Months);
+ insertItem(i18n("User defined"), MyMoneyTransactionFilter::userDefined);
+}
+
+void KMyMoneyPeriodCombo::setCurrentItem(MyMoneyTransactionFilter::dateOptionE id)
+{
+ if(id >= MyMoneyTransactionFilter::dateOptionCount)
+ id = MyMoneyTransactionFilter::userDefined;
+
+ KMyMoneyGeneralCombo::setCurrentItem(id);
+}
+
+MyMoneyTransactionFilter::dateOptionE KMyMoneyPeriodCombo::currentItem(void) const
+{
+ return static_cast<MyMoneyTransactionFilter::dateOptionE>(KMyMoneyGeneralCombo::currentItem());
+}
+
+QDate KMyMoneyPeriodCombo::start(MyMoneyTransactionFilter::dateOptionE id)
+{
+ QDate start, end;
+ MyMoneyTransactionFilter::translateDateRange(id, start, end);
+ return start;
+}
+
+QDate KMyMoneyPeriodCombo::end(MyMoneyTransactionFilter::dateOptionE id)
+{
+ QDate start, end;
+ MyMoneyTransactionFilter::translateDateRange(id, start, end);
+ return end;
+}
+
+#if 0
+void KMyMoneyPeriodCombo::dates(QDate& start, QDate& end, MyMoneyTransactionFilter::dateOptionE id)
+{
+}
+#endif
+
+KMyMoneyOccurenceCombo::KMyMoneyOccurenceCombo(QWidget* parent, const char* name) :
+ KMyMoneyGeneralCombo(parent, name)
+{
+}
+
+MyMoneySchedule::occurenceE KMyMoneyOccurenceCombo::currentItem(void) const
+{
+ return static_cast<MyMoneySchedule::occurenceE>(KMyMoneyGeneralCombo::currentItem());
+}
+
+KMyMoneyOccurencePeriodCombo::KMyMoneyOccurencePeriodCombo(QWidget* parent, const char* name) :
+ KMyMoneyOccurenceCombo(parent, name)
+{
+ insertItem(i18n(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_ONCE)), MyMoneySchedule::OCCUR_ONCE);
+ insertItem(i18n(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_DAILY)), MyMoneySchedule::OCCUR_DAILY);
+ insertItem(i18n(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_WEEKLY)), MyMoneySchedule::OCCUR_WEEKLY);
+ insertItem(i18n(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH)), MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ insertItem(i18n(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_MONTHLY)), MyMoneySchedule::OCCUR_MONTHLY);
+ insertItem(i18n(MyMoneySchedule::occurencePeriodToString(MyMoneySchedule::OCCUR_YEARLY)), MyMoneySchedule::OCCUR_YEARLY);
+}
+
+KMyMoneyFrequencyCombo::KMyMoneyFrequencyCombo(QWidget* parent, const char* name) :
+ KMyMoneyOccurenceCombo(parent, name)
+{
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_ONCE)), MyMoneySchedule::OCCUR_ONCE);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_DAILY)), MyMoneySchedule::OCCUR_DAILY);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_WEEKLY)), MyMoneySchedule::OCCUR_WEEKLY);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERWEEK)), MyMoneySchedule::OCCUR_EVERYOTHERWEEK);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYHALFMONTH)), MyMoneySchedule::OCCUR_EVERYHALFMONTH);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEWEEKS)), MyMoneySchedule::OCCUR_EVERYTHREEWEEKS);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS)), MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURWEEKS)), MyMoneySchedule::OCCUR_EVERYFOURWEEKS);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_MONTHLY)), MyMoneySchedule::OCCUR_MONTHLY);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS)), MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERMONTH)), MyMoneySchedule::OCCUR_EVERYOTHERMONTH);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYTHREEMONTHS)), MyMoneySchedule::OCCUR_EVERYTHREEMONTHS);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYFOURMONTHS)), MyMoneySchedule::OCCUR_EVERYFOURMONTHS);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_TWICEYEARLY)), MyMoneySchedule::OCCUR_TWICEYEARLY);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_YEARLY)), MyMoneySchedule::OCCUR_YEARLY);
+ insertItem(i18n(MyMoneySchedule::occurenceToString(MyMoneySchedule::OCCUR_EVERYOTHERYEAR)), MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+}
+
+int KMyMoneyFrequencyCombo::daysBetweenEvents(void) const
+{
+ return MyMoneySchedule::daysBetweenEvents(currentItem());
+}
+
+int KMyMoneyFrequencyCombo::eventsPerYear(void) const
+{
+ return MyMoneySchedule::eventsPerYear(currentItem());
+}
+#include "kmymoneycombo.moc"
diff --git a/kmymoney2/widgets/kmymoneycombo.h b/kmymoney2/widgets/kmymoneycombo.h
new file mode 100644
index 0000000..c85847d
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycombo.h
@@ -0,0 +1,467 @@
+/***************************************************************************
+ kmymoneycombo.h - description
+ -------------------
+ begin : Mon Mar 12 2007
+ copyright : (C) 2007 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYCOMBO_H
+#define KMYMONEYCOMBO_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtimer.h>
+#include <qmutex.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyutils.h>
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/register.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/transaction.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneytransactionfilter.h>
+#include <kmymoney/mymoneyscheduled.h>
+
+class kMyMoneyCompletion;
+class KMyMoneySelector;
+class kMyMoneyLineEdit;
+
+/**
+ * @author Thomas Baumgart
+ */
+class KMyMoneyCombo : public KComboBox
+{
+ Q_OBJECT
+public:
+ KMyMoneyCombo(QWidget *w = 0, const char *name=0);
+ KMyMoneyCombo(bool rw, QWidget *w = 0, const char *name=0);
+
+ /**
+ * This method is used to turn on/off the hint display and to setup the appropriate text.
+ * The hint text is shown in a lighter color if the field is otherwise empty and does
+ * not have the keyboard focus.
+ *
+ * @param hint reference to text. If @a hint is empty, no hint will be shown.
+ */
+ void setHint(const QString& hint) const;
+
+ /**
+ * overridden for internal reasons.
+ *
+ * @param editable make combo box editable (@a true) or selectable only (@a false).
+ */
+ void setEditable(bool editable);
+
+ /**
+ * This method returns a pointer to the completion object of the combo box.
+ *
+ * @return pointer to kMyMoneyCompletion or derivative.
+ */
+ kMyMoneyCompletion* completion(void) const;
+
+ /**
+ * This method returns a pointer to the completion object's selector.
+ *
+ * @return pointer to KMyMoneySelector or derivative.
+ */
+ KMyMoneySelector* selector(void) const;
+
+ /**
+ * This method returns the ids of the currently selected items
+ */
+ void selectedItems(QStringList& list) const;
+
+ /**
+ * This method returns the id of the first selected item.
+ * Usage makes usually only sense when the selection mode
+ * of the associated KMyMoneySelector is QListView::Single.
+ *
+ * @sa KMyMoneySelector::setSelectionMode()
+ *
+ * @param id reference to QString containing the id. If no item
+ * is selected id will be empty.
+ */
+ void selectedItem(QString& id) const KDE_DEPRECATED;
+
+ /**
+ * This method returns the id of the first selected item.
+ * Usage makes usually only sense when the selection mode
+ * of the associated KMyMoneySelector is QListView::Single.
+ *
+ * @sa KMyMoneySelector::setSelectionMode()
+ *
+ * @return reference to QString containing the id. If no item
+ * is selected the QString will be empty.
+ */
+ const QString& selectedItem(void) const { return m_id; }
+
+ /**
+ * This method selects the item with the respective @a id.
+ *
+ * @param id reference to QString containing the id
+ */
+ void setSelectedItem(const QString& id);
+
+ /**
+ * This method checks if the position @a pos is part of the
+ * area of the drop down arrow.
+ */
+ bool isInArrowArea(const QPoint& pos) const;
+
+ void setSuppressObjectCreation(bool suppress) { m_canCreateObjects = !suppress; }
+
+ /**
+ * overridden for internal reasons, no API change
+ */
+ void setCurrentText(const QString& txt = QString()) { KComboBox::setCurrentText(txt); }
+
+ /**
+ * overridden to set the background color of the lineedit as well
+ */
+ void setPaletteBackgroundColor(const QColor& color);
+
+ /**
+ * Overridden to support our own completion box
+ */
+ QSize sizeHint() const;
+
+protected slots:
+ virtual void slotItemSelected(const QString& id);
+
+protected:
+ /**
+ * reimplemented to support our own popup widget
+ */
+ void mousePressEvent(QMouseEvent *e);
+
+ /**
+ * reimplemented to support our own popup widget
+ */
+ void keyPressEvent(QKeyEvent *e);
+
+ /**
+ * reimplemented to support our own popup widget
+ */
+ void paintEvent(QPaintEvent *);
+
+ /**
+ * reimplemented to support detection of new items
+ */
+ void focusOutEvent(QFocusEvent* );
+
+ /**
+ * set the widgets text area based on the item with the given @a id.
+ */
+ virtual void setCurrentTextById(const QString& id);
+
+ /**
+ * Overridden for internal reasons, no API change
+ */
+ void connectNotify(const char* signal);
+
+ /**
+ * Overridden for internal reasons, no API change
+ */
+ void disconnectNotify(const char* signal);
+
+protected:
+ /**
+ * This member keeps a pointer to the object's completion object
+ */
+ kMyMoneyCompletion* m_completion;
+
+ /**
+ * Use our own line edit to provide hint functionality
+ */
+ kMyMoneyLineEdit* m_edit;
+
+ /**
+ * The currently selected item
+ */
+ QString m_id;
+
+signals:
+ void itemSelected(const QString& id);
+ void objectCreation(bool);
+ void createItem(const QString&, QString&);
+
+private:
+ QTimer m_timer;
+ QMutex m_focusMutex;
+ /**
+ * Flag to control object creation. Use setSuppressObjectCreation()
+ * to modify it's setting. Defaults to @a false.
+ */
+ bool m_canCreateObjects;
+
+ /**
+ * Flag to check whether a focusOutEvent processing is underway or not
+ */
+ bool m_inFocusOutEvent;
+};
+
+/**
+ * @author Thomas Baumgart
+ * This class implements a combo box with the possible states for
+ * reconciliation.
+ */
+class KMyMoneyReconcileCombo : public KMyMoneyCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyReconcileCombo(QWidget *w = 0, const char *name=0);
+
+ void setState(MyMoneySplit::reconcileFlagE state);
+ MyMoneySplit::reconcileFlagE state(void) const;
+ void removeDontCare(void);
+
+protected slots:
+ void slotSetState(const QString&);
+};
+
+/**
+ * @author Thomas Baumgart
+ * This class implements a combo box with the possible states for
+ * actions (Deposit, Withdrawal, etc.).
+ *
+ * @deprecated
+ */
+class KMyMoneyComboAction : public KMyMoneyCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyComboAction(QWidget *w = 0, const char *name=0);
+
+ void setAction(int state);
+ int action(void) const;
+ void protectItem(int id, bool protect);
+
+protected slots:
+ void slotSetAction(const QString&);
+
+signals:
+ void actionSelected(int);
+};
+
+/**
+ * @author Thomas Baumgart
+ * This class implements a combo box with the possible states for
+ * actions (Deposit, Withdrawal, etc.).
+ */
+class KMyMoneyCashFlowCombo : public KMyMoneyCombo
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a combo box that contains the entries "Pay to", "From" and
+ * " " for don't care.
+ */
+ KMyMoneyCashFlowCombo(QWidget *w = 0, const char *name=0, MyMoneyAccount::accountTypeE type = MyMoneyAccount::Asset);
+
+ void setDirection(KMyMoneyRegister::CashFlowDirection dir);
+ KMyMoneyRegister::CashFlowDirection direction(void) const { return m_dir; }
+ void removeDontCare(void);
+
+protected slots:
+ void slotSetDirection(const QString& id);
+
+signals:
+ void directionSelected(KMyMoneyRegister::CashFlowDirection);
+
+private:
+ KMyMoneyRegister::CashFlowDirection m_dir;
+};
+
+/**
+ * @author Thomas Baumgart
+ * This class implements a combo box with the possible activities
+ * for investment transactions (buy, sell, dividend, etc.)
+ */
+class KMyMoneyActivityCombo : public KMyMoneyCombo
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a combo box that contains the entries "Buy", "Sell" etc.
+ */
+ KMyMoneyActivityCombo(QWidget *w = 0, const char *name=0);
+
+ void setActivity(MyMoneySplit::investTransactionTypeE activity);
+ MyMoneySplit::investTransactionTypeE activity(void) const { return m_activity; }
+
+protected slots:
+ void slotSetActivity(const QString& id);
+
+signals:
+ void activitySelected(MyMoneySplit::investTransactionTypeE);
+
+private:
+ MyMoneySplit::investTransactionTypeE m_activity;
+};
+
+/**
+ * This class implements a text based payee selector.
+ * When initially used, the widget has the functionality of a KComboBox object.
+ * Whenever a key is pressed, the set of loaded payees is searched for
+ * payees names which match the currently entered text.
+ *
+ * If any match is found a list selection box is opened and the user can use
+ * the up/down, page-up/page-down keys or the mouse to navigate in the list. If
+ * a payee is selected, the selection box is closed. Other key-strokes are
+ * directed to the parent object to manipulate the text. The visible contents of
+ * the selection box is updated with every key-stroke.
+ *
+ * This object is a replacement of the kMyMoneyPayee object and should be used
+ * for new code.
+ *
+ * @author Thomas Baumgart
+ */
+class KMyMoneyPayeeCombo : public KMyMoneyCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyPayeeCombo(QWidget* parent = 0, const char* name = 0);
+
+ void loadPayees(const QValueList<MyMoneyPayee>& list);
+};
+
+class KMyMoneyGeneralCombo : public KComboBox
+{
+ Q_OBJECT
+public:
+ KMyMoneyGeneralCombo(QWidget* parent = 0, const char* name = 0);
+ virtual ~KMyMoneyGeneralCombo();
+
+ void insertItem(const QString& txt, int id, int idx = -1);
+
+ void setItem(int id) KDE_DEPRECATED; // replace with setCurrentItem(id)
+ int item(void) const KDE_DEPRECATED; // replace with currentItem()
+
+ void setCurrentItem(int id);
+ int currentItem(void) const;
+
+ void removeItem(int id);
+
+public slots:
+ void clear(void);
+
+signals:
+ void itemSelected(int id);
+
+protected:
+ // prevent the caller to use the standard KComboBox insertItem function with a default idx
+ void insertItem(const QString&);
+
+protected slots:
+ void slotChangeItem(int idx);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+
+/**
+ * This class implements a time period selector
+ * @author Thomas Baumgart
+ */
+class KMyMoneyPeriodCombo : public KMyMoneyGeneralCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyPeriodCombo(QWidget* parent = 0, const char* name = 0);
+
+ MyMoneyTransactionFilter::dateOptionE currentItem(void) const;
+ void setCurrentItem(MyMoneyTransactionFilter::dateOptionE id);
+
+ /**
+ * This function returns the actual start date for the given
+ * period definition given by @p id. For user defined periods
+ * the returned value is QDate()
+ */
+ static QDate start(MyMoneyTransactionFilter::dateOptionE id);
+
+ /**
+ * This function returns the actual end date for the given
+ * period definition given by @p id. For user defined periods
+ * the returned value is QDate()
+ */
+ static QDate end(MyMoneyTransactionFilter::dateOptionE id);
+
+ // static void dates(QDate& start, QDate& end, MyMoneyTransactionFilter::dateOptionE id);
+};
+
+/**
+ * This class implements an occurence selector
+ * as a parent class for both OccurencePeriod and Frequency combos
+ *
+ * @author Colin Wright
+ */
+class KMyMoneyOccurenceCombo : public KMyMoneyGeneralCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyOccurenceCombo(QWidget* parent = 0, const char* name = 0);
+
+ MyMoneySchedule::occurenceE currentItem(void) const;
+};
+
+/**
+ * This class implements an occurence period selector
+ *
+ * @author Colin Wright
+ */
+class KMyMoneyOccurencePeriodCombo : public KMyMoneyOccurenceCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyOccurencePeriodCombo(QWidget* parent = 0, const char* name = 0);
+};
+
+/**
+ * This class implements a payment frequency selector
+ * @author Thomas Baumgart
+ */
+class KMyMoneyFrequencyCombo : public KMyMoneyOccurenceCombo
+{
+ Q_OBJECT
+public:
+ KMyMoneyFrequencyCombo(QWidget* parent = 0, const char* name = 0);
+
+ /**
+ * This method returns the number of events for the selected payment
+ * frequency (eg for yearly the return value is 1 and for monthly it
+ * is 12). In case, the frequency cannot be converted (once, every other year, etc.)
+ * the method returns 0.
+ */
+ int eventsPerYear(void) const;
+ /**
+ * This method returns the number of days between two events of
+ * the selected frequency. The return value for months is based
+ * on 30 days and the year is 360 days long.
+ */
+ int daysBetweenEvents(void) const;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneycompletion.cpp b/kmymoney2/widgets/kmymoneycompletion.cpp
new file mode 100644
index 0000000..f9bc7a3
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycompletion.cpp
@@ -0,0 +1,304 @@
+/***************************************************************************
+ kmymoneycompletion.cpp - description
+ -------------------
+ begin : Mon Apr 26 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneycompletion.h"
+#include <kmymoney/kmymoneyselector.h>
+#include <kmymoney/kmymoneylistviewitem.h>
+#include "./kmymoneycombo.h"
+
+const int kMyMoneyCompletion::MAX_ITEMS = 16;
+
+kMyMoneyCompletion::kMyMoneyCompletion(QWidget *parent, const char *name ) :
+ QVBox(parent, name, WType_Popup)
+{
+ m_selector = new KMyMoneySelector(this);
+ m_selector->listView()->setFocusProxy(this);
+
+ m_parent = parent;
+ setFocusProxy((parent) ? parent : (QWidget*) NoFocus);
+ setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
+ connectSignals(m_selector, m_selector->listView());
+}
+
+void kMyMoneyCompletion::connectSignals(QWidget* widget, KListView* lv)
+{
+ m_widget = widget;
+ m_lv = lv;
+ connect(lv, SIGNAL(executed(QListViewItem*,const QPoint&,int)), this, SLOT(slotItemSelected(QListViewItem*,const QPoint&,int)));
+}
+
+kMyMoneyCompletion::~kMyMoneyCompletion()
+{
+}
+
+void kMyMoneyCompletion::adjustSize(void)
+{
+ QListViewItemIterator it(m_lv, QListViewItemIterator::Visible);
+ int count = 0;
+ while(it.current()) {
+ ++count;
+ ++it;
+ }
+ adjustSize(count);
+}
+
+void kMyMoneyCompletion::adjustSize(const int count)
+{
+ int w = m_widget->sizeHint().width();
+ if(m_parent && w < m_parent->width())
+ w = m_parent->width();
+
+ QFontMetrics fm(font());
+ if(w < fm.maxWidth()*15)
+ w = fm.maxWidth()*15;
+
+ int h = 0;
+ QListViewItemIterator it(m_lv, QListViewItemIterator::Visible);
+ QListViewItem* item = it.current();
+ if(item)
+ h = item->height() * (count > MAX_ITEMS ? MAX_ITEMS : count);
+
+ // the offset of 4 in the next statement avoids the
+ // display of a scroll bar if count < MAX_ITEMS.
+ resize(w, h+4);
+
+ if(m_parent) {
+ // the code of this basic block is taken from KCompletionBox::show()
+ // and modified to our local needs
+
+ // this is probably better, once kde switches to requiring qt3.1
+ // QRect screenSize = QApplication::desktop()->availableGeometry(d->m_parent);
+ // for now use this since it's qt3.0.x-safe
+ QRect screenSize = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(m_parent));
+
+ QPoint orig = m_parent->mapToGlobal( QPoint(0, m_parent->height()) );
+ int x = orig.x();
+ int y = orig.y();
+
+ if ( x + width() > screenSize.right() )
+ x = screenSize.right() - width();
+
+ // check for the maximum height here to avoid flipping
+ // of the completion box from top to bottom of the
+ // edit widget. The offset (y) is certainly based
+ // on the actual height.
+ if(item) {
+ if ((y + item->height()*MAX_ITEMS) > screenSize.bottom() )
+ y = y - height() - m_parent->height();
+ }
+
+ move( x, y);
+ }
+}
+
+void kMyMoneyCompletion::show(bool presetSelected)
+{
+ if(!m_id.isEmpty() && presetSelected)
+ m_selector->setSelected(m_id);
+
+ adjustSize();
+
+ if(m_parent) {
+ m_parent->installEventFilter(this);
+ // make sure to install the filter for the combobox lineedit as well
+ // We have do this here because QObject::installEventFilter() is not
+ // declared virtual and we have no chance to override it in KMyMoneyCombo
+ KMyMoneyCombo* c = dynamic_cast<KMyMoneyCombo*>(m_parent);
+ if(c && c->lineEdit()) {
+ c->lineEdit()->installEventFilter(this);
+ }
+ }
+
+ QVBox::show();
+}
+
+void kMyMoneyCompletion::hide(void)
+{
+ if(m_parent) {
+ m_parent->removeEventFilter(this);
+ // make sure to uninstall the filter for the combobox lineedit as well
+ // We have do this here because QObject::installEventFilter() is not
+ // declared virtual and we have no chance to override it in KMyMoneyCombo
+ KMyMoneyCombo* c = dynamic_cast<KMyMoneyCombo*>(m_parent);
+ if(c && c->lineEdit()) {
+ c->lineEdit()->removeEventFilter(this);
+ }
+ }
+ QVBox::hide();
+}
+
+bool kMyMoneyCompletion::eventFilter(QObject* o, QEvent* e)
+{
+ int type = e->type();
+
+ KMyMoneyCombo *c = dynamic_cast<KMyMoneyCombo*>(m_parent);
+ QListViewItem* item;
+ if(o == m_parent || (c && o == c->lineEdit())) {
+ if(isVisible()) {
+ if(type == QEvent::KeyPress) {
+ QKeyEvent* ev = static_cast<QKeyEvent*> (e);
+ QKeyEvent evt(QEvent::KeyPress,
+ Key_Down, 0, ev->state(), QString::null,
+ ev->isAutoRepeat(), ev->count());
+ QKeyEvent evbt(QEvent::KeyPress,
+ Key_Up, 0, ev->state(), QString::null,
+ ev->isAutoRepeat(), ev->count());
+
+ switch(ev->key()) {
+ case Key_Tab:
+ case Key_BackTab:
+ slotItemSelected(m_lv->currentItem(), QPoint(0,0), 0);
+ break;
+
+ case Key_Down:
+ case Key_Next:
+ item = m_lv->currentItem();
+ while(item) {
+ item = item->itemBelow();
+ if(item && selector()->match(m_lastCompletion, item))
+ break;
+ }
+ if(item) {
+ m_lv->setCurrentItem(item);
+ selector()->ensureItemVisible(item);
+ }
+ ev->accept();
+ return true;
+
+ case Key_Up:
+ case Key_Prior:
+ item = m_lv->currentItem();
+ while(item) {
+ item = item->itemAbove();
+ if(item && selector()->match(m_lastCompletion, item))
+ break;
+ }
+ if(item) {
+ m_lv->setCurrentItem(item);
+ // make sure, we always see a possible (non-selectable) group item
+ if(item->itemAbove())
+ item = item->itemAbove();
+ selector()->ensureItemVisible(item);
+ }
+ ev->accept();
+ return true;
+
+ case Key_Escape:
+ hide();
+ ev->accept();
+ return true;
+
+ case Key_Enter:
+ case Key_Return:
+ slotItemSelected(m_lv->currentItem(), QPoint(0,0), 0);
+ ev->accept();
+ return true;
+
+ case Key_Home:
+ case Key_End:
+ if(ev->state() & ControlButton) {
+ item = m_lv->currentItem();
+ if(ev->key() == Key_Home) {
+ while(item && item->itemAbove()) {
+ item = item->itemAbove();
+ }
+ while(item && !selector()->match(m_lastCompletion, item)) {
+ item = item->itemBelow();
+ }
+ } else {
+ while(item && item->itemBelow()) {
+ item = item->itemBelow();
+ }
+ while(item && !selector()->match(m_lastCompletion, item)) {
+ item = item->itemAbove();
+ }
+ }
+ if(item) {
+ m_lv->setCurrentItem(item);
+ // make sure, we always see a possible (non-selectable) group item
+ if(item->itemAbove())
+ item = item->itemAbove();
+ selector()->ensureItemVisible(item);
+ }
+ ev->accept();
+ return true;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ }
+ }
+ return QVBox::eventFilter(o, e);
+}
+
+void kMyMoneyCompletion::slotMakeCompletion(const QString& txt)
+{
+ int cnt = selector()->slotMakeCompletion(txt.stripWhiteSpace());
+
+ if(m_parent && m_parent->isVisible() && !isVisible() && cnt)
+ show(false);
+ else {
+ if(cnt != 0) {
+ adjustSize();
+ } else {
+ hide();
+ }
+ }
+}
+
+void kMyMoneyCompletion::slotItemSelected(QListViewItem *item, const QPoint&, int)
+{
+ KMyMoneyListViewItem* it_v = static_cast<KMyMoneyListViewItem*>(item);
+ if(it_v && it_v->isSelectable()) {
+ QString id = it_v->id();
+ // hide the widget, so we can debug the slots that are connect
+ // to the signal we emit very soon
+ hide();
+ m_id = id;
+ emit itemSelected(id);
+ }
+}
+
+void kMyMoneyCompletion::setSelected(const QString& id)
+{
+ m_id = id;
+ m_selector->setSelected(id, true);
+}
+
+#include "kmymoneycompletion.moc"
diff --git a/kmymoney2/widgets/kmymoneycompletion.h b/kmymoney2/widgets/kmymoneycompletion.h
new file mode 100644
index 0000000..1efea63
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycompletion.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+ kmymoneycompletion.h - description
+ -------------------
+ begin : Mon Apr 26 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYCOMPLETION_H
+#define KMYMONEYCOMPLETION_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qvbox.h>
+#include <qregexp.h>
+class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KListView;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KMyMoneySelector;
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class kMyMoneyCompletion : public QVBox
+{
+ Q_OBJECT
+public:
+
+ kMyMoneyCompletion(QWidget *parent=0, const char *name=0);
+ virtual ~kMyMoneyCompletion();
+
+ /**
+ * Re-implemented for internal reasons. API is unaffected.
+ */
+ virtual void show(void) { show(true); }
+
+
+ /**
+ * Re-implemented for internal reasons. API is unaffected.
+ */
+ virtual void hide(void);
+
+ /**
+ * This method sets the current account with id @p id as
+ * the current selection.
+ *
+ * @param id id of account to be selected
+ */
+ void setSelected(const QString& id);
+
+ virtual KMyMoneySelector* selector(void) const { return m_selector; }
+
+public slots:
+ void slotMakeCompletion(const QString& txt);
+
+ void slotItemSelected(QListViewItem *item, const QPoint& pos, int col);
+
+protected:
+ /**
+ * Reimplemented from kMyMoneyAccountSelector to get events from the viewport (to hide
+ * this widget on mouse-click, Escape-presses, etc.
+ */
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ /**
+ * This method resizes the widget to show a maximum of @p count
+ * or @a MAX_ITEMS items.
+ *
+ * @param count maximum number to be shown if < MAX_ITEMS
+ */
+ void adjustSize(const int count);
+
+ /**
+ * This method counts the number of items currently visible and
+ * calls adjustSize(count).
+ */
+ void adjustSize(void);
+
+ void connectSignals(QWidget *widget, KListView* lv);
+
+ void show(bool presetSelected);
+
+signals:
+ void itemSelected(const QString& id);
+
+protected:
+ QWidget* m_parent;
+ QWidget* m_widget;
+ QString m_id;
+ KListView* m_lv;
+ KMyMoneySelector* m_selector;
+ QRegExp m_lastCompletion;
+
+ static const int MAX_ITEMS;
+
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneycurrencyselector.cpp b/kmymoney2/widgets/kmymoneycurrencyselector.cpp
new file mode 100644
index 0000000..009dc2b
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycurrencyselector.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+ kmymoneycurrencyselector.cpp - description
+ -------------------
+ begin : Tue Apr 6 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+#include <qbitmap.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kstandarddirs.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneycurrencyselector.h"
+
+KMyMoneySecuritySelector::KMyMoneySecuritySelector(QWidget *parent, const char *name ) :
+ KComboBox(parent, name),
+ m_displayItem(FullName),
+ m_displayOnly(false),
+ m_displayType(TypeAll)
+{
+ // update(QString());
+}
+
+KMyMoneySecuritySelector::KMyMoneySecuritySelector(displayTypeE type, QWidget *parent, const char *name ) :
+ KComboBox(parent,name),
+ m_displayItem(FullName),
+ m_displayOnly(false),
+ m_displayType(type)
+{
+ // update(QString());
+}
+
+KMyMoneySecuritySelector::~KMyMoneySecuritySelector()
+{
+}
+
+void KMyMoneySecuritySelector::selectDisplayItem(KMyMoneySecuritySelector::displayItemE item)
+{
+ m_displayItem = item;
+ update(QString());
+}
+
+void KMyMoneySecuritySelector::update(const QString& id)
+{
+ MyMoneySecurity curr = MyMoneyFile::instance()->baseCurrency();
+ QString baseCurrency = curr.id();
+
+ if(!id.isEmpty())
+ curr = m_currency;
+
+ this->clear();
+ m_list.clear();
+ if(m_displayType & TypeCurrencies)
+ m_list += MyMoneyFile::instance()->currencyList();
+ if(m_displayType & TypeSecurities)
+ m_list += MyMoneyFile::instance()->securityList();
+
+ // sort
+ qHeapSort(m_list);
+
+ QValueList<MyMoneySecurity>::ConstIterator it;
+
+ // construct a transparent 16x16 pixmap
+ QPixmap empty(16, 16);
+ empty.setMask(QBitmap(16, 16, true));
+
+ int itemId = 0;
+ int m_selectedItemId = 0;
+ for(it = m_list.begin(); it != m_list.end(); ++it) {
+ QString display;
+ switch(m_displayItem) {
+ default:
+ case FullName:
+ if((*it).isCurrency()) {
+ display = QString("%2 (%1)").arg((*it).id()).arg((*it).name());
+ } else
+ display = QString("%2 (%1)").arg((*it).tradingSymbol()).arg((*it).name());
+ break;
+ break;
+
+ case Symbol:
+ if((*it).isCurrency())
+ display = (*it).id();
+ else
+ display = (*it).tradingSymbol();
+ break;
+ }
+ if((*it).id() == baseCurrency) {
+ insertItem(QPixmap( locate("icon","hicolor/16x16/apps/kmymoney2.png")),
+ display, itemId);
+ } else {
+ insertItem(empty, display, itemId);
+ }
+
+ if(curr.id() == (*it).id()) {
+ m_selectedItemId = itemId;
+ m_currency = (*it);
+ }
+
+ itemId++;
+ }
+ setCurrentItem(m_selectedItemId);
+}
+
+void KMyMoneySecuritySelector::setDisplayOnly(const bool disp)
+{
+ if(disp == m_displayOnly)
+ return;
+
+ switch(disp) {
+ case true:
+ connect(this, SIGNAL(activated(int)), this, SLOT(slotSetInitialCurrency()));
+ break;
+ case false:
+ disconnect(this, SIGNAL(activated(int)), this, SLOT(slotSetInitialCurrency()));
+ break;
+ }
+ m_displayOnly = disp;
+}
+
+void KMyMoneySecuritySelector::slotSetInitialSecurity(void)
+{
+ setCurrentItem(m_selectedItemId);
+}
+
+const MyMoneySecurity& KMyMoneySecuritySelector::security(void) const
+{
+ return m_list[currentItem()];
+}
+
+void KMyMoneySecuritySelector::setSecurity(const MyMoneySecurity& currency)
+{
+ m_currency = currency;
+ update(QString("x"));
+}
+
+KMyMoneyCurrencySelector::KMyMoneyCurrencySelector(QWidget *parent, const char *name ) :
+ KMyMoneySecuritySelector(TypeCurrencies, parent, name)
+{
+}
+
+#include "kmymoneycurrencyselector.moc"
diff --git a/kmymoney2/widgets/kmymoneycurrencyselector.h b/kmymoney2/widgets/kmymoneycurrencyselector.h
new file mode 100644
index 0000000..e733eb2
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycurrencyselector.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ kmymoneycurrencyselector.h - description
+ -------------------
+ begin : Tue Apr 6 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYCURRENCYSELECTOR_H
+#define KMYMONEYCURRENCYSELECTOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KMyMoneySecuritySelector : public KComboBox
+{
+ Q_OBJECT
+public:
+ enum displayItemE {
+ Symbol = 0,
+ FullName
+ };
+
+ enum displayTypeE {
+ TypeCurrencies = 0x01,
+ TypeSecurities = 0x02,
+ TypeAll = 0x03
+ };
+
+ KMyMoneySecuritySelector(QWidget *parent=0, const char *name=0);
+ KMyMoneySecuritySelector(displayTypeE type = TypeAll, QWidget *parent=0, const char *name=0);
+ virtual ~KMyMoneySecuritySelector();
+
+ const MyMoneySecurity& security(void) const;
+ void setSecurity(const MyMoneySecurity& currency);
+ void selectDisplayItem(KMyMoneySecuritySelector::displayItemE item);
+ void setDisplayOnly(const bool disp);
+
+ void update(const QString& id);
+
+public slots:
+ void slotSetInitialSecurity(void);
+
+private:
+ MyMoneySecurity m_currency;
+ displayItemE m_displayItem;
+ int m_selectedItemId;
+ bool m_displayOnly;
+ displayTypeE m_displayType;
+ QValueList<MyMoneySecurity> m_list;
+};
+
+class KMyMoneyCurrencySelector : public KMyMoneySecuritySelector
+{
+public:
+ KMyMoneyCurrencySelector(QWidget *parent=0, const char *name=0);
+ virtual ~KMyMoneyCurrencySelector() {}
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneydateinput.cpp b/kmymoney2/widgets/kmymoneydateinput.cpp
new file mode 100644
index 0000000..e1b4be8
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneydateinput.cpp
@@ -0,0 +1,348 @@
+/***************************************************************************
+ kmymoneydateinput.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpainter.h>
+#include <qdrawutil.h>
+#include <qpoint.h>
+#include <qvalidator.h>
+#include <qtimer.h>
+#include <qstyle.h>
+#include <qlayout.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include "kdecompat.h"
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+#include <kshortcut.h>
+#include <kpassivepopup.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneydateinput.h"
+
+namespace {
+ const int DATE_POPUP_TIMEOUT = 1500;
+}
+
+bool KMyMoneyDateEdit::event(QEvent* e)
+{
+ // make sure that we keep the current date setting of a kMyMoneyDateInput object
+ // across the QDateEdit::event(FocusOutEvent)
+ bool rc;
+
+ kMyMoneyDateInput* p = dynamic_cast<kMyMoneyDateInput*>(parentWidget());
+ if(e->type() == QEvent::FocusOut && p) {
+ QDate d = p->date();
+ rc = QDateEdit::event(e);
+ if(d.isValid())
+ d = p->date();
+ p->loadDate(d);
+ } else {
+ rc = QDateEdit::event(e);
+ }
+ return rc;
+}
+
+kMyMoneyDateInput::kMyMoneyDateInput(QWidget *parent, const char *name, Qt::AlignmentFlags flags)
+ : QHBox(parent,name)
+{
+ m_qtalignment = flags;
+ m_date = QDate::currentDate();
+
+ dateEdit = new KMyMoneyDateEdit(m_date, this, "dateEdit");
+ setFocusProxy(dateEdit);
+ focusWidget()->installEventFilter(this); // To get dateEdit's FocusIn/Out and some KeyPress events
+ dateEdit->installEventFilter(this); // To get dateEdit's FocusIn/Out and some KeyPress events
+
+ m_datePopup = new KPassivePopup(dateEdit, "datePopup");
+ m_datePopup->setTimeout(DATE_POPUP_TIMEOUT);
+ m_datePopup->setView(new QLabel(KGlobal::locale()->formatDate(m_date), m_datePopup, "datePopupLabel"));
+
+ m_dateFrame = new QVBox(this, 0, WType_Popup);
+ m_dateFrame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
+ m_dateFrame->setLineWidth(3);
+ m_dateFrame->hide();
+
+ QString dateFormat = KGlobal::locale()->dateFormatShort().lower();
+ QString order, separator;
+ for(unsigned i = 0; i < dateFormat.length(); ++i) {
+ // DD.MM.YYYY is %d.%m.%y
+ // dD.mM.YYYY is %e.%n.%y
+ // SHORTWEEKDAY, dD SHORTMONTH YYYY is %a, %e %b %Y
+ if(dateFormat[i] == 'y' || dateFormat[i] == 'm' || dateFormat[i] == 'n' || dateFormat[i] == 'd' || dateFormat[i] == 'e') {
+ if(dateFormat[i] == 'n')
+ dateFormat[i] = 'm';
+ if(dateFormat[i] == 'e')
+ dateFormat[i] = 'd';
+ order += dateFormat[i];
+ } else if(dateFormat[i] != '%' && separator.isEmpty())
+ separator = dateFormat[i];
+ if(order.length() == 3)
+ break;
+ }
+
+ // see if we find a known format. If it's unknown, then we use YMD (international)
+ // set m_focusDatePart to the day position (0-2)
+ if(order == "mdy") {
+ dateEdit->setOrder(QDateEdit::MDY);
+ m_focusDatePart = 1;
+ } else if(order == "dmy") {
+ dateEdit->setOrder(QDateEdit::DMY);
+ m_focusDatePart = 0;
+ } else if(order == "ydm") {
+ dateEdit->setOrder(QDateEdit::YDM);
+ m_focusDatePart = 1;
+ } else {
+ dateEdit->setOrder(QDateEdit::YMD);
+ m_focusDatePart = 2;
+ separator = '-';
+ }
+ dateEdit->setSeparator(separator);
+
+ m_datePicker = new KDatePicker(m_dateFrame, m_date);
+#if KDE_IS_VERSION(3,1,0)
+ // Let the date picker have a close button (Added in 3.1)
+ m_datePicker->setCloseButton(true);
+#endif
+
+ // the next line is a try to add an icon to the button
+ m_dateButton = new KPushButton(QIconSet(QPixmap(KGlobal::iconLoader()->iconPath("date", -KIcon::SizeSmall))), QString(""), this);
+ m_dateButton->setMinimumWidth(30);
+
+ connect(m_dateButton,SIGNAL(clicked()),SLOT(toggleDatePicker()));
+ connect(dateEdit, SIGNAL(valueChanged(const QDate&)), this, SLOT(slotDateChosenRef(const QDate&)));
+ connect(m_datePicker, SIGNAL(dateSelected(QDate)), this, SLOT(slotDateChosen(QDate)));
+ connect(m_datePicker, SIGNAL(dateEntered(QDate)), this, SLOT(slotDateChosen(QDate)));
+ connect(m_datePicker, SIGNAL(dateSelected(QDate)), m_dateFrame, SLOT(hide()));
+}
+
+void kMyMoneyDateInput::markAsBadDate(bool bad, const QColor& color)
+{
+ if(dateEdit->focusProxy()) {
+ dateEdit->focusProxy()->setPaletteForegroundColor(paletteForegroundColor());
+ if(bad)
+ dateEdit->focusProxy()->setPaletteForegroundColor(color);
+ }
+}
+
+void kMyMoneyDateInput::show(void)
+{
+ // don't forget the standard behaviour ;-)
+ QHBox::show();
+
+ // If the widget is shown, the size must be fixed a little later
+ // to be appropriate. I saw this in some other places and the only
+ // way to solve this problem is to postpone the setup of the size
+ // to the time when the widget is on the screen.
+ QTimer::singleShot(50, this, SLOT(fixSize()));
+}
+
+void kMyMoneyDateInput::fixSize(void)
+{
+ // According to a hint in the documentation of KDatePicker::sizeHint()
+ // 28 pixels should be added in each direction to obtain a better
+ // display of the month button. I decided, (22,14) is good
+ // enough and save some space on the screen (ipwizard)
+ m_dateFrame->setFixedSize(m_datePicker->sizeHint() + QSize(22, 14));
+
+ dateEdit->setMinimumWidth(dateEdit->minimumSizeHint().width() + 6);
+}
+
+kMyMoneyDateInput::~kMyMoneyDateInput()
+{
+ delete m_dateFrame;
+ delete m_datePopup;
+}
+
+void kMyMoneyDateInput::toggleDatePicker()
+{
+ int w = m_dateFrame->width();
+ int h = m_dateFrame->height();
+
+ if(m_dateFrame->isVisible())
+ {
+ m_dateFrame->hide();
+ }
+ else
+ {
+ QPoint tmpPoint = mapToGlobal(m_dateButton->geometry().bottomRight());
+
+ // usually, the datepicker widget is shown underneath the dateEdit widget
+ // if it does not fit on the screen, we show it above this widget
+
+ if(tmpPoint.y() + h > QApplication::desktop()->height()) {
+ tmpPoint.setY(tmpPoint.y() - h - m_dateButton->height());
+ }
+
+ if((m_qtalignment == Qt::AlignRight && tmpPoint.x()+w <= QApplication::desktop()->width())
+ || (tmpPoint.x()-w < 0) )
+ {
+ m_dateFrame->setGeometry(tmpPoint.x()-width(), tmpPoint.y(), w, h);
+ }
+ else
+ {
+ tmpPoint.setX(tmpPoint.x() - w);
+ m_dateFrame->setGeometry(tmpPoint.x(), tmpPoint.y(), w, h);
+ }
+
+ if(m_date.isValid())
+ {
+ m_datePicker->setDate(m_date);
+ }
+ else
+ {
+ m_datePicker->setDate(QDate::currentDate());
+ }
+ m_dateFrame->show();
+ }
+}
+
+
+void kMyMoneyDateInput::resizeEvent(QResizeEvent* ev)
+{
+ m_dateButton->setMaximumHeight(ev->size().height());
+ m_dateButton->setMaximumWidth(ev->size().height());
+ dateEdit->setMaximumHeight(ev->size().height());
+
+ // qDebug("Received resize-event %d,%d", ev->size().width(), ev->size().height());
+}
+
+
+/** Overriding QWidget::keyPressEvent
+ *
+ * increments/decrements the date upon +/- or Up/Down key input
+ * sets the date to current date when the 'T' key is pressed
+ */
+void kMyMoneyDateInput::keyPressEvent(QKeyEvent * k)
+{
+ KShortcut today(i18n("Enter todays date into date input widget", "T"));
+
+ switch(k->key()) {
+ case Key_Equal:
+ case Key_Plus:
+ slotDateChosen(m_date.addDays(1));
+ break;
+
+ case Key_Minus:
+ slotDateChosen(m_date.addDays(-1));
+ break;
+
+ default:
+ if(today.contains(KKey(k)) || k->key() == Key_T) {
+ slotDateChosen(QDate::currentDate());
+ }
+ break;
+ }
+}
+
+/**
+ * This function receives all events that are sent to focusWidget().
+ * Some KeyPress events are intercepted and passed to keyPressEvent.
+ * Otherwise they would be consumed by QDateEdit.
+ */
+bool kMyMoneyDateInput::eventFilter(QObject *, QEvent *e)
+{
+ if (e->type() == QEvent::FocusIn) {
+ m_datePopup->show();
+ // The cast to the base class is needed since setFocusSection
+ // is protected in QDateEdit. This causes some logic in
+ // QDateEdit::setFocusSection not to be executed but this does
+ // not hurt here, because the widget just receives focus.
+ static_cast<QDateTimeEditBase *>(dateEdit)->setFocusSection(m_focusDatePart);
+ }
+ else if (e->type() == QEvent::FocusOut)
+ m_datePopup->hide();
+ else if (e->type() == QEvent::KeyPress) {
+ if (QKeyEvent *k = dynamic_cast<QKeyEvent*>(e)) {
+ if (k->key() == Key_Minus) {
+ keyPressEvent(k);
+ return true;
+ }
+ }
+ }
+
+ return false; // Don't filter the event
+}
+
+void kMyMoneyDateInput::slotDateChosenRef(const QDate& date)
+{
+ if(date.isValid()) {
+ emit dateChanged(date);
+ m_date = date;
+
+ QLabel *lbl = static_cast<QLabel*>(m_datePopup->view());
+ lbl->setText(KGlobal::locale()->formatDate(date));
+ lbl->adjustSize();
+ if(m_datePopup->isVisible() || hasFocus())
+ m_datePopup->show(); // Repaint
+ }
+}
+
+void kMyMoneyDateInput::slotDateChosen(QDate date)
+{
+ if(date.isValid()) {
+ // the next line implies a call to slotDateChosenRef() above
+ dateEdit->setDate(date);
+ }
+}
+
+QDate kMyMoneyDateInput::date(void) const
+{
+ return dateEdit->date();
+}
+
+void kMyMoneyDateInput::setDate(QDate date)
+{
+ slotDateChosen(date);
+}
+
+void kMyMoneyDateInput::loadDate(const QDate& date)
+{
+ m_date = m_prevDate = date;
+
+ blockSignals(true);
+ dateEdit->setDate(date);
+ m_date = date;
+ blockSignals(false);
+}
+
+void kMyMoneyDateInput::resetDate(void)
+{
+ setDate(m_prevDate);
+}
+
+QWidget* kMyMoneyDateInput::focusWidget(void) const
+{
+ QWidget* w = dateEdit;
+ while(w->focusProxy())
+ w = w->focusProxy();
+ return w;
+}
+
+#include "kmymoneydateinput.moc"
diff --git a/kmymoney2/widgets/kmymoneydateinput.h b/kmymoney2/widgets/kmymoneydateinput.h
new file mode 100644
index 0000000..4561d63
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneydateinput.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ kmymoneydateinput.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYDATEINPUT_H
+#define KMYMONEYDATEINPUT_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qlineedit.h>
+#include <qdatetime.h>
+#include <qdatetimeedit.h>
+#include <qvbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kdatepicker.h>
+class KPushButton;
+class KPassivePopup;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+// Ideas neatly taken from korganizer
+// Respective authors are credited.
+// Some ideas/code have been borrowed from Calendar-0.13 (phoenix.bmedesign.com/~qt)
+
+/**
+ * Provided to be able to catch the focusOut events before the contents gets changed
+ */
+class KMyMoneyDateEdit : public QDateEdit
+{
+ Q_OBJECT
+public:
+ KMyMoneyDateEdit(const QDate& date, QWidget *parent=0, const char *name=0) : QDateEdit(date, parent, name) {}
+
+protected:
+ /** reimplemented for internal reasons */
+ bool event(QEvent* e);
+};
+
+/**
+ * This class provides the general widget used for date selection
+ * throughout the KMyMoney project. It provides an QDateEdit widget
+ * which is based on an edit field with spin boxes and adds a QPushButton
+ * to open a KDatePicker.
+ */
+class kMyMoneyDateInput : public QHBox
+{
+ Q_OBJECT
+
+public:
+ kMyMoneyDateInput(QWidget *parent=0, const char *name=0, Qt::AlignmentFlags flags=Qt::AlignLeft);
+ ~kMyMoneyDateInput();
+
+ // Replace calls to this with the new date() method
+ // QDate getQDate(void) KDE_DEPRECATED;
+
+ QDate date(void) const;
+ void setDate(QDate date);
+ void loadDate(const QDate& date);
+ void resetDate(void);
+ QWidget* focusWidget(void) const;
+ virtual void setRange(const QDate & min, const QDate & max) { dateEdit->setRange(min, max); }
+ void markAsBadDate(bool bad = false, const QColor& = QColor());
+
+public slots:
+ virtual void show(void);
+
+signals:
+ void dateChanged(const QDate& date);
+
+protected:
+ /**
+ * - increments/decrements the date upon +/- key input
+ * - increments/decrements the date upon Up/Down key input
+ * - sets the date to current date when the 'T' key is pressed.
+ * The actual key for this to happen might be overridden through
+ * an i18n package. The 'T'-key is always possible.
+ */
+ void keyPressEvent(QKeyEvent * k);
+ void resizeEvent(QResizeEvent*);
+
+ /** To intercept events sent to focusWidget() */
+ bool eventFilter(QObject *o, QEvent *e);
+
+protected slots:
+ void slotDateChosen(QDate date);
+ void toggleDatePicker();
+
+private slots:
+ void slotDateChosenRef(const QDate& date);
+ void fixSize(void);
+
+private:
+ QDateEdit *dateEdit;
+ KDatePicker *m_datePicker;
+ QDate m_date; // The date !
+ QDate m_prevDate;
+ Qt::AlignmentFlags m_qtalignment;
+ QVBox *m_dateFrame;
+ KPushButton *m_dateButton;
+ KPassivePopup *m_datePopup;
+ int m_focusDatePart;
+};
+
+#endif
+
diff --git a/kmymoney2/widgets/kmymoneydatetbl.cpp b/kmymoney2/widgets/kmymoneydatetbl.cpp
new file mode 100644
index 0000000..e48e01e
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneydatetbl.cpp
@@ -0,0 +1,698 @@
+/***************************************************************************
+ kmymoneydatetbl.cpp - description
+ -------------------
+ begin : Thu Jul 3 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+ /****************************************************************************
+ Contains code from the KDateTable class ala kdelibs-3.1.2. Original license:
+
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
+ (C) 1998-2001 Mirko Boehm (mirko@kde.org)
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qglobal.h>
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qpen.h>
+#include <qpainter.h>
+#include <qdialog.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include "kdecompat.h"
+#include <kdatetbl.h> // Use the classes available for maximum re-use
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <knotifyclient.h>
+#if KDE_IS_VERSION(3,2,0)
+#include <kcalendarsystem.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kmymoneydatetbl.h"
+
+kMyMoneyDateTbl::kMyMoneyDateTbl(QWidget *parent, QDate date_, const char* name, WFlags f)
+ : QGridView(parent, name, f)
+{
+ // call this first to make sure that member variables are initialized
+ setType(MONTHLY);
+
+ setFontSize(10);
+
+ if(!date_.isValid())
+ {
+ kdDebug() << "kMyMoneyDateTbl ctor: WARNING: Given date is invalid, using current date." << endl;
+ date_=QDate::currentDate();
+ }
+ setFocusPolicy( QWidget::StrongFocus );
+
+
+ viewport()->setEraseColor(KGlobalSettings::baseColor());
+
+ setDate(date_); // this initializes firstday, numdays, numDaysPrevMonth
+
+ // So we can emit hoverDate
+// QApplication::setGlobalMouseTracking(true);
+ viewport()->setMouseTracking(true);
+}
+
+void
+kMyMoneyDateTbl::paintCell(QPainter *painter, int row, int col)
+{
+ QRect rect;
+ QString text;
+ QPen pen;
+ int w=cellWidth();
+ int h=cellHeight();
+ QBrush brushBlue(KGlobalSettings::activeTitleColor());
+ QBrush brushLightblue(KGlobalSettings::baseColor());
+ QFont font=KGlobalSettings::generalFont();
+
+ // -----
+ font.setPointSize(fontsize);
+
+#if KDE_VERSION < 310
+ int firstWeekDay = KGlobal::locale()->weekStartsMonday() ? 1 : 0;
+#else
+ int firstWeekDay = KGlobal::locale()->weekStartDay();
+#endif
+
+ if (row==0)
+ { // we are drawing the headline
+ if (m_type == MONTHLY)
+ {
+ font.setBold(true);
+ painter->setFont(font);
+ bool normalday = true;
+ QString daystr;
+ if ( col+firstWeekDay < 8 )
+ daystr = WEEK_DAY_NAME(col+firstWeekDay, true);
+ else
+ daystr = WEEK_DAY_NAME(col+firstWeekDay-7, true);
+
+ if ( daystr==i18n("Sunday", "Sun") || daystr==i18n("Saturday", "Sat") )
+ normalday=false;
+
+ if (!normalday)
+ {
+ painter->setPen(KGlobalSettings::baseColor());
+ painter->setBrush(brushLightblue);
+ painter->drawRect(0, 0, w, h);
+ painter->setPen(KGlobalSettings::activeTitleColor());
+ } else {
+ painter->setPen(KGlobalSettings::activeTitleColor());
+ painter->setBrush(brushBlue);
+ painter->drawRect(0, 0, w, h);
+ painter->setPen(KGlobalSettings::activeTextColor());
+ }
+ painter->drawText(0, 0, w, h-1, AlignCenter,
+ daystr, -1, &rect);
+ painter->setPen(KGlobalSettings::textColor());
+ painter->moveTo(0, h-1);
+ painter->lineTo(w-1, h-1);
+
+ if(rect.width()>maxCell.width())
+ maxCell.setWidth(rect.width());
+
+ if(rect.height()>maxCell.height())
+ maxCell.setHeight(rect.height());
+ }
+ else if (m_type == WEEKLY)
+ {
+ painter->setPen(KGlobalSettings::activeTitleColor());
+ painter->setBrush(brushBlue);
+ painter->drawRect(0, 0, w, h);
+ painter->setPen(KGlobalSettings::activeTextColor());
+
+ int year=date.year();
+ QString headerText;
+#if QT_VERSION > 0x030005
+ // FIXME: Shouldn't that be i18n()'ed as well
+ QString weekStr = QString::number(date.weekNumber(&year));
+ QString yearStr = QString::number(year);
+ headerText = i18n("Week %1 for year %2.")
+ .arg(weekStr)
+ .arg(yearStr);
+#else
+ // FIXME: include code to display the same as for KDE >= 3.0.5
+ QString weekStr = QString::number(weekNumber(date, &year));
+ QString yearStr = QString::number(year);
+ headerText = i18n("Week %1 for year %2.")
+ .arg(weekStr)
+ .arg(yearStr);
+#endif
+
+ painter->drawText(0, 0, w, h-1, AlignCenter, headerText, -1, &rect);
+
+ maxCell.setWidth(width());
+
+ if(rect.height()>maxCell.height())
+ maxCell.setHeight(rect.height());
+ }
+ else if (m_type == QUARTERLY)
+ {
+ int athird = width()/3;
+
+ painter->setPen(KGlobalSettings::activeTitleColor());
+ painter->setBrush(brushBlue);
+ painter->setPen(/*KGlobalSettings::activeTextColor()*/black);
+
+ if (col == 0)
+ {
+ painter->drawRect(0, 0, athird, h);
+ painter->drawText(0, 0, athird, h-1, AlignCenter, "Month 1", -1, &rect);
+
+ painter->drawRect(athird, 0, athird, h);
+ painter->drawText(athird, 0, athird, h-1, AlignCenter, "Month 2", -1, &rect);
+
+ painter->drawRect(athird*2, 0, athird, h);
+ painter->drawText(athird*2, 0, athird, h-1, AlignCenter, "Month 3", -1, &rect);
+ }
+ }
+ }
+ else
+ {
+ int pos;
+
+ QDate drawDate(date);
+
+ if (m_type == MONTHLY)
+ {
+ pos=7*(row-1)+col;
+ if ( firstWeekDay < 4 )
+ pos += firstWeekDay;
+ else
+ pos += firstWeekDay - 7;
+
+ if (pos<firstday || (firstday+numdays<=pos))
+ { // we are either
+ // painting a day of the previous month or
+ // painting a day of the following month
+
+ if (pos<firstday)
+ { // previous month
+ drawDate = drawDate.addMonths(-1);
+ text.setNum(numDaysPrevMonth+pos-firstday+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ } else { // following month
+ drawDate = drawDate.addMonths(1);
+ text.setNum(pos-firstday-numdays+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ }
+ } else { // paint a day of the current month
+ text.setNum(pos-firstday+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ }
+ }
+ else if (m_type == WEEKLY)
+ {
+ // TODO: Handle other start weekdays than Monday
+ text = QDate::shortDayName(row);
+ text += " ";
+
+ int dayOfWeek = date.dayOfWeek();
+ int diff;
+
+ if (row < dayOfWeek)
+ {
+ diff = -(dayOfWeek - row);
+ }
+ else
+ {
+ diff = row - dayOfWeek;
+ }
+
+ drawDate = date.addDays(diff);
+ }
+ else if (m_type == QUARTERLY)
+ {
+ }
+
+ drawCellContents(painter, row, col, drawDate);
+ }
+}
+
+void
+kMyMoneyDateTbl::keyPressEvent( QKeyEvent *e )
+{
+ if ( e->key() == Qt::Key_Prior ) {
+ setDate(date.addMonths(-1));
+ return;
+ }
+ if ( e->key() == Qt::Key_Next ) {
+ setDate(date.addMonths(1));
+ return;
+ }
+
+ if ( e->key() == Qt::Key_Up ) {
+ if ( date.day() > 7 ) {
+ setDate(date.addDays(-7));
+ return;
+ }
+ }
+ if ( e->key() == Qt::Key_Down ) {
+ if ( date.day() <= date.daysInMonth()-7 ) {
+ setDate(date.addDays(7));
+ return;
+ }
+ }
+ if ( e->key() == Qt::Key_Left ) {
+ if ( date.day() > 1 ) {
+ setDate(date.addDays(-1));
+ return;
+ }
+ }
+ if ( e->key() == Qt::Key_Right ) {
+ if ( date.day() < date.daysInMonth() ) {
+ setDate(date.addDays(1));
+ return;
+ }
+ }
+
+ if ( e->key() == Qt::Key_Minus ) {
+ setDate(date.addDays(-1));
+ return;
+ }
+ if ( e->key() == Qt::Key_Plus ) {
+ setDate(date.addDays(1));
+ return;
+ }
+ if ( e->key() == Qt::Key_N ) {
+ setDate(QDate::currentDate());
+ return;
+ }
+
+ KNotifyClient::beep();
+}
+
+void
+kMyMoneyDateTbl::viewportResizeEvent(QResizeEvent * e)
+{
+ if (e)
+ QGridView::viewportResizeEvent(e);
+
+ setCellWidth(viewport()->width()/m_colCount);
+ setCellHeight(viewport()->height()/m_rowCount);
+}
+
+void
+kMyMoneyDateTbl::setFontSize(int size)
+{
+ int count;
+ QFontMetrics metrics(fontMetrics());
+ QRect rect;
+
+ // ----- store rectangles:
+ fontsize=size;
+
+ // ----- find largest day name:
+ maxCell.setWidth(0);
+ maxCell.setHeight(0);
+
+ for(count=0; count<m_colCount; ++count)
+ {
+ rect=metrics.boundingRect(WEEK_DAY_NAME(count+1, true));
+ maxCell.setWidth(QMAX(maxCell.width(), rect.width()));
+ maxCell.setHeight(QMAX(maxCell.height(), rect.height()));
+ }
+
+ if (m_type == WEEKLY)
+ {
+ // Re-size to width
+ maxCell.setWidth(width());
+ }
+
+ // ----- compare with a real wide number and add some space:
+ rect=metrics.boundingRect(QString::fromLatin1("88"));
+ maxCell.setWidth(QMAX(maxCell.width()+2, rect.width()));
+ maxCell.setHeight(QMAX(maxCell.height()+4, rect.height()));
+}
+
+void
+kMyMoneyDateTbl::wheelEvent ( QWheelEvent * e )
+{
+ setDate(date.addMonths( -(int)(e->delta()/120)) );
+ e->accept();
+}
+
+void
+kMyMoneyDateTbl::contentsMouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->type()!=QEvent::MouseButtonRelease)
+ { // the KDatePicker only reacts on mouse press events:
+ return;
+ }
+
+ if(!isEnabled())
+ {
+ KNotifyClient::beep();
+ return;
+ }
+
+#if KDE_VERSION < 310
+ int dayoff = KGlobal::locale()->weekStartsMonday() ? 1 : 0;
+#else
+ int dayoff = KGlobal::locale()->weekStartDay();
+#endif
+
+ // -----
+ int row, col, pos, temp;
+ QPoint mouseCoord;
+
+ // -----
+ mouseCoord = e->pos();
+ row=rowAt(mouseCoord.y());
+ col=columnAt(mouseCoord.x());
+ if(row<1 || col<0)
+ { // the user clicked on the frame of the table
+ return;
+ }
+
+ if (m_type == MONTHLY)
+ {
+ // Rows and columns are zero indexed. The (row - 1) below is to avoid counting
+ // the row with the days of the week in the calculation. We however want pos
+ // to be "1 indexed", hence the "+ 1" at the end of the sum.
+ pos = (7 * (row - 1)) + col + 1;
+
+ // This gets pretty nasty below. firstday is a locale independant index for
+ // the first day of the week. dayoff is the day of the week that the week
+ // starts with for the selected locale. Monday = 1 .. Sunday = 7
+ // Strangely, in some cases dayoff is in fact set to 8, hence all of the
+ // "dayoff % 7" sections below.
+
+ if (pos + dayoff % 7 <= firstday)
+ { // this day is in the previous month
+ setDate(date.addDays(-1 * (date.day() + firstday - pos - dayoff % 7)));
+ return;
+ }
+
+ if (firstday + numdays < pos + dayoff % 7)
+ { // this date is in the next month
+ setDate(date.addDays(pos - firstday - date.day() + dayoff % 7));
+ return;
+ }
+ temp = firstday + date.day() - dayoff % 7 - 1;
+
+ setDate(QDate(date.year(), date.month(), pos - firstday + dayoff % 7));
+
+ updateCell(temp/7+1, temp%7); // Update the previously selected cell
+ }
+ else if (m_type == WEEKLY)
+ {
+ int dayOfWeek = date.dayOfWeek();
+ int diff;
+
+ if (row < dayOfWeek)
+ {
+ diff = -(dayOfWeek - row);
+ }
+ else
+ {
+ diff = row - dayOfWeek;
+ }
+
+ setDate(date.addDays(diff));
+ updateCell(dayOfWeek, 0);
+ }
+ else if (m_type == QUARTERLY)
+ {
+ }
+
+ updateCell(row, col); // Update the selected cell
+
+ emit(tableClicked());
+}
+
+bool
+kMyMoneyDateTbl::setDate(const QDate& date_)
+{
+ bool changed=false;
+ QDate temp;
+ // -----
+ if(!date_.isValid())
+ {
+ kdDebug() << "kMyMoneyDateTbl::setDate: refusing to set invalid date." << endl;
+ return false;
+ }
+
+ if(date!=date_)
+ {
+ date=date_;
+ changed=true;
+ }
+
+ temp.setYMD(date.year(), date.month(), 1);
+ firstday=temp.dayOfWeek();
+
+ if (firstday==1)
+ firstday=8;
+
+ numdays=date.daysInMonth();
+
+ if (date.month()==1)
+ { // set to december of previous year
+ temp.setYMD(date.year()-1, 12, 1);
+ } else { // set to previous month
+ temp.setYMD(date.year(), date.month()-1, 1);
+ }
+
+ numDaysPrevMonth=temp.daysInMonth();
+
+ if (changed)
+ {
+ repaintContents(false);
+ }
+
+ emit(dateChanged(date));
+ return true;
+}
+
+const QDate&
+kMyMoneyDateTbl::getDate() const
+{
+ return date;
+}
+
+// what are those repaintContents() good for? (pfeiffer)
+void kMyMoneyDateTbl::focusInEvent( QFocusEvent *e )
+{
+// repaintContents(false);
+ QGridView::focusInEvent( e );
+}
+
+void kMyMoneyDateTbl::focusOutEvent( QFocusEvent *e )
+{
+// repaintContents(false);
+ QGridView::focusOutEvent( e );
+}
+
+QSize
+kMyMoneyDateTbl::sizeHint() const
+{
+ if (maxCell.height()>0 && maxCell.width()>0)
+ {
+ return QSize(maxCell.width()*numCols()+2*frameWidth(),
+ (maxCell.height()+2)*numRows()+2*frameWidth());
+ } else {
+ kdDebug() << "kMyMoneyDateTbl::sizeHint: obscure failure - " << endl;
+ return QSize(-1, -1);
+ }
+}
+
+
+void kMyMoneyDateTbl::setType(calendarType type)
+{
+ if (type == WEEKLY)
+ {
+ m_rowCount = 8;
+ m_colCount = 1;
+ m_type = WEEKLY;
+ }
+ else if (type == QUARTERLY)
+ {
+ m_rowCount = 7;
+ m_colCount = 21;
+ m_type = QUARTERLY;
+ }
+ else // default to monthly
+ {
+ m_rowCount = m_colCount = 7;
+ m_type = MONTHLY;
+ }
+
+ setNumRows(m_rowCount);
+ setNumCols(m_colCount);
+ setHScrollBarMode(AlwaysOff);
+ setVScrollBarMode(AlwaysOff);
+
+ viewportResizeEvent(NULL);
+}
+
+void kMyMoneyDateTbl::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ int row, col, pos;
+ QPoint mouseCoord;
+
+ mouseCoord = e->pos();
+ row = rowAt(mouseCoord.y());
+ col = columnAt(mouseCoord.x());
+ if (row<1 || col<0)
+ {
+ return;
+ }
+
+#if KDE_VERSION < 310
+ int firstWeekDay = KGlobal::locale()->weekStartsMonday() ? 1 : 0;
+#else
+ int firstWeekDay = KGlobal::locale()->weekStartDay();
+#endif
+
+ QDate drawDate(date);
+ QString text;
+
+ if (m_type == MONTHLY)
+ {
+ pos=7*(row-1)+col;
+ if ( firstWeekDay < 4 )
+ pos += firstWeekDay;
+ else
+ pos += firstWeekDay - 7;
+
+ if (pos<firstday || (firstday+numdays<=pos))
+ { // we are either
+ // painting a day of the previous month or
+ // painting a day of the following month
+
+ if (pos<firstday)
+ { // previous month
+ drawDate = drawDate.addMonths(-1);
+ text.setNum(numDaysPrevMonth+pos-firstday+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ } else { // following month
+ drawDate = drawDate.addMonths(1);
+ text.setNum(pos-firstday-numdays+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ }
+ } else { // paint a day of the current month
+ text.setNum(pos-firstday+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ }
+ }
+ else if (m_type == WEEKLY)
+ {
+ // TODO: Handle other start weekdays than Monday
+ text = QDate::shortDayName(row);
+ text += " ";
+
+ int dayOfWeek = date.dayOfWeek();
+ int diff;
+
+ if (row < dayOfWeek)
+ {
+ diff = -(dayOfWeek - row);
+ }
+ else
+ {
+ diff = row - dayOfWeek;
+ }
+
+ drawDate = date.addDays(diff);
+ }
+ else if (m_type == QUARTERLY)
+ {
+ }
+
+ if (m_drawDateOrig != drawDate)
+ {
+ m_drawDateOrig = drawDate;
+ emit hoverDate(drawDate);
+ }
+
+ QGridView::contentsMouseMoveEvent(e);
+}
+
+#if QT_VERSION <= 0x030005
+// The following code is borrowed from QT 3.2 QDate::weekNumber()
+// and slightly modified
+int kMyMoneyDateTbl::weekNumber(const QDate& date, int *yearNumber) const
+{
+ if ( !date.isValid() )
+ return 0;
+
+ int dow = date.dayOfWeek();
+ int doy = date.dayOfYear();
+ int currYear = date.year();
+ int jan1WeekDay = QDate( currYear, 1, 1 ).dayOfWeek();
+ int yearNum;
+ int weekNum;
+
+ if ( doy <= (8 - jan1WeekDay) && jan1WeekDay > 4 ) {
+ yearNum = currYear - 1;
+ weekNum = 52;
+ if ( jan1WeekDay == 5 ||
+ (jan1WeekDay == 6 && QDate::leapYear(yearNum)) )
+ weekNum++;
+ } else {
+ int totalDays = 365;
+ if ( QDate::leapYear(currYear) )
+ totalDays++;
+
+ if ( (totalDays - doy < 4 - dow)
+ || (jan1WeekDay == 7 && totalDays - doy < 3) ) {
+ yearNum = currYear + 1;
+ weekNum = 1;
+ } else {
+ int j = doy + ( 7 - dow ) + ( jan1WeekDay - 1 );
+ yearNum = currYear;
+ weekNum = j / 7;
+ if ( jan1WeekDay > 4 )
+ weekNum--;
+ }
+ }
+ if ( yearNumber )
+ *yearNumber = yearNum;
+ return weekNum;
+
+}
+#endif
+
+#include "kmymoneydatetbl.moc"
diff --git a/kmymoney2/widgets/kmymoneydatetbl.h b/kmymoney2/widgets/kmymoneydatetbl.h
new file mode 100644
index 0000000..7ff6610
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneydatetbl.h
@@ -0,0 +1,189 @@
+/***************************************************************************
+ kmymoneydatetbl.h - description
+ -------------------
+ begin : Thu Jul 3 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/****************************************************************************
+ Contains code from the KDateTable class ala kdelibs-3.1.2. Original license:
+
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
+ (C) 1998-2001 Mirko Boehm (mirko@kde.org)
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KMYMONEYDATETBL_H
+#define KMYMONEYDATETBL_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qgridview.h>
+#include <qdatetime.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+
+/**
+ * @author Michael Edwardes
+ */
+class kMyMoneyDateTbl : public QGridView {
+ Q_OBJECT
+public:
+ enum calendarType { WEEKLY,
+ MONTHLY,
+ QUARTERLY };
+
+public:
+ /**
+ * The constructor.
+ */
+ kMyMoneyDateTbl(QWidget *parent=0,
+ QDate date=QDate::currentDate(),
+ const char* name=0, WFlags f=0);
+ /**
+ * Returns a recommended size for the widget.
+ * To save some time, the size of the largest used cell content is
+ * calculated in each paintCell() call, since all calculations have
+ * to be done there anyway. The size is stored in maxCell. The
+ * sizeHint() simply returns a multiple of maxCell.
+ */
+ virtual QSize sizeHint() const;
+ /**
+ * Set the font size of the date table.
+ */
+ virtual void setFontSize(int size);
+ /**
+ * Select and display this date.
+ */
+ virtual bool setDate(const QDate&);
+ virtual const QDate& getDate() const;
+
+ virtual void setType(calendarType type);
+ virtual calendarType type(void) const { return m_type; }
+
+signals:
+ /**
+ * The selected date changed.
+ */
+ void dateChanged(QDate);
+ /**
+ * A date has been selected by clicking on the table.
+ */
+ void tableClicked();
+
+ /**
+ *
+ **/
+ virtual void hoverDate(QDate);
+
+protected:
+ /**
+ * Paint a cell.
+ */
+ virtual void paintCell(QPainter*, int, int);
+ /**
+ * Handle the resize events.
+ */
+ virtual void viewportResizeEvent(QResizeEvent *);
+ /**
+ * React on mouse clicks that select a date.
+ */
+ virtual void contentsMouseReleaseEvent(QMouseEvent *);
+ virtual void wheelEvent( QWheelEvent * e );
+ virtual void keyPressEvent( QKeyEvent *e );
+ virtual void focusInEvent( QFocusEvent *e );
+ virtual void focusOutEvent( QFocusEvent *e );
+
+ virtual void drawCellContents(QPainter *painter, int row, int col, const QDate& theDate) = 0;
+
+ virtual void contentsMouseMoveEvent(QMouseEvent* e);
+
+ /**
+ * The font size of the displayed text.
+ */
+ int fontsize;
+ /**
+ * The currently selected date.
+ */
+ QDate date;
+ /**
+ * The day of the first day in the month [1..7].
+ */
+ int firstday;
+ /**
+ * The number of days in the current month.
+ */
+ int numdays;
+ /**
+ * The number of days in the previous month.
+ */
+ int numDaysPrevMonth;
+ /**
+ * unused
+ * ### remove in KDE 4.0
+ */
+ bool unused_hasSelection;
+ /**
+ * Save the size of the largest used cell content.
+ */
+ QRect maxCell;
+
+ /**
+ * Type related variables
+ **/
+ calendarType m_type;
+ int m_colCount;
+ int m_rowCount;
+
+ ///
+ QDate m_drawDateOrig;
+
+private:
+#if QT_VERSION <= 0x030005
+ int weekNumber(const QDate&, int *yr) const;
+#endif
+
+#if KDE_IS_VERSION(3,2,0)
+ #define WEEK_DAY_NAME(a,b) KGlobal::locale()->calendar()->weekDayName(a,b)
+#else
+ #define WEEK_DAY_NAME(a,b) KGlobal::locale()->weekDayName(a,b)
+#endif
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyedit.cpp b/kmymoney2/widgets/kmymoneyedit.cpp
new file mode 100644
index 0000000..87be674
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyedit.cpp
@@ -0,0 +1,559 @@
+/***************************************************************************
+ kmymoneyedit.cpp
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes,
+ 2004 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qwidget.h>
+#include <qvbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <klineedit.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneylineedit.h>
+#include "kmymoneyedit.h"
+#include "kmymoneycalculator.h"
+#include "../mymoney/mymoneymoney.h"
+
+kMyMoneyMoneyValidator::kMyMoneyMoneyValidator(QObject * parent, const char * name) :
+ QDoubleValidator(parent, name)
+{
+}
+
+kMyMoneyMoneyValidator::kMyMoneyMoneyValidator( double bottom, double top, int decimals,
+ QObject * parent, const char * name ) :
+ QDoubleValidator(bottom, top, decimals, parent, name)
+{
+}
+
+/*
+ * The code of the following function is taken from kdeui/knumvalidator.cpp
+ * and adjusted to always use the monetary symbols defined in the KDE control center
+ */
+QValidator::State kMyMoneyMoneyValidator::validate( QString & input, int & _p ) const
+{
+ QString s = input;
+ KLocale * l = KGlobal::locale();
+ // ok, we have to re-format the number to have:
+ // 1. decimalSymbol == '.'
+ // 2. negativeSign == '-'
+ // 3. positiveSign == <empty>
+ // 4. thousandsSeparator() == <empty> (we don't check that there
+ // are exactly three decimals between each separator):
+ QString d = l->monetaryDecimalSymbol(),
+ n = l->negativeSign(),
+ p = l->positiveSign(),
+ t = l->monetaryThousandsSeparator();
+ // first, delete p's and t's:
+ if ( !p.isEmpty() )
+ for ( int idx = s.find( p ) ; idx >= 0 ; idx = s.find( p, idx ) )
+ s.remove( idx, p.length() );
+
+
+ if ( !t.isEmpty() )
+ for ( int idx = s.find( t ) ; idx >= 0 ; idx = s.find( t, idx ) )
+ s.remove( idx, t.length() );
+
+ // then, replace the d's and n's
+ if ( ( !n.isEmpty() && n.find('.') != -1 ) ||
+ ( !d.isEmpty() && d.find('-') != -1 ) ) {
+ // make sure we don't replace something twice:
+ kdWarning() << "KDoubleValidator: decimal symbol contains '-' or "
+ "negative sign contains '.' -> improve algorithm" << endl;
+ return Invalid;
+ }
+
+ if ( !d.isEmpty() && d != "." )
+ for ( int idx = s.find( d ) ; idx >= 0 ; idx = s.find( d, idx + 1 ) )
+ s.replace( idx, d.length(), ".");
+
+ if ( !n.isEmpty() && n != "-" )
+ for ( int idx = s.find( n ) ; idx >= 0 ; idx = s.find( n, idx + 1 ) )
+ s.replace( idx, n.length(), "-" );
+
+ // Take care of monetary parens around the value if selected via
+ // the locale settings.
+ // If the lead-in or lead-out paren is present, remove it
+ // before passing the string to the QDoubleValidator
+ if(l->negativeMonetarySignPosition() == KLocale::ParensAround
+ || l->positiveMonetarySignPosition() == KLocale::ParensAround) {
+ QRegExp regExp("^(\\()?([\\d-\\.]*)(\\))?$");
+ if(s.find(regExp) != -1) {
+ s = regExp.cap(2);
+ }
+ }
+
+ // check for non numeric values (QDoubleValidator allows an 'e', we don't)
+ QRegExp nonNumeric("[^\\d-\\.]+");
+ if(s.find(nonNumeric) != -1)
+ return Invalid;
+
+ // check for minus sign trailing the number
+ QRegExp trailingMinus("^([^-]*)\\w*-$");
+ if(s.find(trailingMinus) != -1) {
+ s = QString("-%1").arg(trailingMinus.cap(1));
+ }
+
+ // check for the maximum allowed number of decimal places
+ int decPos = s.find('.');
+ if(decPos != -1) {
+ if(decimals() == 0)
+ return Invalid;
+ if(((int)(s.length()) - decPos) > decimals())
+ return Invalid;
+ }
+
+ // If we have just a single minus sign, we are done
+ if(s == QString("-"))
+ return Acceptable;
+
+ QValidator::State rc = QDoubleValidator::validate( s, _p );
+
+ if(rc == Acceptable) {
+ // If the numeric value is acceptable, we check if the parens
+ // are ok. If only the lead-in is present, the return value
+ // is intermediate, if only the lead-out is present then it
+ // definitely is invalid. Nevertheless, we check for parens
+ // only, if the locale settings have it enabled.
+ if(l->negativeMonetarySignPosition() == KLocale::ParensAround
+ || l->positiveMonetarySignPosition() == KLocale::ParensAround) {
+ int tmp = input.contains('(') - input.contains(')');
+ if(tmp > 0)
+ rc = Intermediate;
+ else if(tmp < 0)
+ rc = Invalid;
+ }
+ }
+ return rc;
+}
+
+kMyMoneyEdit::kMyMoneyEdit(QWidget *parent, const char *name, const int prec)
+ : QHBox(parent, name)
+{
+ m_prec = prec;
+ if(prec < -1 || prec > 20)
+ m_prec = KGlobal::locale()->fracDigits();
+ init();
+}
+
+kMyMoneyEdit::kMyMoneyEdit(const MyMoneySecurity& sec, QWidget *parent, const char *name)
+ : QHBox(parent, name)
+{
+ m_prec = MyMoneyMoney::denomToPrec(sec.smallestAccountFraction());
+ init();
+}
+
+// converted image from kde3.5.1/share/apps/kdevdesignerpart/pics/designer_resetproperty.png
+static const uchar resetButtonImage[] = {
+ 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,
+ 0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,
+ 0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,
+ 0x08,0x06,0x00,0x00,0x00,0x0F,0x0E,0x84,
+ 0x76,0x00,0x00,0x00,0x06,0x62,0x4B,0x47,
+ 0x44,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xA0,
+ 0xBD,0xA7,0x93,0x00,0x00,0x00,0x09,0x70,
+ 0x48,0x59,0x73,0x00,0x00,0x0B,0x13,0x00,
+ 0x00,0x0B,0x13,0x01,0x00,0x9A,0x9C,0x18,
+ 0x00,0x00,0x00,0x07,0x74,0x49,0x4D,0x45,
+ 0x07,0xD6,0x06,0x10,0x09,0x36,0x0C,0x58,
+ 0x91,0x11,0x7C,0x00,0x00,0x00,0x64,0x49,
+ 0x44,0x41,0x54,0x78,0xDA,0x65,0xC9,0xA1,
+ 0x0D,0x02,0x41,0x18,0x84,0xD1,0xF7,0x5F,
+ 0x13,0x04,0x9A,0x39,0x43,0x68,0x81,0x02,
+ 0x10,0xB8,0x13,0x74,0x80,0xC1,0x21,0x76,
+ 0x1D,0xDD,0xD0,0x01,0x65,0x10,0x34,0x9A,
+ 0x0C,0x66,0x83,0x61,0x92,0x2F,0x23,0x5E,
+ 0x25,0x01,0xBD,0x6A,0xC6,0x1D,0x9B,0x25,
+ 0x79,0xC2,0x34,0xE0,0x30,0x00,0x56,0xBD,
+ 0x6A,0x0D,0xD5,0x38,0xE1,0xEA,0x7F,0xE7,
+ 0x4A,0xA2,0x57,0x1D,0x71,0xC1,0x07,0xBB,
+ 0x81,0x8F,0x09,0x96,0xE4,0x86,0x3D,0xDE,
+ 0x78,0x8D,0x48,0xF2,0xAB,0xB1,0x1D,0x9F,
+ 0xC6,0xFC,0x05,0x46,0x68,0x28,0x6B,0x58,
+ 0xEE,0x72,0x0A,0x00,0x00,0x00,0x00,0x49,
+ 0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
+};
+
+void kMyMoneyEdit::init(void)
+{
+ allowEmpty = false;
+ m_edit = new kMyMoneyLineEdit(this, 0, true);
+ m_edit->installEventFilter(this);
+ setFocusProxy(m_edit);
+
+ // Yes, just a simple double validator !
+ kMyMoneyMoneyValidator *validator = new kMyMoneyMoneyValidator(this);
+ m_edit->setValidator(validator);
+ m_edit->setAlignment(AlignRight | AlignVCenter);
+
+ m_calculatorFrame = new QVBox(this, 0, WType_Popup);
+
+ m_calculatorFrame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
+ m_calculatorFrame->setLineWidth(3);
+
+ m_calculator = new kMyMoneyCalculator(m_calculatorFrame);
+ m_calculatorFrame->setFixedSize(m_calculator->width()+3, m_calculator->height()+3);
+ m_calculatorFrame->hide();
+
+ m_calcButton = new KPushButton(QIconSet(QPixmap(KGlobal::iconLoader()->iconPath("kcalc", -KIcon::SizeSmall))), QString(""), this);
+ m_calcButton->setFixedWidth( m_calcButton->sizeHint().width() );
+ m_calcButton->setFixedHeight(m_edit->sizeHint().height());
+ m_calcButton->setFocusProxy(m_edit);
+
+ QPixmap pixmap;
+ pixmap.loadFromData(resetButtonImage, sizeof(resetButtonImage), "PNG", 0);
+ m_resetButton = new KPushButton(QIconSet(pixmap), QString(""), this);
+ m_resetButton->setFixedWidth( m_resetButton->sizeHint().width() );
+ m_resetButton->setFixedHeight(m_edit->sizeHint().height());
+ m_resetButton->setEnabled(false);
+ m_resetButton->setFocusProxy(m_edit);
+
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("General Options");
+ if(kconfig->readBoolEntry("DontShowCalculatorButton", false) == true)
+ setCalculatorButtonVisible(false);
+
+ setSpacing(0);
+
+ connect(m_edit, SIGNAL(textChanged(const QString&)), this, SLOT(theTextChanged(const QString&)));
+ connect(m_calculator, SIGNAL(signalResultAvailable()), this, SLOT(slotCalculatorResult()));
+ connect(m_calcButton, SIGNAL(clicked()), this, SLOT(slotCalculatorOpen()));
+ connect(m_resetButton, SIGNAL(clicked()), this, SLOT(resetText()));
+}
+
+void kMyMoneyEdit::setValidator(const QValidator* v)
+{
+ m_edit->setValidator(v);
+}
+
+kMyMoneyEdit::~kMyMoneyEdit()
+{
+ delete m_calculatorFrame;
+}
+
+KLineEdit* kMyMoneyEdit::lineedit(void) const
+{
+ return m_edit;
+}
+
+void kMyMoneyEdit::setPrecision(const int prec)
+{
+ if(prec >= -1 && prec <= 20) {
+ if(prec != m_prec) {
+ m_prec = prec;
+ // update current display
+ setValue(value());
+ }
+ }
+}
+
+bool kMyMoneyEdit::isValid(void) const
+{
+ return !(m_edit->text().isEmpty());
+}
+
+MyMoneyMoney kMyMoneyEdit::value(void) const
+{
+ QString txt = m_edit->text();
+ ensureFractionalPart(txt);
+ MyMoneyMoney money(txt);
+ if(m_prec != -1)
+ money = money.convert(MyMoneyMoney::precToDenom(m_prec));
+ return money;
+}
+
+void kMyMoneyEdit::setValue(const MyMoneyMoney& value)
+{
+ // load the value into the widget but don't use thousandsSeparators
+ QString txt = value.formatMoney("", m_prec, false);
+ loadText(txt);
+}
+
+void kMyMoneyEdit::loadText(const QString& txt)
+{
+ m_edit->setText(txt);
+ if(isEnabled() && !txt.isEmpty())
+ ensureFractionalPart();
+ m_text = m_edit->text();
+ m_resetButton->setEnabled(false);
+}
+
+void kMyMoneyEdit::clearText(void)
+{
+ m_text = QString();
+ m_edit->setText(m_text);
+}
+
+void kMyMoneyEdit::resetText(void)
+{
+ m_edit->setText(m_text);
+ m_resetButton->setEnabled(false);
+}
+
+void kMyMoneyEdit::theTextChanged(const QString & theText)
+{
+ KLocale * l = KGlobal::locale();
+ QString d = l->monetaryDecimalSymbol();
+ QString l_text = theText;
+ QString nsign, psign;
+ if(l->negativeMonetarySignPosition() == KLocale::ParensAround
+ || l->positiveMonetarySignPosition() == KLocale::ParensAround) {
+ nsign = psign = "(";
+ } else {
+ nsign = l->negativeSign();
+ psign = l->positiveSign();
+ }
+
+ int i = 0;
+ if(isEnabled()) {
+ QValidator::State state = m_edit->validator()->validate( l_text, i);
+ if(state == QValidator::Intermediate) {
+ if(l_text.length() == 1) {
+ if(l_text != d && l_text != nsign && l_text != psign && l_text != "-")
+ state = QValidator::Invalid;
+ }
+ }
+ if (state==QValidator::Invalid)
+ m_edit->setText(previousText);
+ else {
+ previousText = l_text;
+ emit textChanged(m_edit->text());
+ m_resetButton->setEnabled(true);
+ }
+ }
+}
+
+void kMyMoneyEdit::ensureFractionalPart(void)
+{
+ QString s(m_edit->text());
+ ensureFractionalPart(s);
+ m_edit->setText(s);
+}
+
+void kMyMoneyEdit::ensureFractionalPart(QString& s) const
+{
+
+ KLocale* locale = KGlobal::locale();
+ QString decimalSymbol = locale->monetaryDecimalSymbol();
+ if(decimalSymbol.isEmpty())
+ decimalSymbol = ".";
+
+ // If text contains no 'monetaryDecimalSymbol' then add it
+ // followed by the required number of 0s
+ if (!s.isEmpty()) {
+ if(m_prec > 0) {
+ if (!s.contains(decimalSymbol)) {
+ s += decimalSymbol;
+ for (int i=0; i < m_prec; i++)
+ s += "0";
+ }
+ } else if(m_prec == 0) {
+ while(s.contains(decimalSymbol)) {
+ int pos = s.findRev(decimalSymbol);
+ if(pos != -1) {
+ s.truncate(pos);
+ }
+ }
+ } else if(s.contains(decimalSymbol)) { // m_prec == -1 && fraction
+ // no trailing zeroes
+ while(s.endsWith("0")) {
+ s.truncate(s.length()-1);
+ }
+ // no trailing decimalSymbol
+ if(s.endsWith(decimalSymbol))
+ s.truncate(s.length()-1);
+ }
+ }
+}
+
+bool kMyMoneyEdit::eventFilter(QObject * /* o */ , QEvent *e )
+{
+ bool rc = false;
+
+ // we want to catch some keys that are usually handled by
+ // the base class (e.g. '+', '-', etc.)
+ if(e->type() == QEvent::KeyPress) {
+ QKeyEvent *k = static_cast<QKeyEvent *> (e);
+
+ rc = true;
+ switch(k->key()) {
+ case Qt::Key_Plus:
+ case Qt::Key_Minus:
+ if(m_edit->hasSelectedText()) {
+ m_edit->cut();
+ }
+ if(m_edit->text().length() == 0) {
+ rc = false;
+ break;
+ }
+ // in case of '-' we do not enter the calculator when
+ // the current position is the beginning and there is
+ // no '-' sign at the first position.
+ if(k->key() == Qt::Key_Minus) {
+ if(m_edit->cursorPosition() == 0 && m_edit->text()[0] != '-') {
+ rc = false;
+ break;
+ }
+ }
+ // otherwise, tricky fall through here!
+
+ case Qt::Key_Slash:
+ case Qt::Key_Asterisk:
+ case Qt::Key_Percent:
+ if(m_edit->hasSelectedText()) {
+ // remove the selected text
+ m_edit->cut();
+ }
+ calculatorOpen(k);
+ break;
+
+ default:
+ rc = false;
+ break;
+ }
+
+ } else if(e->type() == QEvent::FocusOut) {
+ if(!m_edit->text().isEmpty() || !allowEmpty)
+ ensureFractionalPart();
+
+ if(MyMoneyMoney(m_edit->text()) != MyMoneyMoney(m_text)
+ && !m_calculator->isVisible()) {
+ emit valueChanged(m_edit->text());
+ }
+ m_text = m_edit->text();
+ }
+ return rc;
+}
+
+void kMyMoneyEdit::slotCalculatorOpen(void)
+{
+ calculatorOpen(0);
+}
+
+void kMyMoneyEdit::calculatorOpen(QKeyEvent* k)
+{
+ m_calculator->setInitialValues(m_edit->text(), k);
+
+ int h = m_calculatorFrame->height();
+ int w = m_calculatorFrame->width();
+
+ // usually, the calculator widget is shown underneath the MoneyEdit widget
+ // if it does not fit on the screen, we show it above this widget
+ QPoint p = mapToGlobal(QPoint(0,0));
+ if(p.y() + height() + h > QApplication::desktop()->height())
+ p.setY(p.y() - h);
+ else
+ p.setY(p.y() + height());
+
+ // usually, it is shown left aligned. If it does not fit, we align it
+ // to the right edge of the widget
+ if(p.x() + w > QApplication::desktop()->width())
+ p.setX(p.x() + width() - w);
+
+ QRect r = m_calculator->geometry();
+ r.moveTopLeft(p);
+ m_calculatorFrame->setGeometry(r);
+ m_calculatorFrame->show();
+ m_calculator->setFocus();
+}
+
+void kMyMoneyEdit::slotCalculatorResult(void)
+{
+ QString result;
+ if(m_calculator != 0) {
+ m_calculatorFrame->hide();
+ m_edit->setText(m_calculator->result());
+ ensureFractionalPart();
+ emit valueChanged(m_edit->text());
+ m_text = m_edit->text();
+ }
+}
+
+QWidget* kMyMoneyEdit::focusWidget(void) const
+{
+ QWidget* w = m_edit;
+ while(w->focusProxy())
+ w = w->focusProxy();
+ return w;
+}
+
+void kMyMoneyEdit::setCalculatorButtonVisible(const bool show)
+{
+ m_calcButton->setShown(show);
+}
+
+void kMyMoneyEdit::setResetButtonVisible(const bool show)
+{
+ m_resetButton->setShown(show);
+}
+
+void kMyMoneyEdit::setAllowEmpty(bool allowed)
+{
+ allowEmpty = allowed;
+}
+
+bool kMyMoneyEdit::isCalculatorButtonVisible(void) const
+{
+ return m_calcButton->isVisible();
+}
+
+bool kMyMoneyEdit::isResetButtonVisible(void) const
+{
+ return m_resetButton->isVisible();
+}
+
+bool kMyMoneyEdit::isEmptyAllowed(void) const
+{
+ return allowEmpty;
+}
+
+void kMyMoneyEdit::setHint(const QString& hint) const
+{
+ if(m_edit)
+ m_edit->setHint(hint);
+}
+
+bool kMyMoneyEdit::isReadOnly(void) const
+{
+ if(m_edit)
+ return m_edit->isReadOnly();
+ return false;
+}
+
+void kMyMoneyEdit::setReadOnly(bool readOnly)
+{
+ // we use the QLineEdit::setReadOnly() method directly to avoid
+ // changing the background between readonly and read/write mode
+ // as it is done by the KLineEdit code.
+ if(m_edit)
+ m_edit->QLineEdit::setReadOnly(readOnly);
+}
+
+#include "kmymoneyedit.moc"
diff --git a/kmymoney2/widgets/kmymoneyedit.h b/kmymoney2/widgets/kmymoneyedit.h
new file mode 100644
index 0000000..6415a0c
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyedit.h
@@ -0,0 +1,243 @@
+/***************************************************************************
+ kmymoneyedit.h
+ -------------------
+ copyright : (C) 2000 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYEDIT_H
+#define KMYMONEYEDIT_H
+
+#include "kdecompat.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qhbox.h>
+#include <qvalidator.h>
+
+class QVBox;
+class QWidget;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klineedit.h>
+class KPushButton;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/mymoneysecurity.h>
+class MyMoneyMoney;
+class kMyMoneyCalculator;
+
+#if KDE_VERSION <= KDE_MAKE_VERSION(3,1,0)
+ #define KDoubleValidator QDoubleValidator
+#endif
+
+/**
+ * This class is derived from KDoubleValidator and uses
+ * the monetary symbols instead of the numeric symbols.
+ * Also, it always accepts localized input.
+ *
+ * @author Thomas Baumgart
+ */
+class kMyMoneyMoneyValidator : public QDoubleValidator
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constuct a locale-aware KDoubleValidator with default range
+ * (whatever QDoubleValidator uses for that) and parent @p
+ * parent
+ */
+ kMyMoneyMoneyValidator( QObject * parent, const char * name=0 );
+ /**
+ * Constuct a locale-aware KDoubleValidator for range [@p bottom,@p
+ * top] and a precision of @p decimals decimals after the decimal
+ * point.
+ */
+ kMyMoneyMoneyValidator( double bottom, double top, int decimals,
+ QObject * parent, const char * name=0 );
+ /**
+ * Destructs the validator.
+ */
+ virtual ~kMyMoneyMoneyValidator() {}
+
+ /** Overloaded for internal reasons. The API is not affected. */
+ virtual QValidator::State validate( QString & input, int & pos ) const;
+};
+
+/**
+ * This class represents a widget to enter monetary values.
+ * It has an edit field and a button to select a popup
+ * calculator. The result of the calculator (if used) is
+ * stored in the edit field.
+ *
+ * @author Michael Edwardes, Thomas Baumgart
+ */
+class kMyMoneyEdit : public QHBox
+{
+ Q_OBJECT
+ Q_PROPERTY(bool calculatorButtonVisibility READ isCalculatorButtonVisible WRITE setCalculatorButtonVisible);
+ Q_PROPERTY(bool resetButtonVisibility READ isResetButtonVisible WRITE setResetButtonVisible);
+ Q_PROPERTY(bool allowEmpty READ isEmptyAllowed WRITE setAllowEmpty);
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly )
+
+private:
+ QString previousText; // keep track of what has been typed
+ QString m_text; // keep track of what was the original value
+ kMyMoneyCalculator* m_calculator;
+ QVBox* m_calculatorFrame;
+ kMyMoneyLineEdit* m_edit;
+ KPushButton* m_calcButton;
+ KPushButton* m_resetButton;
+ int m_prec;
+ bool calculatorButtonVisibility;
+ bool allowEmpty;
+
+private:
+ /**
+ * Internal helper function for value() and ensureFractionalPart(void).
+ */
+ void ensureFractionalPart(QString& txt) const;
+
+protected:
+ /**
+ * This method ensures that the text version contains a
+ * fractional part.
+ */
+ void ensureFractionalPart(void);
+
+ /**
+ * This method opens the calculator and replays the key
+ * event pointed to by @p ev. If @p ev is 0, then no key
+ * event is replayed.
+ *
+ * @param ev pointer to QKeyEvent that started the calculator.
+ */
+ void calculatorOpen(QKeyEvent* ev);
+
+ /**
+ * Helper method for constructors.
+ */
+ void init(void);
+
+protected slots:
+ void theTextChanged(const QString & text);
+ void slotCalculatorResult(void);
+ void slotCalculatorOpen(void);
+
+public:
+ kMyMoneyEdit(QWidget *parent=0, const char *name=0, const int prec = -2);
+ kMyMoneyEdit(const MyMoneySecurity& eq, QWidget *parent=0, const char *name=0);
+ ~kMyMoneyEdit();
+
+ /**
+ * @deprecated Use value() instead
+ */
+ // MyMoneyMoney getMoneyValue(void) KDE_DEPRECATED;
+
+ MyMoneyMoney value(void) const;
+
+ void setValue(const MyMoneyMoney& value);
+
+ bool isValid(void) const;
+
+ virtual bool eventFilter(QObject * , QEvent * );
+
+ /**
+ * This method returns the value of the edit field in "numerator/denominator" format.
+ * If you want to get the text of the edit field, use lineedit()->text() instead.
+ */
+ QString text(void) const { return value().toString(); };
+
+ void setMinimumWidth(int w) { m_edit->setMinimumWidth(w); };
+
+ /**
+ * Set the number of fractional digits that should be shown
+ *
+ * @param prec number of fractional digits.
+ *
+ * @note should be used prior to calling loadText()
+ * @sa precision
+ */
+ void setPrecision(const int prec);
+
+ /**
+ * return the number of fractional digits
+ * @sa setPrecision
+ */
+ int precision(void) { return m_prec; };
+
+ QWidget* focusWidget(void) const;
+
+ /**
+ * This method allows to modify the behavior of the widget
+ * such that it accepts an empty value (all blank) or not.
+ * The default is to not accept an emtpy input and to
+ * convert an empty field into 0.00 upon loss of focus.
+ *
+ * @param allowed if @a true, empty input is allowed, if @a false
+ * emtpy input will be converted to 0.00
+ */
+ void setAllowEmpty(bool allowed = true);
+
+ /** Overloaded for internal reasons. The API is not affected. */
+ void setValidator(const QValidator* v);
+
+ bool isCalculatorButtonVisible(void) const;
+
+ bool isResetButtonVisible(void) const;
+
+ bool isEmptyAllowed(void) const;
+
+ KLineEdit* lineedit(void) const;
+
+ void setHint(const QString& hint) const;
+
+ bool isReadOnly(void) const;
+
+public slots:
+ void loadText(const QString& text);
+ void resetText(void);
+ void clearText(void);
+
+ void setText(const QString& txt) { setValue(MyMoneyMoney(txt)); };
+
+ /**
+ * This method allows to show/hide the calculator button of the widget.
+ * The parameter @p show controls the behavior. Default is to show the
+ * button.
+ *
+ * @param show if true, button is shown, if false it is hidden
+ */
+ void setCalculatorButtonVisible(const bool show);
+
+ void setResetButtonVisible(const bool show);
+
+ void setReadOnly(bool readOnly);
+
+signals: // Signals
+ /**
+ * This signal is sent, when the focus leaves this widget and
+ * the amount has been changed by user during this session.
+ */
+ void valueChanged(const QString& text);
+
+ void textChanged(const QString& text);
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyforecastlistviewitem.cpp b/kmymoney2/widgets/kmymoneyforecastlistviewitem.cpp
new file mode 100644
index 0000000..684997e
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyforecastlistviewitem.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+ kmymoneylistviewitem - description
+ -------------------
+ begin : Sun Nov 25 2007
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpalette.h>
+#include <qpen.h>
+#include <qcolor.h>
+#include <qpainter.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyforecastlistviewitem.h"
+
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+KMyMoneyForecastListViewItem::KMyMoneyForecastListViewItem (QListView* parent, QListViewItem* after, bool isNegative) :
+ KListViewItem(parent, after),
+ m_negative(isNegative)
+{
+}
+
+KMyMoneyForecastListViewItem::~KMyMoneyForecastListViewItem()
+{
+}
+
+void KMyMoneyForecastListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
+{
+ QColorGroup _cg = cg;
+ QColor textColour;
+ if(m_negative == true) {
+ textColour = KMyMoneyGlobalSettings::listNegativeValueColor(); //if the item is marked is marked as negative, all columns will be painted negative
+ } else {
+ textColour = m_columnsColor[column]; //otherwise, respect the color for each column
+ }
+ _cg.setColor(QColorGroup::Text, textColour);
+
+ KListViewItem::paintCell(p, _cg, column, width, alignment);
+}
+
+void KMyMoneyForecastListViewItem::setNegative(bool isNegative)
+{
+ m_negative = isNegative;
+}
+
+void KMyMoneyForecastListViewItem::setText( int column, const QString &text, const bool &negative)
+{
+ //if negative set the map to negative color according to KMyMoneySettings
+ if(negative) {
+ m_columnsColor[column] = KMyMoneyGlobalSettings::listNegativeValueColor();
+ } else {
+ m_columnsColor[column] = QColorGroup::Text;
+ }
+
+ KListViewItem::setText(column, text);
+}
diff --git a/kmymoney2/widgets/kmymoneyforecastlistviewitem.h b/kmymoney2/widgets/kmymoneyforecastlistviewitem.h
new file mode 100644
index 0000000..7e48945
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyforecastlistviewitem.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ kmymoneyforecastlistviewitem.h
+ -------------------
+ begin : Sun Nov 25 2007
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYFORECASTLISTVIEWITEM_H
+#define KMYMONEYFORECASTLISTVIEWITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ * This class implements a derived version of a KListViewItem that
+ * allows printing negative numbers in red
+ *
+ * @author Alvaro Soliverez
+ */
+class KMyMoneyForecastListViewItem : public KListViewItem
+{
+public:
+
+ KMyMoneyForecastListViewItem(QListView* parent, QListViewItem* after, bool isNegative);
+
+ ~KMyMoneyForecastListViewItem();
+
+ void setNegative(bool isNegative);
+
+ void setText( int column, const QString &text, const bool &negative = false );
+
+ /**
+ * use my own paint method
+ */
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment);
+
+
+private:
+
+ bool m_negative;
+
+ QMap<int, QColor> m_columnsColor;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneygpgconfig.cpp b/kmymoney2/widgets/kmymoneygpgconfig.cpp
new file mode 100644
index 0000000..f168e69
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneygpgconfig.cpp
@@ -0,0 +1,130 @@
+/***************************************************************************
+ kmymoneyonlinequoteconfig.cpp - description
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kled.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneygpgconfig.h"
+#include "libkgpgfile/kgpgfile.h"
+
+#define RECOVER_KEY_ID "0xD2B08440"
+
+kMyMoneyGPGConfig::kMyMoneyGPGConfig(QWidget *parent, const char *name )
+ : kMyMoneyGPGConfigDecl(parent, name),
+ m_checkCount(0)
+{
+ m_idGroup->setEnabled(KGPGFile::GPGAvailable());
+ m_recoveryGroup->setEnabled(KGPGFile::keyAvailable(RECOVER_KEY_ID));
+
+ m_userKeyFound->off();
+ m_recoverKeyFound->off();
+
+ connect(m_useEncryption, SIGNAL(toggled(bool)), this, SLOT(slotStatusChanged(bool)));
+ connect(m_userId, SIGNAL(textChanged(const QString&)), this, SLOT(slotIdChanged(const QString&)));
+}
+
+void kMyMoneyGPGConfig::resetConfig(void)
+{
+ m_useEncryption->setChecked(m_resetUseEncryption);
+ m_userId->setText(m_resetUserId);
+ m_recover->setChecked(m_resetRecover);
+ slotStatusChanged(m_resetUseEncryption);
+ writeConfig();
+}
+
+void kMyMoneyGPGConfig::readConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("General Options");
+ m_resetUseEncryption = config->readBoolEntry("WriteDataEncrypted", false);
+ m_resetRecover = config->readBoolEntry("EncryptRecover", false);
+ m_resetUserId = config->readEntry("GPG-Recipient");
+
+ resetConfig();
+}
+
+void kMyMoneyGPGConfig::writeConfig(void)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("General Options");
+ config->writeEntry("WriteDataEncrypted", m_useEncryption->isChecked());
+ config->writeEntry("EncryptRecover", m_recover->isChecked());
+ config->writeEntry("GPG-Recipient", m_userId->text());
+}
+
+void kMyMoneyGPGConfig::slotIdChanged(const QString& /*txt*/)
+{
+ // this looks a bit awkward. Here's why: KGPGFile::keyAvailable() starts
+ // an external task and processes UI events while it waits for the external
+ // process to finish. Thus, the first time we get here, the external process
+ // is started and the user my press a second key which calls this routine
+ // again.
+ //
+ // The second invocation is counted, but the check is not started until the
+ // first one finishes. Once the external process finishes, we check if we
+ // were called in the meantime and restart the check.
+ if(++m_checkCount == 1) {
+ while(1) {
+ if(m_userId->text().stripWhiteSpace().length() > 0) {
+ m_userKeyFound->setState((KLed::State) (KGPGFile::keyAvailable(m_userId->text()) ? KLed::On : KLed::Off));
+ if(m_checkCount > 1) {
+ m_checkCount = 1;
+ continue;
+ }
+ } else {
+ m_userKeyFound->setState(KLed::Off);
+ }
+ break;
+ }
+ --m_checkCount;
+ }
+}
+
+void kMyMoneyGPGConfig::slotStatusChanged(bool state)
+{
+ if(state) {
+ m_idGroup->setEnabled(KGPGFile::GPGAvailable());
+ m_recoveryGroup->setEnabled(KGPGFile::GPGAvailable());
+ m_recoverKeyFound->setState((KLed::State) (KGPGFile::keyAvailable(RECOVER_KEY_ID) ? KLed::On : KLed::Off));
+ if(m_userId->text().isEmpty())
+ m_userKeyFound->setState(KLed::Off);
+ else
+ m_userKeyFound->setState((KLed::State) (KGPGFile::keyAvailable(m_userId->text()) ? KLed::On : KLed::Off));
+ } else {
+ m_idGroup->setEnabled(false);
+ m_recoveryGroup->setEnabled(false);
+ m_recoverKeyFound->setState(KLed::Off);
+ m_userKeyFound->setState(KLed::Off);
+ }
+}
+
+#include "kmymoneygpgconfig.moc"
diff --git a/kmymoney2/widgets/kmymoneygpgconfig.h b/kmymoney2/widgets/kmymoneygpgconfig.h
new file mode 100644
index 0000000..9d2bdc7
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneygpgconfig.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ kmymoneygpgconfig.h - description
+ -------------------
+ begin : Mon Jan 3 2005
+ copyright : (C) 2005 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYGPGCONFIG_H
+#define KMYMONEYGPGCONFIG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../widgets/kmymoneygpgconfigdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+
+/**
+ * This class provides the necessary user interface to
+ * setup the parameters required for data encryption
+ */
+class kMyMoneyGPGConfig : public kMyMoneyGPGConfigDecl
+{
+ Q_OBJECT
+public:
+ kMyMoneyGPGConfig(QWidget* parent, const char *name);
+ virtual ~kMyMoneyGPGConfig() {}
+
+ void writeConfig(void);
+ void readConfig(void);
+ void resetConfig(void);
+
+protected slots:
+ void slotIdChanged(const QString& txt);
+ void slotStatusChanged(bool);
+
+private:
+ QString m_resetUserId;
+ bool m_resetUseEncryption;
+ bool m_resetRecover;
+ int m_checkCount;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneygpgconfigdecl.ui b/kmymoney2/widgets/kmymoneygpgconfigdecl.ui
new file mode 100644
index 0000000..4aa12eb
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneygpgconfigdecl.ui
@@ -0,0 +1,197 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kMyMoneyGPGConfigDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyGPGConfigDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>490</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>GPG encryption settings</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This page allows you to set the parameters for encrypted file storage of your &lt;b&gt;KMyMoney&lt;/b&gt; data based on &lt;b&gt;GPG&lt;/b&gt;.&lt;p&gt;
+Acces to the settings is disabled if &lt;b&gt;GPG&lt;/b&gt; could not be detected on your system. In this case, please make sure that &lt;b&gt;GPG&lt;/b&gt; is working properly for the current user.&lt;p&gt;
+The &lt;i&gt;Recovery encryption&lt;/i&gt; group is only accessible, if the necessary key for &lt;b&gt;kmymoney-recover@users.sourceforge.net&lt;/b&gt; with id 0x8AFDDC8E is found.</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_useEncryption</cstring>
+ </property>
+ <property name="text">
+ <string>Use GPG encryption</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_idGroup</cstring>
+ </property>
+ <property name="title">
+ <string>User identification</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Enter the id of the key you want to use for data encryption. This can either be an e-mail address or the hexadecimal key id. In case of the key id don't forget the leading &lt;i&gt;0x&lt;/i&gt;.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>User ID</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>m_userId</cstring>
+ </property>
+ </widget>
+ <widget class="KLed">
+ <property name="name">
+ <cstring>m_userKeyFound</cstring>
+ </property>
+ <property name="shape">
+ <enum>Circular</enum>
+ </property>
+ <property name="look">
+ <enum>Sunken</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This symbol denotes, if the key for the given user id has been found in your keyring. It is green when found, dark otherwise.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_recoveryGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Recovery encryption</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_recover</cstring>
+ </property>
+ <property name="text">
+ <string>Also encrypt with kmymoney-recover key</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLed">
+ <property name="name">
+ <cstring>m_recoverKeyFound</cstring>
+ </property>
+ <property name="shape">
+ <enum>Circular</enum>
+ </property>
+ <property name="look">
+ <enum>Sunken</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This symbol denotes, if the KMyMoney recovery key has been found in your keyring. It is green when found, dark otherwise.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>You can specify to encrypt the data also with the KMyMoney recover key. Only the core KMyMoney developers are in posession of the respective private key required to read back such encrypted data.&lt;p&gt;
+
+This mechanism is provided for the case that you have lost your key and cannot access your data anymore. With this option activated, the KMyMoney developers can decrypt the data and supply you with it in a readable form. Please be prepared, that you have to answer a few detailed questions about the contents of your data before we will send it out.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneylineedit.cpp b/kmymoney2/widgets/kmymoneylineedit.cpp
new file mode 100644
index 0000000..18e2e31
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneylineedit.cpp
@@ -0,0 +1,152 @@
+/***************************************************************************
+ kmymoneylineedit.cpp - description
+ -------------------
+ begin : Wed May 9 2001
+ copyright : (C) 2001 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qrect.h>
+#include <qpainter.h>
+#include <qpalette.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneylineedit.h"
+
+kMyMoneyLineEdit::kMyMoneyLineEdit(QWidget *w, const char* name, bool forceMonetaryDecimalSymbol, int alignment) :
+ KLineEdit(w, name),
+ m_forceMonetaryDecimalSymbol(forceMonetaryDecimalSymbol)
+{
+ setAlignment(alignment);
+}
+
+kMyMoneyLineEdit::~kMyMoneyLineEdit()
+{
+}
+
+void kMyMoneyLineEdit::resetText(void)
+{
+ setText(m_text);
+}
+
+void kMyMoneyLineEdit::loadText(const QString& text)
+{
+ m_text = text;
+ setText(text);
+}
+
+void kMyMoneyLineEdit::focusOutEvent(QFocusEvent *ev)
+{
+ // if the current text is not in the list of
+ // possible completions, we have a new payee
+ // and signal that to the outside world.
+ if(text() != m_text) {
+ emit lineChanged(text());
+ }
+ KLineEdit::focusOutEvent(ev);
+
+ // force update of hint
+ if(text().isEmpty())
+ repaint();
+}
+
+void kMyMoneyLineEdit::keyReleaseEvent(QKeyEvent* k)
+{
+ if(m_forceMonetaryDecimalSymbol) {
+ if(k->state() & Qt::Keypad) {
+ if(k->key() == Qt::Key_Comma
+ || k->key() == Qt::Key_Period) {
+ if(KGlobal::locale()->monetaryDecimalSymbol() == ",") {
+ QKeyEvent newk(k->type(), Qt::Key_Comma, ',', k->state(), ",", k->isAutoRepeat(), k->count());
+ KLineEdit::keyReleaseEvent(&newk);
+ k->ignore();
+ return;
+ }
+
+ if(KGlobal::locale()->monetaryDecimalSymbol() == ".") {
+ QKeyEvent newk(k->type(), Qt::Key_Comma, ',', k->state(), ".", k->isAutoRepeat(), k->count());
+ KLineEdit::keyReleaseEvent(&newk);
+ k->ignore();
+ return;
+ }
+ }
+ }
+ }
+ KLineEdit::keyReleaseEvent(k);
+}
+
+void kMyMoneyLineEdit::keyPressEvent(QKeyEvent* k)
+{
+ if(m_forceMonetaryDecimalSymbol) {
+ if(k->state() & Qt::Keypad) {
+ if(k->key() == Qt::Key_Comma
+ || k->key() == Qt::Key_Period) {
+ if(KGlobal::locale()->monetaryDecimalSymbol() == ",") {
+ QKeyEvent newk(k->type(), Qt::Key_Comma, ',', k->state(), ",", k->isAutoRepeat(), k->count());
+ KLineEdit::keyPressEvent(&newk);
+ k->ignore();
+ return;
+ }
+
+ if(KGlobal::locale()->monetaryDecimalSymbol() == ".") {
+ QKeyEvent newk(k->type(), Qt::Key_Period, '.', k->state(), ".", k->isAutoRepeat(), k->count());
+ KLineEdit::keyPressEvent(&newk);
+ k->ignore();
+ return;
+ }
+ }
+ }
+ }
+ KLineEdit::keyPressEvent(k);
+}
+
+void kMyMoneyLineEdit::drawContents( QPainter *p)
+{
+ KLineEdit::drawContents(p);
+
+ if(text().isEmpty() && !m_hint.isEmpty() && !hasFocus()) {
+ const int innerMargin = 1;
+
+ // the following 5 lines are taken from QLineEdit::drawContents()
+ QRect cr = contentsRect();
+ QFontMetrics fm = fontMetrics();
+ QRect lineRect( cr.x() + innerMargin, cr.y() + (cr.height() - fm.height() + 1) / 2,
+ cr.width() - 2*innerMargin, fm.height() );
+ QPoint topLeft = lineRect.topLeft() - QPoint(0, -fm.ascent());
+
+ p->save();
+ QFont f = p->font();
+ f.setItalic(true);
+ f.setWeight(QFont::Light);
+ p->setFont(f);
+ p->setPen(palette().disabled().text());
+
+ p->drawText(topLeft, m_hint);
+
+ p->restore();
+ }
+}
+
+#include "kmymoneylineedit.moc"
diff --git a/kmymoney2/widgets/kmymoneylineedit.h b/kmymoney2/widgets/kmymoneylineedit.h
new file mode 100644
index 0000000..2351082
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneylineedit.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+ kmymoneylineedit.h - description
+ -------------------
+ begin : Wed May 9 2001
+ copyright : (C) 2001 by Michael Edwardes
+ 2006 by Thomas Baumgart
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@ctv.es>
+ Felix Rodriguez <frodriguez@mail.wesleyan.edu>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYLINEEDIT_H
+#define KMYMONEYLINEEDIT_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ * This class represents a special verson of a KLineEdit object that
+ * supports the display of a hint if the display area is empty. It also
+ * overrides the comma key on the numeric keypad with the currently
+ * selected monetaryDecimalSymbol if selected during creation of the object.
+ *
+ * @author Michael Edwardes
+ * @author Thomas Baumgart
+ */
+class kMyMoneyLineEdit : public KLineEdit
+{
+ Q_OBJECT
+public:
+ /**
+ * @param w pointer to parent
+ * @param name pointer to name of object
+ * @param forceMonetaryDecimalSymbol if @a true, the numeric keypad comma key will have a fixed
+ * value and does not follow the keyboard layout (default: @p false)
+ * @param alignment Controls the alignment of the text. Default is Qt::AlignLeft | Qt::AlignVCenter.
+ * See Qt::AlignmentFlags for other possible values.
+ */
+ kMyMoneyLineEdit(QWidget *w = 0, const char* name = 0, bool forceMonetaryDecimalSymbol = false, int alignment = (AlignLeft | AlignVCenter));
+ ~kMyMoneyLineEdit();
+
+ /**
+ * This method is used to set the value of the widget back to
+ * the one passed using loadText().
+ */
+ void resetText(void);
+
+ /**
+ * This method is used to turn on/off the hint display
+ */
+ void setHint(const QString& hint) { m_hint = hint; };
+
+
+public slots:
+ void loadText(const QString& text);
+
+signals:
+ /**
+ * This signal is emitted when the focus leaves the object and the text
+ * has been changed. The new text is passed as @a str.
+ */
+ void lineChanged(const QString& str);
+
+protected:
+ void focusOutEvent(QFocusEvent *ev);
+
+ /** reimplemented to support the hint display */
+ void drawContents( QPainter *);
+
+ /**
+ * Overridden so that the period key on the numeric keypad always sends
+ * out the currently selected monetary decimal symbol instead of the
+ * key defined by the keymap.
+ *
+ * Example: If you have set the keymap (keyboard layout) as English, then
+ * the numeric keypad will send a period but if you have set the keymap to
+ * be German, the same key will send a comma.
+ *
+ * @param ev pointer to current QKeyEvent
+ */
+ void keyPressEvent(QKeyEvent* ev);
+
+ /**
+ * Overridden so that the period key on the numeric keypad always sends
+ * out the currently selected monetary decimal symbol instead of the
+ * key defined by the keymap.
+ *
+ * Example: If you have set the keymap (keyboard layout) as English, then
+ * the numeric keypad will send a period but if you have set the keymap to
+ * be German, the same key will send a comma.
+ *
+ * @param ev pointer to current QKeyEvent
+ */
+ void keyReleaseEvent(QKeyEvent* ev);
+
+private:
+ /**
+ * This member keeps the initial value. It is used during
+ * resetText() to set the widgets text back to this initial value
+ * and as comparison during focusOutEvent() to emit the lineChanged
+ * signal if the current text is different.
+ */
+ QString m_text;
+
+ /**
+ * This member tells what to display as hint as long as the field is empty
+ */
+ QString m_hint;
+
+ /**
+ * This member keeps the status if overriding the numeric keypad comma key
+ * is requested or not.
+ */
+ bool m_forceMonetaryDecimalSymbol;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneylistviewitem.cpp b/kmymoney2/widgets/kmymoneylistviewitem.cpp
new file mode 100644
index 0000000..26367ad
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneylistviewitem.cpp
@@ -0,0 +1,135 @@
+/***************************************************************************
+ kmymoneylistviewitem - description
+ -------------------
+ begin : Wed Jun 28 2006
+ copyright : (C) 2000-2006 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpalette.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneylistviewitem.h"
+#include "kmymoneychecklistitem.h"
+#include "../kmymoneyglobalsettings.h"
+
+KMyMoneyListViewItem::KMyMoneyListViewItem(QListView* parent, const QString& txt, const QString& key, const QString& id) :
+ KListViewItem(parent, txt),
+ m_key(key),
+ m_id(id),
+ m_isOdd(0),
+ m_isKnown(0)
+{
+ if(key.isEmpty())
+ m_key = txt;
+}
+
+KMyMoneyListViewItem::KMyMoneyListViewItem(QListViewItem* parent, const QString& txt, const QString& key, const QString& id) :
+ KListViewItem(parent, txt),
+ m_key(key),
+ m_id(id),
+ m_isOdd(0),
+ m_isKnown(0)
+{
+ if(key.isEmpty())
+ m_key = txt;
+}
+
+KMyMoneyListViewItem::~KMyMoneyListViewItem()
+{
+}
+
+QString KMyMoneyListViewItem::key(int column, bool ascending) const
+{
+ Q_UNUSED(ascending);
+
+ if(column == 0)
+ return m_key[0] + text(0);
+ return m_key.mid(1);
+}
+
+
+void KMyMoneyListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
+{
+ QColorGroup _cg = cg;
+ _cg.setColor(QColorGroup::Base, backgroundColor());
+
+ // make sure to bypass KListViewItem::paintCell() as
+ // we don't like it's logic - that's why we do this
+ // here ;-) (ipwizard)
+ QListViewItem::paintCell(p, _cg, column, width, alignment);
+}
+
+const QColor KMyMoneyListViewItem::backgroundColor()
+{
+ return isAlternate() ? KMyMoneyGlobalSettings::listBGColor() : KMyMoneyGlobalSettings::listColor();
+}
+
+bool KMyMoneyListViewItem::isAlternate(void)
+{
+// logic taken from KListViewItem::isAlternate()
+ KMyMoneyCheckListItem* ciAbove;
+ KMyMoneyListViewItem* liAbove;
+ ciAbove = dynamic_cast<KMyMoneyCheckListItem*> (itemAbove());
+ liAbove = dynamic_cast<KMyMoneyListViewItem*> (itemAbove());
+
+ m_isKnown = ciAbove ? ciAbove->m_isKnown : (liAbove ? liAbove->m_isKnown : true);
+ if(m_isKnown) {
+ m_isOdd = ciAbove ? !ciAbove->m_isOdd : (liAbove ? !liAbove->m_isOdd : false);
+ } else {
+ KMyMoneyCheckListItem* clItem;
+ KMyMoneyListViewItem* liItem;
+ bool previous = true;
+ if(QListViewItem::parent()) {
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(QListViewItem::parent());
+ liItem = dynamic_cast<KMyMoneyListViewItem*>(QListViewItem::parent());
+ if(clItem)
+ previous = clItem->m_isOdd;
+ else
+ previous = liItem->m_isOdd;
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(QListViewItem::parent()->firstChild());
+ liItem = dynamic_cast<KMyMoneyListViewItem*>(QListViewItem::parent()->firstChild());
+ } else {
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(listView()->firstChild());
+ liItem = dynamic_cast<KMyMoneyListViewItem*>(listView()->firstChild());
+ }
+ while(clItem || liItem) {
+ if(clItem) {
+ clItem->m_isOdd = previous = !previous;
+ clItem->m_isKnown = true;
+ liItem = dynamic_cast<KMyMoneyListViewItem *>(clItem->nextSibling());
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(clItem->nextSibling());
+ } else if(liItem) {
+ liItem->m_isOdd = previous = !previous;
+ liItem->m_isKnown = true;
+ clItem = dynamic_cast<KMyMoneyCheckListItem *>(liItem->nextSibling());
+ liItem = dynamic_cast<KMyMoneyListViewItem *>(liItem->nextSibling());
+ }
+ }
+ }
+ return m_isOdd;
+}
+
+#include "kmymoneylistviewitem.moc"
diff --git a/kmymoney2/widgets/kmymoneylistviewitem.h b/kmymoney2/widgets/kmymoneylistviewitem.h
new file mode 100644
index 0000000..64f7562
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneylistviewitem.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ kmymoneylistviewitem.h
+ -------------------
+ begin : Wed Jun 28 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYLISTVIEWITEM_H
+#define KMYMONEYLISTVIEWITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KMyMoneyCheckListItem;
+
+/**
+ * This class implements a derived version of a QListViewItem that
+ * allows the storage of an engine object id with the object
+ *
+ * @author Thomas Baumgart
+ */
+class KMyMoneyListViewItem : public QObject, public KListViewItem
+{
+ friend class KMyMoneyCheckListItem;
+
+ Q_OBJECT
+public:
+ KMyMoneyListViewItem(QListView *parent, const QString& txt, const QString& key, const QString& id);
+ KMyMoneyListViewItem(QListViewItem *parent, const QString& txt, const QString& key, const QString& id);
+ ~KMyMoneyListViewItem();
+
+ const QString& id(void) const { return m_id; };
+
+ /**
+ * use my own paint method
+ */
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment);
+
+ /**
+ * use my own backgroundColor method
+ */
+ const QColor backgroundColor();
+
+ /**
+ * This method returns a const reference to the key passed to the constructor. The column
+ * defines what is returned: For @a column equals 0, the first character passed as @a key to
+ * the constructor concatenated with the value returned by text(0) is returned. For @a column
+ * equals to 1, the @a key as passed to the constructor except the first character is returned.
+ */
+ QString key(int column, bool ascending) const;
+
+
+ /**
+ * Reimplemented for internal reasons
+ */
+ bool isAlternate(void);
+
+private:
+ QString m_key;
+ QString m_id;
+ // copied from KListViewItem()
+ unsigned int m_isOdd : 1;
+ unsigned int m_isKnown : 1;
+ unsigned int m_unused : 30;
+
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyonlinequoteconfig.cpp b/kmymoney2/widgets/kmymoneyonlinequoteconfig.cpp
new file mode 100644
index 0000000..125cc13
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyonlinequoteconfig.cpp
@@ -0,0 +1,214 @@
+/***************************************************************************
+ kmymoneyonlinequoteconfig.cpp - description
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyonlinequoteconfig.h"
+#include "../converter/webpricequote.h"
+
+kMyMoneyOnlineQuoteConfig::kMyMoneyOnlineQuoteConfig(QWidget *parent, const char *name )
+ : kMyMoneyOnlineQuoteConfigDecl(parent, name)
+{
+#if 1
+ QStringList groups = WebPriceQuote::quoteSources();
+
+ loadList(true /*updateResetList*/);
+
+ m_updateButton->setEnabled(false);
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem updateButtenItem( i18n("&Update" ),
+ QIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Accepts the entered data and stores it"),
+ i18n("Use this to accept the modified data."));
+ m_updateButton->setGuiItem(updateButtenItem);
+
+ KGuiItem deleteButtenItem( i18n( "&Delete" ),
+ QIconSet(il->loadIcon("editdelete", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Delete the selected source entry"),
+ i18n("Use this to delete the selected online source entry"));
+ m_deleteButton->setGuiItem(deleteButtenItem);
+
+ KGuiItem newButtenItem( i18n( "&New..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new source entry for online quotes"),
+ i18n("Use this to create a new entry for online quotes"));
+ m_newButton->setGuiItem(newButtenItem);
+
+ connect(m_updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateEntry()));
+ connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewEntry()));
+
+ connect(m_quoteSourceList, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotLoadWidgets(QListViewItem*)));
+ connect(m_quoteSourceList, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotLoadWidgets(QListViewItem*)));
+ connect(m_quoteSourceList, SIGNAL(itemRenamed(QListViewItem*,const QString&,int)), this, SLOT(slotEntryRenamed(QListViewItem*,const QString&,int)));
+
+ connect(m_editURL, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editSymbol, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editDate, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editDateFormat, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+ connect(m_editPrice, SIGNAL(textChanged(const QString&)), this, SLOT(slotEntryChanged()));
+
+ // FIXME deleting a source is not yet implemented
+ m_deleteButton->setEnabled(false);
+#endif
+}
+
+void kMyMoneyOnlineQuoteConfig::loadList(const bool updateResetList)
+{
+ QStringList groups = WebPriceQuote::quoteSources();
+
+ if(updateResetList)
+ m_resetList.clear();
+ m_quoteSourceList->clear();
+ QStringList::Iterator it;
+ for(it = groups.begin(); it != groups.end(); ++it) {
+ new QListViewItem(m_quoteSourceList, *it);
+ if(updateResetList)
+ m_resetList += WebPriceQuoteSource(*it);
+ }
+
+ QListViewItem* first = m_quoteSourceList->firstChild();
+ if(first)
+ m_quoteSourceList->setSelected(first, true);
+ slotLoadWidgets(first);
+
+ m_newButton->setEnabled(m_quoteSourceList->findItem(i18n("New Quote Source"), 0) == 0);
+}
+
+void kMyMoneyOnlineQuoteConfig::resetConfig(void)
+{
+ QStringList::ConstIterator it;
+ QStringList groups = WebPriceQuote::quoteSources();
+
+ // delete all currently defined entries
+ for(it = groups.begin(); it != groups.end(); ++it) {
+ WebPriceQuoteSource(*it).remove();
+ }
+
+ // and write back the one's from the reset list
+ QValueList<WebPriceQuoteSource>::ConstIterator itr;
+ for(itr = m_resetList.begin(); itr != m_resetList.end(); ++itr) {
+ (*itr).write();
+ }
+
+ loadList();
+}
+
+void kMyMoneyOnlineQuoteConfig::slotLoadWidgets(QListViewItem* item)
+{
+ m_editURL->setEnabled(true);
+ m_editSymbol->setEnabled(true);
+ m_editPrice->setEnabled(true);
+ m_editDate->setEnabled(true);
+ m_editURL->setText(QString());
+ m_editSymbol->setText(QString());
+ m_editPrice->setText(QString());
+ m_editDate->setText(QString());
+ m_editDateFormat->setText(QString());
+
+ if(item) {
+ m_currentItem = WebPriceQuoteSource(item->text(0));
+ m_editURL->setText(m_currentItem.m_url);
+ m_editSymbol->setText(m_currentItem.m_sym);
+ m_editPrice->setText(m_currentItem.m_price);
+ m_editDate->setText(m_currentItem.m_date);
+ m_editDateFormat->setText(m_currentItem.m_dateformat);
+
+ } else {
+ m_editURL->setEnabled(false);
+ m_editSymbol->setEnabled(false);
+ m_editPrice->setEnabled(false);
+ m_editDate->setEnabled(false);
+ m_editDateFormat->setEnabled(false);
+ }
+
+ m_updateButton->setEnabled(false);
+
+}
+
+void kMyMoneyOnlineQuoteConfig::slotEntryChanged(void)
+{
+ bool modified = m_editURL->text() != m_currentItem.m_url
+ || m_editSymbol->text() != m_currentItem.m_sym
+ || m_editDate->text() != m_currentItem.m_date
+ || m_editDateFormat->text() != m_currentItem.m_dateformat
+ || m_editPrice->text() != m_currentItem.m_price;
+
+ m_updateButton->setEnabled(modified);
+}
+
+void kMyMoneyOnlineQuoteConfig::slotUpdateEntry(void)
+{
+ m_currentItem.m_url = m_editURL->text();
+ m_currentItem.m_sym = m_editSymbol->text();
+ m_currentItem.m_date = m_editDate->text();
+ m_currentItem.m_dateformat = m_editDateFormat->text();
+ m_currentItem.m_price = m_editPrice->text();
+ m_currentItem.write();
+ slotEntryChanged();
+}
+
+void kMyMoneyOnlineQuoteConfig::slotNewEntry(void)
+{
+ WebPriceQuoteSource newSource(i18n("New Quote Source"));
+ newSource.write();
+ loadList();
+ QListViewItem* item = m_quoteSourceList->findItem(i18n("New Quote Source"), 0);
+ if(item) {
+ m_quoteSourceList->setSelected(item, true);
+ slotLoadWidgets(item);
+ }
+}
+
+void kMyMoneyOnlineQuoteConfig::slotEntryRenamed(QListViewItem* item, const QString& text, int /* col */)
+{
+ int nameCount = 0;
+ QListViewItemIterator it(m_quoteSourceList);
+ while(it.current()) {
+ if(it.current()->text(0) == text)
+ ++nameCount;
+ ++it;
+ }
+
+ // Make sure we get a non-empty and unique name
+ if(text.length() > 0 && nameCount == 1) {
+ m_currentItem.rename(text);
+ } else {
+ item->setText(0, m_currentItem.m_name);
+ }
+ m_newButton->setEnabled(m_quoteSourceList->findItem(i18n("New Quote Source"), 0) == 0);
+}
+
+#include "kmymoneyonlinequoteconfig.moc"
diff --git a/kmymoney2/widgets/kmymoneyonlinequoteconfig.h b/kmymoney2/widgets/kmymoneyonlinequoteconfig.h
new file mode 100644
index 0000000..f00cbdb
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyonlinequoteconfig.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ kmymoneyonlinequoteconfig.h - description
+ -------------------
+ begin : Thu Dec 30 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYONLINEQUOTECONFIG_H
+#define KMYMONEYONLINEQUOTECONFIG_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../widgets/kmymoneyonlinequoteconfigdecl.h"
+#include "../converter/webpricequote.h"
+
+class kMyMoneyOnlineQuoteConfig : public kMyMoneyOnlineQuoteConfigDecl
+{
+ Q_OBJECT
+public:
+ kMyMoneyOnlineQuoteConfig(QWidget* parent, const char *name);
+ virtual ~kMyMoneyOnlineQuoteConfig() {}
+
+ void writeConfig(void) {}
+ void readConfig(void) {}
+ void resetConfig(void);
+
+protected slots:
+ void slotUpdateEntry(void);
+ void slotLoadWidgets(QListViewItem* item);
+ void slotEntryChanged(void);
+ void slotNewEntry(void);
+ void slotEntryRenamed(QListViewItem* item, const QString& text, int col);
+
+protected:
+ void loadList(const bool updateResetList = false);
+
+private:
+ QValueList<WebPriceQuoteSource> m_resetList;
+ WebPriceQuoteSource m_currentItem;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyonlinequoteconfigdecl.ui b/kmymoney2/widgets/kmymoneyonlinequoteconfigdecl.ui
new file mode 100644
index 0000000..0131edd
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyonlinequoteconfigdecl.ui
@@ -0,0 +1,231 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kMyMoneyOnlineQuoteConfigDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyOnlineQuoteConfigDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>594</width>
+ <height>487</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Online Quotes</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_quoteSourceList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ <property name="itemsRenameable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupParsing</cstring>
+ </property>
+ <property name="title">
+ <string>Details</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Symbol</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_editSymbol</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the symbol from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_editPrice</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the price from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_editDateFormat</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the date from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_editURL</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>URL to be used to download the quote</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the URL from which stock quotes will be fetched. &lt;b&gt;%1&lt;/b&gt; will be replaced with the symbol for the security being quoted. For currency conversions, &lt;b&gt;%2&lt;/b&gt; will be replaced with the currency to be quoted and &lt;b&gt;%1&lt;/b&gt; with the currency the quote is based on.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>m_editDate</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Regular Expression to extract the date from the downloaded data</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Date Format</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;Enter regular expressions which can be used to parse the data returned from the URL entered above. The symbol, price, and date must be found in the quote data to be usable. You may also try the KMyMoney user's mailinglist at &lt;a href="mailto:kmymoney2-user@lists.sourceforge.net"&gt;kmymoney2-user@lists.sourceforge.net&lt;/a&gt; to find what settings work for other users in your country.&lt;/i&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_newButton</cstring>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_deleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>240</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_updateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Update</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneypriceview.cpp b/kmymoney2/widgets/kmymoneypriceview.cpp
new file mode 100644
index 0000000..1b884d2
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneypriceview.cpp
@@ -0,0 +1,343 @@
+/***************************************************************************
+ kmymoneypriceview.cpp - description
+ -------------------
+ begin : Wed Mar 24 2004
+ copyright : (C) 2000-2004 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qheader.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneypriceview.h"
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyfile.h>
+#include "../kmymoneyglobalsettings.h"
+#if 0
+#include "../widgets/kmymoneycurrencyselector.h"
+#include "../dialogs/kupdatestockpricedlg.h"
+#include "../dialogs/kcurrencycalculator.h"
+#include "../dialogs/kequitypriceupdatedlg.h"
+#include "../kmymoneyutils.h"
+#include "../mymoney/mymoneyfile.h"
+#endif
+
+#define COMMODITY_COL 0
+#define CURRENCY_COL 1
+#define DATE_COL 2
+#define PRICE_COL 3
+#define SOURCE_COL 4
+
+KMyMoneyPriceItem::KMyMoneyPriceItem(KListView *view, const MyMoneyPrice& pr) :
+ KMyMoneyListViewItem(view, QString(), QString(), QString()),
+ m_pr(pr)
+{
+ MyMoneySecurity from, to;
+ KConfig *kconfig = KGlobal::config();
+ kconfig->setGroup("General Options");
+ int prec = kconfig->readNumEntry("PricePrecision", 4);
+
+ if(!m_pr.isValid())
+ m_pr = MyMoneyFile::instance()->price(m_pr.from(), m_pr.to(), m_pr.date());
+
+ if(m_pr.isValid()) {
+ QString priceBase = m_pr.to();
+ from = MyMoneyFile::instance()->security(m_pr.from());
+ to = MyMoneyFile::instance()->security(m_pr.to());
+ if(!to.isCurrency()) {
+ from = MyMoneyFile::instance()->security(m_pr.to());
+ to = MyMoneyFile::instance()->security(m_pr.from());
+ priceBase = m_pr.from();
+ }
+
+ setText(COMMODITY_COL, (from.isCurrency()) ? from.id() : from.tradingSymbol());
+ setText(CURRENCY_COL, to.id());
+ setText(DATE_COL, KGlobal::locale()->formatDate(m_pr.date(), true));
+ setText(PRICE_COL, m_pr.rate(priceBase).formatMoney("", prec));
+ setText(SOURCE_COL, m_pr.source());
+ }
+}
+
+int KMyMoneyPriceItem::compare(QListViewItem* i, int col, bool ascending) const
+{
+ KMyMoneyPriceItem* item = static_cast<KMyMoneyPriceItem*>(i);
+ int rc = 0;
+
+ switch(col) {
+ case DATE_COL: // date
+ if(m_pr.date() > item->m_pr.date())
+ rc = 1;
+ else if(m_pr.date() < item->m_pr.date())
+ rc = -1;
+ break;
+
+ case PRICE_COL: // value
+ if(m_pr.rate(QString()) > item->m_pr.rate(QString()))
+ rc = 1;
+ else if(m_pr.rate(QString()) < item->m_pr.rate(QString()))
+ rc = -1;
+ break;
+
+ default:
+ rc = QListViewItem::compare(i, col, ascending);
+ break;
+ }
+ return rc;
+}
+
+KMyMoneyPriceView::KMyMoneyPriceView(QWidget *parent, const char *name ) :
+ KListView(parent,name),
+ m_contextMenu(0),
+ m_showAll(false)
+{
+ addColumn(i18n("Commodity"));
+ addColumn(i18n("Currency"));
+ addColumn(i18n("Date"));
+ addColumn(i18n("Price"));
+ addColumn(i18n("Source"));
+ setAllColumnsShowFocus(true);
+ setMultiSelection(false);
+ setColumnWidthMode(0, QListView::Maximum);
+ setColumnWidthMode(1, QListView::Maximum);
+ setShowSortIndicator(true);
+ setSorting(COMMODITY_COL);
+
+ header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
+
+ KIconLoader *kiconloader = KGlobal::iconLoader();
+
+ m_contextMenu = new KPopupMenu(this);
+ m_contextMenu->insertTitle(i18n("Price Options"));
+ m_contextMenu->insertItem(kiconloader->loadIcon("filenew", KIcon::Small),
+ i18n("New..."),
+ this, SIGNAL(newPrice()));
+
+ m_contextMenu->insertItem(kiconloader->loadIcon("edit", KIcon::Small),
+ i18n("Edit..."),
+ this, SIGNAL(editPrice()));
+
+ m_contextMenu->insertItem(kiconloader->loadIcon("connect_creating", KIcon::Small),
+ i18n("Online Price Update..."),
+ this, SIGNAL(onlinePriceUpdate()));
+
+ m_contextMenu->insertItem(kiconloader->loadIcon("delete", KIcon::Small),
+ i18n("Delete..."),
+ this, SIGNAL(deletePrice()));
+
+ connect(this, SIGNAL(rightButtonClicked(QListViewItem* , const QPoint&, int)),
+ this, SLOT(slotListClicked(QListViewItem*, const QPoint&, int)));
+
+ // connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadWidget()));
+
+ // slotReloadWidget();
+
+ // If the widget is shown, the size must be fixed a little later
+ // to be appropriate. I saw this in some other places and the only
+ // way to solve this problem is to postpone the setup of the size
+ // to the time when the widget is on the screen.
+ resize(width()-1, height()-1);
+ QTimer::singleShot(50, this, SLOT(slotTimerDone()));
+}
+
+KMyMoneyPriceView::~KMyMoneyPriceView()
+{
+}
+
+void KMyMoneyPriceView::slotTimerDone(void)
+{
+ // the resize operation does the trick to adjust
+ // all widgets in the view to the size they should
+ // have and show up correctly. Don't ask me, why
+ // this is, but it cured the problem (ipwizard).
+ resize(width()+1, height()+1);
+}
+
+#if 0
+void KMyMoneyPriceView::slotReloadWidget(void)
+{
+ m_priceHistory->clear();
+
+ MyMoneyPriceList list = MyMoneyFile::instance()->priceList();
+ MyMoneyPriceList::ConstIterator it_l;
+ for(it_l = list.begin(); it_l != list.end(); ++it_l) {
+ MyMoneyPriceEntries::ConstIterator it_e;
+ if(m_showAll) {
+ for(it_e = (*it_l).begin(); it_e != (*it_l).end(); ++it_e) {
+ new kMyMoneyPriceItem(m_priceHistory, *it_e);
+ }
+ } else {
+ if((*it_l).count() > 0) {
+ it_e = (*it_l).end();
+ --it_e;
+ new kMyMoneyPriceItem(m_priceHistory, *it_e);
+ }
+ }
+ }
+}
+#endif
+
+void KMyMoneyPriceView::resizeEvent(QResizeEvent* e)
+{
+ int w = visibleWidth()/5;
+
+ setColumnWidth(0, w);
+ setColumnWidth(1, w);
+ setColumnWidth(2, w);
+ setColumnWidth(3, w);
+ setColumnWidth(4, w);
+ resizeContents(visibleWidth(), contentsHeight());
+
+ KListView::resizeEvent(e);
+}
+
+void KMyMoneyPriceView::slotListClicked(QListViewItem* item, const QPoint&, int)
+{
+ int editId = m_contextMenu->idAt(2);
+ int updateId = m_contextMenu->idAt(3);
+ int delId = m_contextMenu->idAt(4);
+
+ m_contextMenu->setItemEnabled(editId, item != 0);
+ m_contextMenu->setItemEnabled(delId, item != 0);
+
+ KMyMoneyPriceItem* priceitem = dynamic_cast<KMyMoneyPriceItem*>(item);
+ if(priceitem) {
+ MyMoneySecurity security;
+ security = MyMoneyFile::instance()->security(priceitem->price().from());
+ m_contextMenu->setItemEnabled(updateId, security.isCurrency() );
+
+ // Modification of automatically added entries is not allowed
+ if(priceitem->price().source() == "KMyMoney") {
+ m_contextMenu->setItemEnabled(editId, false);
+ m_contextMenu->setItemEnabled(updateId, false);
+ m_contextMenu->setItemEnabled(delId, false);
+ }
+ }
+ else
+ m_contextMenu->setItemEnabled(updateId, false );
+
+ m_contextMenu->exec(QCursor::pos());
+}
+
+#if 0
+void KMyMoneyPriceView::slotNewPrice(void)
+{
+ KUpdateStockPriceDlg dlg(this);
+ kMyMoneyPriceItem* item = dynamic_cast<kMyMoneyPriceItem*>(m_priceHistory->selectedItem());
+ if(item) {
+ MyMoneySecurity security;
+ security = MyMoneyFile::instance()->security(item->price().from());
+ dlg.m_security->setSecurity(security);
+ security = MyMoneyFile::instance()->security(item->price().to());
+ dlg.m_currency->setSecurity(security);
+ }
+ if(dlg.exec()) {
+ MyMoneyPrice price(dlg.m_security->security().id(), dlg.m_currency->security().id(), dlg.date(), MyMoneyMoney(1,1));
+ kMyMoneyPriceItem* p = new kMyMoneyPriceItem(m_priceHistory, price);
+ m_priceHistory->setSelected(p, true);
+ // If the user cancels the following operation, we delete the new item
+ // and re-select any previously selected one
+ if(slotEditPrice() == QDialog::Rejected) {
+ delete p;
+ if(item)
+ m_priceHistory->setSelected(item, true);
+ }
+ }
+}
+
+int KMyMoneyPriceView::slotEditPrice(void)
+{
+ int rc = QDialog::Rejected;
+ kMyMoneyPriceItem* item = dynamic_cast<kMyMoneyPriceItem*>(m_priceHistory->selectedItem());
+ if(item) {
+ MyMoneySecurity from(MyMoneyFile::instance()->security(item->price().from()));
+ MyMoneySecurity to(MyMoneyFile::instance()->security(item->price().to()));
+ signed64 fract = MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision());
+
+ KCurrencyCalculator calc(from,
+ to,
+ MyMoneyMoney(1,1),
+ item->price().rate(),
+ item->price().date(),
+ fract,
+ this, "currencyCalculator");
+ // we always want to update the price, that's why we're here
+ calc.m_updateButton->setChecked(true);
+ calc.m_updateButton->hide();
+
+ rc = calc.exec();
+ }
+ return rc;
+}
+
+void KMyMoneyPriceView::slotDeletePrice(void)
+{
+ kMyMoneyPriceItem* item = dynamic_cast<kMyMoneyPriceItem*>(m_priceHistory->selectedItem());
+ if(item) {
+ if(KMessageBox::questionYesNo(this, i18n("Do you really want to delete the selected price entry?"), i18n("Delete price information"), KStdGuiItem::yes(), KStdGuiItem::no(), "DeletePrice") == KMessageBox::Yes) {
+ MyMoneyFileTransaction ft;
+ try {
+ MyMoneyFile::instance()->removePrice(item->price());
+ ft.commit();
+ } catch(MyMoneyException *e) {
+ qDebug("Cannot delete price");
+ delete e;
+ }
+ }
+ }
+}
+
+void KMyMoneyPriceView::slotShowAllPrices(bool enabled)
+{
+ if(m_showAll != enabled) {
+ m_showAll = enabled;
+ slotReloadWidget();
+ }
+}
+
+void KMyMoneyPriceView::slotOnlinePriceUpdate(void)
+{
+ KMyMoneyPriceItem* item = dynamic_cast<KMyMoneyPriceItem*>(m_priceHistory->selectedItem());
+ if(item)
+ {
+ KEquityPriceUpdateDlg dlg(this, (item->text(COMMODITY_COL)+" "+item->text(CURRENCY_COL)).utf8());
+ if(dlg.exec() == QDialog::Accepted)
+ dlg.storePrices();
+ }
+}
+
+#endif
+
+#include "kmymoneypriceview.moc"
diff --git a/kmymoney2/widgets/kmymoneypriceview.h b/kmymoney2/widgets/kmymoneypriceview.h
new file mode 100644
index 0000000..56907ac
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneypriceview.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ kmymoneypriceview.h - description
+ -------------------
+ begin : Wed Mar 24 2004
+ copyright : (C) 2004 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYPRICEVIEW_H
+#define KMYMONEYPRICEVIEW_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+// class QListViewItem;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kpopupmenu.h>
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneylistviewitem.h>
+//#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneyprice.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KMyMoneyPriceItem : public KMyMoneyListViewItem
+{
+public:
+ KMyMoneyPriceItem(KListView *, const MyMoneyPrice& pr);
+ ~KMyMoneyPriceItem() {}
+
+ int compare(QListViewItem *p, int col, bool ascending) const;
+
+ const MyMoneyPrice& price(void) const { return m_pr; };
+
+private:
+ MyMoneyPrice m_pr;
+};
+
+
+class KMyMoneyPriceView : public KListView
+{
+ Q_OBJECT
+public:
+ KMyMoneyPriceView(QWidget *parent=0, const char *name=0);
+ ~KMyMoneyPriceView();
+
+protected:
+ /// the resize event
+ virtual void resizeEvent(QResizeEvent*);
+
+protected slots:
+ void slotListClicked(QListViewItem* item, const QPoint&, int);
+
+private slots:
+ void slotTimerDone(void);
+
+signals:
+ void newPrice(void);
+ void deletePrice(void);
+ void editPrice(void);
+ void onlinePriceUpdate(void);
+
+private:
+ KPopupMenu* m_contextMenu;
+ bool m_showAll;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyreportconfigtab1decl.ui b/kmymoney2/widgets/kmymoneyreportconfigtab1decl.ui
new file mode 100644
index 0000000..0d94537
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyreportconfigtab1decl.ui
@@ -0,0 +1,123 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kMyMoneyReportConfigTab1Decl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyReportConfigTab1Decl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>172</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Report Tab</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;On this tab, you set the basic properties of this report.&lt;/p&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout35</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Report Name</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_editName</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose a name for this report.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout36</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Comment</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_editComment</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Enter a comment to help you remember the details of this report.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkCurrency</cstring>
+ </property>
+ <property name="text">
+ <string>Convert values to base currency</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to convert all values in the report to your base currency.&lt;/p&gt;&lt;p&gt;Leave it unchecked if you'd like to see values in their original currency.&lt;/p&gt;&lt;p&gt;If currencies are not converted, then subtotals will not be shown.&lt;/p&gt;</string>
+ <comment>Convert 'em!!</comment>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkFavorite</cstring>
+ </property>
+ <property name="text">
+ <string>Mark as a favorite report</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to notate this report as one of your favorites.&lt;/p&gt;&lt;p&gt;All your favorite reports are grouped in one place on the report list for easy access.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneyreportconfigtab2decl.ui b/kmymoney2/widgets/kmymoneyreportconfigtab2decl.ui
new file mode 100644
index 0000000..1ad7cf0
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyreportconfigtab2decl.ui
@@ -0,0 +1,282 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>kMyMoneyReportConfigTab2Decl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyReportConfigTab2Decl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>278</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Rows/Columns Tab</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;On this tab, you configure how you'd like the rows and columns to be selected and organized.&lt;/p&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Detail</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>All</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Top-Level</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Groups</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Totals</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboDetail</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose what kind of accounts to display as the rows of this report.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QFrame" row="0" column="2">
+ <property name="name">
+ <cstring>m_budgetFrame</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Budget</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo">
+ <property name="name">
+ <cstring>m_comboBudget</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Columns</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Daily</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Weekly</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Monthly</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Bi-Monthly</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Quarterly</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Yearly</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboColumns</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose how large of a time period each column should encompass&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Income &amp; Expenses</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Assets &amp; Liabilities</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboRows</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose what kind of accounts to display as the rows of this report.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Rows</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_checkTotalColumn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Show totals column</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel10</cstring>
+ </property>
+ <property name="text">
+ <string>Average days</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="4" column="1">
+ <property name="name">
+ <cstring>m_movingAverageDays</cstring>
+ </property>
+ <property name="maxValue">
+ <number>366</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>94</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkScheduled</cstring>
+ </property>
+ <property name="text">
+ <string>Include scheduled transactions</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkTransfers</cstring>
+ </property>
+ <property name="text">
+ <string>Include transfers</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkUnused</cstring>
+ </property>
+ <property name="text">
+ <string>Include unused accounts/categories</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneyreportconfigtab3decl.ui b/kmymoney2/widgets/kmymoneyreportconfigtab3decl.ui
new file mode 100644
index 0000000..2284c1f
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyreportconfigtab3decl.ui
@@ -0,0 +1,437 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>kMyMoneyReportConfigTab3Decl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyReportConfigTab3Decl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>617</width>
+ <height>267</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Rows/Columns Tab</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;On this tab, you configure how you'd like the rows and columns to be selected and organized.&lt;/p&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ </font>
+ </property>
+ <property name="text">
+ <string>Organize by:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Categories</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Top Categories</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Payees</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Accounts</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Top Accounts</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Month</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Week</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboOrganizeBy</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose how to group the transactions in this report&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>358</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Show Columns</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Choose which columns should be shown in the report.&lt;/p&gt;&lt;p&gt;The date and transaction amount are always shown.&lt;/p&gt;</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_checkMemo</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Memo</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Memo column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="3">
+ <property name="name">
+ <cstring>m_checkShares</cstring>
+ </property>
+ <property name="text">
+ <string>Shares</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Shares column for investments&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="3">
+ <property name="name">
+ <cstring>m_checkPrice</cstring>
+ </property>
+ <property name="text">
+ <string>Price</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Price column for investments&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="2">
+ <property name="name">
+ <cstring>m_checkReconciled</cstring>
+ </property>
+ <property name="text">
+ <string>Reconciled</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Reconciled column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="2">
+ <property name="name">
+ <cstring>m_checkAccount</cstring>
+ </property>
+ <property name="text">
+ <string>Account</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Account column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_checkNumber</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Number</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Number column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>m_checkPayee</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Payee</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Payee column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_checkCategory</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Category</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Category column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="4">
+ <property name="name">
+ <cstring>m_checkAction</cstring>
+ </property>
+ <property name="text">
+ <string>Action</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Action column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="4">
+ <property name="name">
+ <cstring>m_checkBalance</cstring>
+ </property>
+ <property name="text">
+ <string>Balance</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show the Running balance column&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>205</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>m_checkLoans</cstring>
+ </property>
+ <property name="text">
+ <string>Include only Loan accounts</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>m_checkInvestments</cstring>
+ </property>
+ <property name="text">
+ <string>Include only Investment accounts</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Check this box to include only those categories which have been marked to "Include on Tax Reports"&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_checkHideSplitDetails</cstring>
+ </property>
+ <property name="text">
+ <string>Hide Split Transaction Details</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Do not display the individual transactions that make up a split transaction</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_checkTax</cstring>
+ </property>
+ <property name="text">
+ <string>Include only Tax categories</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Check this box to include only those categories which have been marked to "Include on Tax Reports"&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_checkTax</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_checkInvestments</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkTax</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_checkLoans</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkInvestments</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_checkTax</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkInvestments</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_checkLoans</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkLoans</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_checkTax</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkLoans</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_checkInvestments</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneyreportconfigtabchartdecl.ui b/kmymoney2/widgets/kmymoneyreportconfigtabchartdecl.ui
new file mode 100644
index 0000000..2aa9126
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyreportconfigtabchartdecl.ui
@@ -0,0 +1,214 @@
+<!DOCTYPE UI><UI version="3.0">
+<class>kMyMoneyReportConfigTabChartDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyReportConfigTabChartDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>174</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Chart Tab</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;On this tab, you configure the chart drawn forthis report.&lt;/p&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Chart Type</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select what form you would like the chart to be drawn as.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Line</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Bar</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Stacked Bar</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Pie</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ring</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboType</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>121</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkGridLines</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid lines</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to show horizontal and vertical grid lines on the chart.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkValues</cstring>
+ </property>
+ <property name="text">
+ <string>Draw values on chart</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to draw the numeric values for data points next to their plot location.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkShowChart</cstring>
+ </property>
+ <property name="text">
+ <string>Show as chart by default</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select this option to cause the report to be shown as a chart when you first open the report. Otherwise, it will come up as a text report.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Line width</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;p&gt;Select what width should be used to draw the line on the chart&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_lineWidth</cstring>
+ </property>
+ <property name="maxValue">
+ <number>10</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>121</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneyreportcontroldecl.ui b/kmymoney2/widgets/kmymoneyreportcontroldecl.ui
new file mode 100644
index 0000000..2d0e0e3
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyreportcontroldecl.ui
@@ -0,0 +1,150 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>kMyMoneyReportControlDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kMyMoneyReportControlDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>33</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>ReportControl</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonChart</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Chart</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Show the chart version of this report</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonConfigure</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Configure this report</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonNew</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Create a new report based on this one</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCopy</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Copy</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Copy this report to the clipboard</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonExport</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Export</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Export this report as an HTML or CSV file</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonDelete</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Permanently delete this report</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonClose</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Close this window</string>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/kmymoneyscheduledcalendar.cpp b/kmymoney2/widgets/kmymoneyscheduledcalendar.cpp
new file mode 100644
index 0000000..6c17a33
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyscheduledcalendar.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+ kmymoneyscheduledcalendar.cpp - description
+ -------------------
+ begin : Wed Jul 2 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qpushbutton.h>
+#include <qkeysequence.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "../widgets/kmymoneyscheduledcalendar.h"
+#include "../mymoney/mymoneyfile.h"
+
+kMyMoneyScheduledCalendar::kMyMoneyScheduledCalendar(QWidget *parent, const char *name )
+ : kMyMoneyCalendar(parent,name)
+{
+ QPushButton *pb1 = new QPushButton(i18n("Select Schedules"), this);
+
+ kpopupmenu = new KPopupMenu(this);
+ kpopupmenu->setCheckable(true);
+ kpopupmenu->insertItem(i18n("Bills"), 0);
+ kpopupmenu->insertItem(i18n("Deposits"), 1);
+ kpopupmenu->insertItem(i18n("Transfers"), 2);
+ kpopupmenu->connectItem(0, this, SLOT(slotSetViewBills()));
+ kpopupmenu->connectItem(1, this, SLOT(slotSetViewDeposits()));
+ kpopupmenu->connectItem(2, this, SLOT(slotSetViewTransfers()));
+ kpopupmenu->setItemChecked(0, true);
+ kpopupmenu->setItemChecked(1, true);
+ kpopupmenu->setItemChecked(2, true);
+ pb1->setPopup(kpopupmenu);
+
+ m_scheduledDateTable = new kMyMoneyScheduledDateTbl(this);
+ setDateTable((kMyMoneyDateTbl*)m_scheduledDateTable);
+
+ setUserButton1(true, pb1);
+
+ init( QDate::currentDate() );
+
+ connect(m_scheduledDateTable, SIGNAL(enterClicked(const MyMoneySchedule&, const QDate&)),
+ this, SIGNAL(enterClicked(const MyMoneySchedule&, const QDate&)));
+ connect(m_scheduledDateTable, SIGNAL(skipClicked(const MyMoneySchedule&, const QDate&)),
+ this, SIGNAL(skipClicked(const MyMoneySchedule&, const QDate&)));
+}
+
+kMyMoneyScheduledCalendar::~kMyMoneyScheduledCalendar()
+{
+}
+
+void kMyMoneyScheduledCalendar::slotSetViewBills()
+{
+ kpopupmenu->setItemChecked(0, ((kpopupmenu->isItemChecked(0)) ? false : true));
+ m_scheduledDateTable->filterBills(!kpopupmenu->isItemChecked(0));
+}
+
+void kMyMoneyScheduledCalendar::slotSetViewDeposits()
+{
+ kpopupmenu->setItemChecked(1, ((kpopupmenu->isItemChecked(1)) ? false : true));
+ m_scheduledDateTable->filterDeposits(!kpopupmenu->isItemChecked(1));
+}
+
+void kMyMoneyScheduledCalendar::slotSetViewTransfers()
+{
+ kpopupmenu->setItemChecked(2, ((kpopupmenu->isItemChecked(2)) ? false : true));
+ m_scheduledDateTable->filterTransfers(!kpopupmenu->isItemChecked(2));
+}
+
+#include "kmymoneyscheduledcalendar.moc"
diff --git a/kmymoney2/widgets/kmymoneyscheduledcalendar.h b/kmymoney2/widgets/kmymoneyscheduledcalendar.h
new file mode 100644
index 0000000..1543b5a
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyscheduledcalendar.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ kmymoneyscheduledcalendar.h - description
+ -------------------
+ begin : Wed Jul 2 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYSCHEDULEDCALENDAR_H
+#define KMYMONEYSCHEDULEDCALENDAR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../widgets/kmymoneycalendar.h"
+#include "../widgets/kmymoneyscheduleddatetbl.h"
+
+class KPopupMenu;
+class kMyMoneyDateTbl;
+
+/**
+ * A representation of a calendar.
+ *
+ * Uses the base class kMyMoneyCalendar to actually render
+ * the calendar.
+ *
+ * @author Michael Edwardes 2003
+ *
+**/
+class kMyMoneyScheduledCalendar : public kMyMoneyCalendar {
+ Q_OBJECT
+
+public:
+ /**
+ * Standard constructor.
+ **/
+ kMyMoneyScheduledCalendar(QWidget *parent=0, const char *name=0);
+
+ /**
+ * Standard destructor.
+ **/
+ ~kMyMoneyScheduledCalendar();
+
+ /**
+ * Dynamically set the Date Table
+ **/
+ void setDateTable(kMyMoneyDateTbl* tbl) { table = tbl; }
+
+ void refresh() { m_scheduledDateTable->refresh(); }
+
+ void setFilterAccounts(const QStringList& list) { m_scheduledDateTable->setFilterAccounts(list); }
+
+signals:
+ void enterClicked(const MyMoneySchedule&, const QDate&);
+ void skipClicked(const MyMoneySchedule&, const QDate&);
+
+protected slots:
+ void slotSetViewBills();
+ void slotSetViewDeposits();
+ void slotSetViewTransfers();
+
+private:
+ KPopupMenu* kpopupmenu;
+ kMyMoneyScheduledDateTbl *m_scheduledDateTable;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyscheduleddatetbl.cpp b/kmymoney2/widgets/kmymoneyscheduleddatetbl.cpp
new file mode 100644
index 0000000..870abd5
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyscheduleddatetbl.cpp
@@ -0,0 +1,530 @@
+/***************************************************************************
+ kmymoneyscheduleddatetbl.cpp - description
+ -------------------
+ begin : Thu Jul 3 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+ /****************************************************************************
+ Contains code from the KDateTable class ala kdelibs-3.1.2. Original license:
+
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
+ (C) 1998-2001 Mirko Boehm (mirko@kde.org)
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qstring.h>
+#include <qpen.h>
+#include <qpainter.h>
+#include <qdialog.h>
+#include <qdrawutil.h>
+#include <qcursor.h>
+#include <qapplication.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include "kdecompat.h"
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#include "kmymoneyscheduleddatetbl.h"
+#include "../mymoney/mymoneyfile.h"
+
+kMyMoneyScheduledDateTbl::kMyMoneyScheduledDateTbl(QWidget *parent, QDate date_, const char* name, WFlags f )
+ : kMyMoneyDateTbl(parent, date_, name, f),
+ m_filterBills(false), m_filterDeposits(false), m_filterTransfers(false)
+{
+ connect(&briefWidget, SIGNAL(enterClicked(const MyMoneySchedule&, const QDate&)), this, SIGNAL(enterClicked(const MyMoneySchedule&, const QDate&)));
+ connect(&briefWidget, SIGNAL(skipClicked(const MyMoneySchedule&, const QDate&)), this, SIGNAL(skipClicked(const MyMoneySchedule&, const QDate&)));
+}
+
+kMyMoneyScheduledDateTbl::~kMyMoneyScheduledDateTbl()
+{
+}
+
+void kMyMoneyScheduledDateTbl::drawCellContents(QPainter *painter, int /*row*/, int /*col*/, const QDate& theDate)
+{
+ QRect rect;
+ QString text;
+ int w=cellWidth();
+ int h=cellHeight();
+ QPen pen;
+ QBrush brushBlue(KGlobalSettings::activeTitleColor());
+ QBrush brushLightblue(KGlobalSettings::baseColor());
+ QFont font=KGlobalSettings::generalFont();
+ MyMoneyFile *file = MyMoneyFile::instance();
+
+ // -----
+ font.setPointSize(fontsize);
+ QFont fontLarge(font);
+ QFont fontSmall(font);
+ fontLarge.setPointSize(fontsize*2);
+ fontSmall.setPointSize(fontsize-1);
+
+ painter->setFont(font);
+
+
+ if (m_type == MONTHLY)
+ {
+ if (theDate.month() != date.month())
+ {
+ painter->setFont(fontSmall);
+ pen = lightGray;
+ }
+ else
+ {
+ pen = gray;
+ }
+
+ if (theDate == date)
+ {
+ if (hasFocus())
+ { // draw the currently selected date
+ painter->setPen(KGlobalSettings::highlightColor());
+ painter->setBrush(KGlobalSettings::highlightColor());
+ pen=white;
+ } else {
+ painter->setPen(KGlobalSettings::calculateAlternateBackgroundColor(KGlobalSettings::highlightColor()));
+ painter->setBrush(KGlobalSettings::calculateAlternateBackgroundColor(KGlobalSettings::highlightColor()));
+ pen=white;
+ }
+ } else {
+ painter->setBrush(KGlobalSettings::baseColor());
+ painter->setPen(KGlobalSettings::baseColor());
+ }
+ painter->drawRect(0, 0, w, h);
+ painter->setPen(pen);
+ text = QString::number(theDate.day());
+ addDayPostfix(text);
+ painter->drawText(0, 0, w-2, h, AlignRight, text, -1, &rect);
+
+ MyMoneyFile *file = MyMoneyFile::instance();
+ QValueList<MyMoneySchedule> schedules;
+ try
+ {
+
+ // Honour the filter.
+ int scheduleTypes=0;
+ int scheduleOcurrences=0;
+ int schedulePaymentTypes=0;
+
+ scheduleOcurrences |= MyMoneySchedule::OCCUR_ANY;
+ schedulePaymentTypes |= MyMoneySchedule::STYPE_ANY;
+
+ if (!m_filterBills)
+ {
+ scheduleTypes |= MyMoneySchedule::TYPE_BILL;
+ }
+ if (!m_filterDeposits)
+ {
+ scheduleTypes |= MyMoneySchedule::TYPE_DEPOSIT;
+ }
+ if (!m_filterTransfers)
+ {
+ scheduleTypes |= MyMoneySchedule::TYPE_TRANSFER;
+ }
+
+ schedules = file->scheduleListEx( scheduleTypes,
+ scheduleOcurrences,
+ schedulePaymentTypes,
+ theDate,
+ m_filterAccounts);
+ }
+ catch ( MyMoneyException* e)
+ {
+ // SAfe to ignore here, cause no schedules might exist
+ // for the selected account
+ delete e;
+ }
+
+ if (schedules.count() >= 1)
+ {
+ QValueList<MyMoneySchedule>::Iterator iter;
+ bool anyOverdue=false;
+ for (iter=schedules.begin(); iter!=schedules.end(); ++iter)
+ {
+ MyMoneySchedule schedule = *iter;
+ if (theDate < QDate::currentDate())
+ {
+ if (schedule.isOverdue())
+ {
+ anyOverdue = true;
+ break; // out early
+ }
+ }
+ }
+
+ if (anyOverdue)
+ painter->setPen(red);
+ else
+ painter->setPen(darkGray);
+
+ painter->setFont(fontLarge);
+ painter->drawText(0, 0, w, h, AlignCenter, QString::number(schedules.count()),
+ -1, &rect);
+ }
+
+ painter->setPen(lightGray);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(0, 0, w, h);
+ }
+ else if (m_type == WEEKLY)
+ {
+ // TODO: Handle other start weekdays than Monday
+ if (theDate == date)
+ {
+ painter->setBrush(KGlobalSettings::highlightColor());
+ }
+ else
+ {
+ painter->setBrush(KGlobalSettings::baseColor());
+ painter->setPen(KGlobalSettings::baseColor());
+ }
+
+ painter->setPen(lightGray);
+ painter->drawRect(0, 0, w, h);
+
+ text = QString::number(theDate.day());
+ addDayPostfix(text);
+
+ painter->drawText(0, 0, w-2, h, AlignRight, QDate::shortDayName(theDate.dayOfWeek()) + " " + text, -1, &rect);
+
+ QValueList<MyMoneySchedule> billSchedules;
+ QValueList<MyMoneySchedule> depositSchedules;
+ QValueList<MyMoneySchedule> transferSchedules;
+ try
+ {
+ text = QString();
+
+ if (!m_filterBills)
+ {
+ billSchedules = file->scheduleListEx( MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ theDate,
+ m_filterAccounts);
+
+ if (billSchedules.count() >= 1)
+ {
+ text += i18n("%1 Bills.").arg(QString::number(billSchedules.count()));
+ }
+ }
+
+ if (!m_filterDeposits)
+ {
+ depositSchedules = file->scheduleListEx( MyMoneySchedule::TYPE_DEPOSIT,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ theDate,
+ m_filterAccounts);
+
+ if (depositSchedules.count() >= 1)
+ {
+ if(!text.isEmpty())
+ text += " ";
+ text += i18n("%1 Deposits.").arg(QString::number(depositSchedules.count()));
+ }
+ }
+
+ if (!m_filterTransfers)
+ {
+ transferSchedules = file->scheduleListEx( MyMoneySchedule::TYPE_TRANSFER,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ theDate,
+ m_filterAccounts);
+
+ if (transferSchedules.count() >= 1)
+ {
+ if(!text.isEmpty())
+ text += " ";
+ text += i18n("%1 Transfers.").arg(QString::number(transferSchedules.count()));
+ }
+ }
+ }
+ catch (MyMoneyException* e)
+ {
+ // SAfe to ignore here, cause no schedules might exist
+ // for the selected account
+ delete e;
+ }
+
+ bool anyOverdue=false;
+ QValueList<MyMoneySchedule>::Iterator iter;
+ for (iter=transferSchedules.begin(); iter!=transferSchedules.end(); ++iter)
+ {
+ MyMoneySchedule schedule = *iter;
+ if (theDate < QDate::currentDate())
+ {
+ if (schedule.isOverdue())
+ {
+ anyOverdue = true;
+ break; // out early
+ }
+ }
+ }
+
+ if (!anyOverdue)
+ {
+ for (iter=depositSchedules.begin(); iter!=depositSchedules.end(); ++iter)
+ {
+ MyMoneySchedule schedule = *iter;
+ if (theDate < QDate::currentDate())
+ {
+ if (schedule.isOverdue())
+ {
+ anyOverdue = true;
+ break; // out early
+ }
+ }
+ }
+
+ if (!anyOverdue)
+ {
+ for (iter=billSchedules.begin(); iter!=billSchedules.end(); ++iter)
+ {
+ MyMoneySchedule schedule = *iter;
+ if (theDate < QDate::currentDate())
+ {
+ if (schedule.isOverdue())
+ {
+ anyOverdue = true;
+ break; // out early
+ }
+ }
+ }
+ }
+ }
+
+ if (anyOverdue)
+ painter->setPen(red);
+ else
+ painter->setPen(darkGray);
+
+ painter->setFont(fontLarge);
+ painter->drawText(0, 0, w, h, AlignCenter, text,
+ -1, &rect);
+ }
+ else if (m_type == QUARTERLY)
+ {
+ painter->setBrush(KGlobalSettings::baseColor());
+
+ painter->setPen(lightGray);
+ painter->drawRect(0, 0, w, h);
+ }
+}
+
+void kMyMoneyScheduledDateTbl::addDayPostfix(QString& text)
+{
+ int d = text.toInt();
+
+ if (d >= 1 && d <= 31)
+ {
+ QStringList postfixList = QStringList::split("-", i18n("st-nd-rd-th-th-th-th-th-th-th-th-th-th-th-th-th-th-th-th-th-st-nd-rd-th-th-th-th-th-th-th-st"), true);
+ text += postfixList[d-1];
+ }
+}
+
+void kMyMoneyScheduledDateTbl::refresh()
+{
+ repaintContents(false);
+}
+
+void kMyMoneyScheduledDateTbl::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ int row, col, pos;
+ QPoint mouseCoord;
+
+ if (isActiveWindow() || briefWidget.isVisible())
+ {
+ mouseCoord = e->pos();
+ row = rowAt(mouseCoord.y());
+ col = columnAt(mouseCoord.x());
+ if (row<1 || col<0)
+ {
+ return;
+ }
+
+ #if KDE_VERSION < 310
+ int firstWeekDay = KGlobal::locale()->weekStartsMonday() ? 1 : 0;
+ #else
+ int firstWeekDay = KGlobal::locale()->weekStartDay();
+ #endif
+
+ QDate drawDate(date);
+ QString text;
+
+ if (m_type == MONTHLY)
+ {
+ pos=7*(row-1)+col;
+ if ( firstWeekDay < 4 )
+ pos += firstWeekDay;
+ else
+ pos += firstWeekDay - 7;
+
+ if (pos<firstday || (firstday+numdays<=pos))
+ { // we are either
+ // painting a day of the previous month or
+ // painting a day of the following month
+
+ if (pos<firstday)
+ { // previous month
+ drawDate = drawDate.addMonths(-1);
+ text.setNum(numDaysPrevMonth+pos-firstday+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ } else { // following month
+ drawDate = drawDate.addMonths(1);
+ text.setNum(pos-firstday-numdays+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ }
+ } else { // paint a day of the current month
+ text.setNum(pos-firstday+1);
+ drawDate.setYMD(drawDate.year(), drawDate.month(), text.toInt());
+ }
+ }
+ else if (m_type == WEEKLY)
+ {
+ // TODO: Handle other start weekdays than Monday
+ text = QDate::shortDayName(row);
+ text += " ";
+
+ int dayOfWeek = date.dayOfWeek();
+ int diff;
+
+ if (row < dayOfWeek)
+ {
+ diff = -(dayOfWeek - row);
+ }
+ else
+ {
+ diff = row - dayOfWeek;
+ }
+
+ drawDate = date.addDays(diff);
+ }
+ else if (m_type == QUARTERLY)
+ {
+ }
+
+ m_drawDateOrig = drawDate;
+ MyMoneyFile *file = MyMoneyFile::instance();
+ QValueList<MyMoneySchedule> schedules;
+
+ try
+ {
+ int types=0;
+
+ if (!m_filterBills)
+ {
+ types |= MyMoneySchedule::TYPE_BILL;
+ }
+
+ if (!m_filterDeposits)
+ {
+ types |= MyMoneySchedule::TYPE_DEPOSIT;
+ }
+
+ if (!m_filterTransfers)
+ {
+ types |= MyMoneySchedule::TYPE_TRANSFER;
+ }
+
+
+ schedules = file->scheduleListEx( types,
+ MyMoneySchedule::OCCUR_ANY,
+ MyMoneySchedule::STYPE_ANY,
+ drawDate,
+ m_filterAccounts);
+ }
+ catch ( MyMoneyException* e)
+ {
+ // SAfe to ignore here, cause no schedules might exist
+ // for the selected account
+ delete e;
+ }
+
+ if (schedules.count() >= 1)
+ {
+ briefWidget.setSchedules(schedules, drawDate);
+
+ int h = briefWidget.height();
+ int w = briefWidget.width();
+
+ // Take off five pixels so the mouse cursor
+ // will be over the widget
+ QPoint p = QCursor::pos();
+ if (p.y() + h > QApplication::desktop()->height())
+ {
+ p.setY(p.y() - (h-5));
+ }
+ else
+ p.setY(p.y() - 5);
+
+ if (p.x() + w > QApplication::desktop()->width())
+ {
+ p.setX(p.x() - (w-5));
+ }
+ else
+ p.setX(p.x() - 5);
+
+ briefWidget.move(p);
+ briefWidget.show();
+ }
+ else
+ {
+ briefWidget.hide();
+ }
+ }
+}
+
+void kMyMoneyScheduledDateTbl::filterBills(bool enable)
+{
+ m_filterBills = enable;
+ repaintContents(false);
+}
+
+void kMyMoneyScheduledDateTbl::filterDeposits(bool enable)
+{
+ m_filterDeposits = enable;
+ repaintContents(false);
+}
+
+void kMyMoneyScheduledDateTbl::filterTransfers(bool enable)
+{
+ m_filterTransfers = enable;
+ repaintContents(false);
+}
+
+#include "kmymoneyscheduleddatetbl.moc"
diff --git a/kmymoney2/widgets/kmymoneyscheduleddatetbl.h b/kmymoney2/widgets/kmymoneyscheduleddatetbl.h
new file mode 100644
index 0000000..5985a6b
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyscheduleddatetbl.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ kmymoneyscheduleddatetbl.h - description
+ -------------------
+ begin : Thu Jul 3 2003
+ copyright : (C) 2000-2003 by Michael Edwardes
+ email : mte@users.sourceforge.net
+ Javier Campos Morales <javi_c@users.sourceforge.net>
+ Felix Rodriguez <frodriguez@users.sourceforge.net>
+ John C <thetacoturtle@users.sourceforge.net>
+ Thomas Baumgart <ipwizard@users.sourceforge.net>
+ Kevin Tambascio <ktambascio@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifndef KMYMONEYSCHEDULEDDATETBL_H
+#define KMYMONEYSCHEDULEDDATETBL_H
+
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../widgets/kmymoneydatetbl.h"
+#include "../widgets/kmymoneybriefschedule.h"
+#include "../mymoney/mymoneyscheduled.h"
+
+/**
+ * @author Michael Edwardes
+ */
+
+class kMyMoneyScheduledDateTbl : public kMyMoneyDateTbl
+{
+ Q_OBJECT
+public:
+ kMyMoneyScheduledDateTbl(QWidget *parent=0,
+ QDate date=QDate::currentDate(),
+ const char* name=0, WFlags f=0);
+
+ ~kMyMoneyScheduledDateTbl();
+ void refresh();
+ void filterBills(bool enable);
+ void filterDeposits(bool enable);
+ void filterTransfers(bool enable);
+ void setFilterAccounts(const QStringList& list) { m_filterAccounts = list; repaintContents(false); }
+
+signals:
+ void enterClicked(const MyMoneySchedule&, const QDate&);
+ void skipClicked(const MyMoneySchedule&, const QDate&);
+
+protected:
+ void drawCellContents(QPainter *painter, int row, int col, const QDate& theDate);
+ void addDayPostfix(QString& text);
+ void contentsMouseMoveEvent(QMouseEvent* e);
+
+private:
+ bool m_filterBills, m_filterDeposits, m_filterTransfers;
+ QStringList m_filterAccounts;
+ KMyMoneyBriefSchedule briefWidget;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneyselector.cpp b/kmymoney2/widgets/kmymoneyselector.cpp
new file mode 100644
index 0000000..6ae07ca
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyselector.cpp
@@ -0,0 +1,709 @@
+/***************************************************************************
+ kmymoneyselector.cpp
+ -------------------
+ begin : Thu Jun 29 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qheader.h>
+#include <qtimer.h>
+#include <qstyle.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneyselector.h>
+#include <kmymoney/kmymoneylistviewitem.h>
+#include <kmymoney/kmymoneychecklistitem.h>
+
+#include "../kmymoneyglobalsettings.h"
+
+KMyMoneySelector::KMyMoneySelector(QWidget *parent, const char *name, QWidget::WFlags flags) :
+ QWidget(parent, name, flags)
+{
+ m_selMode = QListView::Single;
+
+ m_listView = new KListView(this);
+ // don't show horizontal scroll bar
+ m_listView->setHScrollBarMode(QScrollView::AlwaysOff);
+
+ m_listView->setSorting(-1);
+
+ if(parent) {
+ setFocusProxy(parent->focusProxy());
+ m_listView->setFocusProxy(parent->focusProxy());
+ }
+
+ m_listView->setAllColumnsShowFocus(true);
+
+ m_layout = new QHBoxLayout( this, 0, 6);
+
+ m_listView->addColumn( "Hidden" );
+ m_listView->header()->hide();
+ m_listView->header()->setStretchEnabled(true, -1);
+ m_listView->header()->adjustHeaderSize();
+
+ m_layout->addWidget( m_listView );
+
+ // force init
+ m_selMode = QListView::Multi;
+ setSelectionMode(QListView::Single);
+
+ connect(m_listView, SIGNAL(rightButtonPressed(QListViewItem* , const QPoint&, int)), this, SLOT(slotListRightMouse(QListViewItem*, const QPoint&, int)));
+}
+
+KMyMoneySelector::~KMyMoneySelector()
+{
+}
+
+void KMyMoneySelector::clear(void)
+{
+ m_listView->clear();
+ m_visibleItem = 0;
+}
+
+void KMyMoneySelector::setSelectionMode(const QListView::SelectionMode mode)
+{
+ if(m_selMode != mode) {
+ m_selMode = mode;
+ clear();
+
+ // make sure, it's either Multi or Single
+ if(mode != QListView::Multi) {
+ m_selMode = QListView::Single;
+ connect(m_listView, SIGNAL(selectionChanged(void)), this, SIGNAL(stateChanged(void)));
+ connect(m_listView, SIGNAL(executed(QListViewItem*)), this, SLOT(slotItemSelected(QListViewItem*)));
+ } else {
+ disconnect(m_listView, SIGNAL(selectionChanged(void)), this, SIGNAL(stateChanged(void)));
+ disconnect(m_listView, SIGNAL(executed(QListViewItem*)), this, SLOT(slotItemSelected(QListViewItem*)));
+ }
+ }
+ QWidget::update();
+}
+
+void KMyMoneySelector::slotItemSelected(QListViewItem *item)
+{
+ if(m_selMode == QListView::Single) {
+ KMyMoneyListViewItem* l_item = dynamic_cast<KMyMoneyListViewItem*>(item);
+ if(l_item && l_item->isSelectable()) {
+ emit itemSelected(l_item->id());
+ }
+ }
+}
+
+QListViewItem* KMyMoneySelector::newItem(const QString& name, QListViewItem* after, const QString& key, const QString& id, QCheckListItem::Type type)
+{
+ QListViewItem* item;
+ if(after)
+ item = new KMyMoneyCheckListItem(m_listView, after, name, key, id, type);
+ else
+ item = new KMyMoneyCheckListItem(m_listView, name, key, id, type);
+
+ item->setSelectable(!id.isEmpty());
+ item->setOpen(true);
+ return item;
+}
+
+QListViewItem* KMyMoneySelector::newItem(const QString& name, const QString& key, const QString& id, QCheckListItem::Type type)
+{
+ return newItem(name, 0, key, id, type);
+}
+
+QListViewItem* KMyMoneySelector::newTopItem(const QString& name, const QString& key, const QString& id)
+{
+ QListViewItem* p;
+
+ if(m_selMode == QListView::Multi) {
+ KMyMoneyCheckListItem* q = new KMyMoneyCheckListItem(m_listView, name, key, id);
+ connect(q, SIGNAL(stateChanged(bool)), this, SIGNAL(stateChanged(void)));
+ p = static_cast<QListViewItem*> (q);
+
+ } else {
+ KMyMoneyListViewItem* q = new KMyMoneyListViewItem(m_listView, name, key, id);
+ p = static_cast<QListViewItem*> (q);
+ }
+
+ return p;
+}
+
+QListViewItem* KMyMoneySelector::newItem(QListViewItem* parent, const QString& name, const QString& key, const QString& id)
+{
+ QListViewItem* p;
+
+ if(m_selMode == QListView::Multi) {
+ KMyMoneyCheckListItem* q = new KMyMoneyCheckListItem(parent, name, key, id);
+ connect(q, SIGNAL(stateChanged(bool)), this, SIGNAL(stateChanged(void)));
+ p = static_cast<QListViewItem*> (q);
+
+ } else {
+ KMyMoneyListViewItem* q = new KMyMoneyListViewItem(parent, name, key, id);
+ p = static_cast<QListViewItem*> (q);
+ }
+
+ return p;
+}
+
+void KMyMoneySelector::protectItem(const QString& itemId, const bool protect)
+{
+ QListViewItemIterator it(m_listView, QListViewItemIterator::Selectable);
+ QListViewItem* it_v;
+ KMyMoneyListViewItem* it_l;
+ KMyMoneyCheckListItem* it_c;
+
+ // scan items
+ while((it_v = it.current()) != 0) {
+ it_l = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ if(it_l) {
+ if(it_l->id() == itemId) {
+ it_l->setSelectable(!protect);
+ break;
+ }
+ } else {
+ it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c) {
+ if(it_c->id() == itemId) {
+ it_c->setSelectable(!protect);
+ break;
+ }
+ }
+ }
+ ++it;
+ }
+}
+
+QListViewItem* KMyMoneySelector::item(const QString& id) const
+{
+ QListViewItemIterator it(m_listView, QListViewItemIterator::Selectable);
+ QListViewItem* it_v;
+ KMyMoneyListViewItem* it_l;
+ KMyMoneyCheckListItem* it_c;
+
+ while((it_v = it.current()) != 0) {
+ it_l = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ if(it_l) {
+ if(it_l->id() == id)
+ break;
+ } else {
+ it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->id() == id)
+ break;
+ }
+ ++it;
+ }
+ return it_v;
+}
+
+int KMyMoneySelector::optimizedWidth(void) const
+{
+ QListViewItemIterator it(m_listView, QListViewItemIterator::Selectable);
+ QListViewItem* it_v;
+ KMyMoneyListViewItem* it_l;
+ KMyMoneyCheckListItem* it_c;
+
+ // scan items
+ int w = 0;
+#ifndef KMM_DESIGNER
+ QFontMetrics fm( KMyMoneyGlobalSettings::listCellFont());
+#else
+ QFontMetrics fm( font() );
+#endif
+ while((it_v = it.current()) != 0) {
+ it_l = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ int nw = 0;
+ if(it_l) {
+ nw = it_l->width(fm, m_listView, 0);
+ } else {
+ it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c) {
+ nw = it_c->width(fm, m_listView, 0);
+ }
+ }
+ if(nw > w)
+ w = nw;
+ ++it;
+ }
+ return w;
+}
+
+void KMyMoneySelector::setOptimizedWidth(void)
+{
+ int w = optimizedWidth();
+
+ m_listView->setMinimumWidth(w+30);
+ m_listView->setMaximumWidth(w+30);
+ m_listView->setColumnWidth(0, w+28);
+}
+
+bool KMyMoneySelector::allItemsSelected(void) const
+{
+ QListViewItem* it_v;
+
+ if(m_selMode == QListView::Single)
+ return false;
+
+ for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ QCheckListItem* it_c = dynamic_cast<QCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(!(it_c->isOn() && allItemsSelected(it_v)))
+ return false;
+ } else {
+ if(!allItemsSelected(it_v))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool KMyMoneySelector::allItemsSelected(const QListViewItem *item) const
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ QCheckListItem* it_c = static_cast<QCheckListItem*>(it_v);
+ if(!(it_c->isOn() && allItemsSelected(it_v)))
+ return false;
+ }
+ }
+ return true;
+}
+
+void KMyMoneySelector::removeItem(const QString& id)
+{
+ QListViewItem* it_v;
+ QListViewItemIterator it;
+
+ it = QListViewItemIterator(m_listView);
+ while((it_v = it.current()) != 0) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(id == it_c->id()) {
+ if(it_c->firstChild()) {
+ it_c->setSelectable(false);
+ } else {
+ delete it_c;
+ }
+ }
+ }
+ } else if(it_v->rtti() == 0) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ if(id == it_c->id()) {
+ if(it_c->firstChild()) {
+ it_c->setSelectable(false);
+ } else {
+ delete it_c;
+ }
+ }
+ }
+ it++;
+ }
+
+ // get rid of top items that just lost the last children (e.g. Favorites)
+ it = QListViewItemIterator(m_listView, QListViewItemIterator::NotSelectable);
+ while((it_v = it.current()) != 0) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->childCount() == 0)
+ delete it_c;
+ }
+ it++;
+ }
+
+ return;
+}
+
+
+void KMyMoneySelector::selectAllItems(const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ QCheckListItem* it_c = dynamic_cast<QCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ it_c->setOn(state);
+ }
+ selectAllSubItems(it_v, state);
+ }
+ }
+ emit stateChanged();
+}
+
+void KMyMoneySelector::selectItems(const QStringList& itemList, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox && itemList.contains(it_c->id())) {
+ it_c->setOn(state);
+ }
+ selectSubItems(it_v, itemList, state);
+ }
+ }
+ emit stateChanged();
+}
+
+void KMyMoneySelector::selectSubItems(QListViewItem* item, const QStringList& itemList, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox && itemList.contains(it_c->id())) {
+ it_c->setOn(state);
+ }
+ selectSubItems(it_v, itemList, state);
+ }
+ }
+}
+
+void KMyMoneySelector::selectAllSubItems(QListViewItem* item, const bool state)
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ QCheckListItem* it_c = dynamic_cast<QCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ it_c->setOn(state);
+ }
+ selectAllSubItems(it_v, state);
+ }
+ }
+}
+
+void KMyMoneySelector::selectedItems(QStringList& list) const
+{
+ QListViewItem* it_v;
+
+ list.clear();
+ if(m_selMode == QListView::Single) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(m_listView->selectedItem());
+ if(it_c != 0)
+ list << it_c->id();
+
+ } else {
+ for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(it_c->isOn())
+ list << (*it_c).id();
+ }
+ selectedItems(list, it_v);
+ }
+ }
+ }
+}
+
+void KMyMoneySelector::selectedItems(QStringList& list, QListViewItem* item) const
+{
+ QListViewItem* it_v;
+
+ for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(it_c->isOn())
+ list << (*it_c).id();
+ selectedItems(list, it_v);
+ }
+ }
+ }
+}
+
+void KMyMoneySelector::itemList(QStringList& list) const
+{
+ QListViewItemIterator it;
+ QListViewItem* it_v;
+
+ it = QListViewItemIterator(m_listView, QListViewItemIterator::Selectable);
+ while((it_v = it.current()) != 0) {
+ {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ list << it_c->id();
+ }
+ } else if(it_v->rtti() == 0) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ list << it_c->id();
+ }
+ }
+ it++;
+ }
+}
+
+void KMyMoneySelector::setSelected(const QString& id, const bool state)
+{
+ QListViewItemIterator it;
+ QListViewItem* it_v;
+ QListViewItem* it_visible = 0;
+
+ it = QListViewItemIterator(m_listView, QListViewItemIterator::Selectable);
+ while((it_v = it.current()) != 0) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ Q_CHECK_PTR(it_c);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ if(it_c->id() == id) {
+ it_c->setOn(state);
+ m_listView->setSelected(it_v, true);
+ if(!it_visible)
+ it_visible = it_v;
+ }
+ }
+ } else if(it_v->rtti() == 0) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ Q_CHECK_PTR(it_c);
+ if(it_c->id() == id) {
+ m_listView->setSelected(it_v, true);
+ if(!it_visible)
+ it_visible = it_v;
+ ensureItemVisible(it_v);
+ return;
+ }
+ }
+ it++;
+ }
+
+ // make sure the first one found is visible
+ if(it_visible)
+ ensureItemVisible(it_visible);
+}
+
+void KMyMoneySelector::ensureItemVisible(const QListViewItem *it_v)
+{
+ // for some reason, I could only use the ensureItemVisible() method
+ // of QListView successfully, after the widget was drawn on the screen.
+ // If called before it had no effect (if the item was not visible).
+ //
+ // The solution was to store the item we wanted to see in a local var
+ // and call QListView::ensureItemVisible() about 10ms later in
+ // the slot slotShowSelected. (ipwizard, 12/29/2003)
+ m_visibleItem = it_v;
+
+ QTimer::singleShot(100, this, SLOT(slotShowSelected()));
+}
+
+void KMyMoneySelector::slotShowSelected(void)
+{
+ if(m_listView && m_visibleItem)
+ m_listView->ensureItemVisible(m_visibleItem);
+}
+
+int KMyMoneySelector::slotMakeCompletion(const QString& _txt)
+{
+ QString txt(QRegExp::escape(_txt));
+ if(KMyMoneyGlobalSettings::stringMatchFromStart() && this->isA("KMyMoneySelector") )
+ txt.prepend('^');
+ return slotMakeCompletion(QRegExp(txt, false));
+}
+
+bool KMyMoneySelector::match(const QRegExp& exp, QListViewItem* item) const
+{
+ return exp.search(item->text(0)) != -1;
+}
+
+int KMyMoneySelector::slotMakeCompletion(const QRegExp& exp)
+{
+ QListViewItemIterator it(m_listView, QListViewItemIterator::Selectable);
+
+ QListViewItem* it_v;
+
+ // The logic used here seems to be awkward. The problem is, that
+ // QListViewItem::setVisible works recursively on all it's children
+ // and grand-children.
+ //
+ // The way out of this is as follows: Make all items visible.
+ // Then go through the list again and perform the checks.
+ // If an item does not have any children (last leaf in the tree view)
+ // perform the check. Then check recursively on the parent of this
+ // leaf that it has no visible children. If that is the case, make the
+ // parent invisible and continue this check with it's parent.
+ while((it_v = it.current()) != 0) {
+ it_v->setVisible(true);
+ ++it;
+ }
+
+ QListViewItem* firstMatch = 0;
+
+ if(!exp.pattern().isEmpty()) {
+ it = QListViewItemIterator(m_listView, QListViewItemIterator::Selectable);
+ while((it_v = it.current()) != 0) {
+ if(it_v->firstChild() == 0) {
+ if(!match(exp, it_v)) {
+ // this is a node which does not contain the
+ // text and does not have children. So we can
+ // safely hide it. Then we check, if the parent
+ // has more children which are still visible. If
+ // none are found, the parent node is hidden also. We
+ // continue until the top of the tree or until we
+ // find a node that still has visible children.
+ bool hide = true;
+ while(hide) {
+ it_v->setVisible(false);
+ it_v = it_v->parent();
+ if(it_v && it_v->isSelectable()) {
+ hide = !match(exp, it_v);
+ QListViewItem* child = it_v->firstChild();
+ for(; child && hide; child = child->nextSibling()) {
+ if(child->isVisible())
+ hide = false;
+ }
+ } else
+ hide = false;
+ }
+ } else if(!firstMatch) {
+ firstMatch = it_v;
+ }
+ ++it;
+
+ } else if(match(exp, it_v)) {
+ if(!firstMatch) {
+ firstMatch = it_v;
+ }
+ // a node with children contains the text. We want
+ // to display all child nodes in this case, so we need
+ // to advance the iterator to the next sibling of the
+ // current node. This could well be the sibling of a
+ // parent or grandparent node.
+ QListViewItem* curr = it_v;
+ QListViewItem* item;
+ while((item = curr->nextSibling()) == 0) {
+ curr = curr->parent();
+ if(curr == 0)
+ break;
+ if(match(exp, curr))
+ firstMatch = curr;
+ }
+ do {
+ ++it;
+ } while(it.current() && it.current() != item);
+
+ } else {
+ // It's a node with children that does not match. We don't
+ // change it's status here.
+ ++it;
+ }
+ }
+ }
+
+ // make the first match the one that is selected
+ // if we have no match, make sure none is selected
+ if(m_selMode == QListView::Single) {
+ if(firstMatch) {
+ m_listView->setSelected(firstMatch, true);
+ ensureItemVisible(firstMatch);
+ } else
+ m_listView->selectAll(false);
+ }
+
+ // Get the number of visible nodes for the return code
+ int cnt = 0;
+
+ it = QListViewItemIterator(m_listView, QListViewItemIterator::Selectable | QListViewItemIterator::Visible);
+ while((it_v = it.current()) != 0) {
+ cnt++;
+ it++;
+ }
+ return cnt;
+}
+
+bool KMyMoneySelector::contains(const QString& txt) const
+{
+ QListViewItemIterator it(m_listView, QListViewItemIterator::Selectable);
+ QListViewItem* it_v;
+ while((it_v = it.current()) != 0) {
+ if(it_v->rtti() == 1) {
+ KMyMoneyCheckListItem* it_c = dynamic_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->text() == txt) {
+ return true;
+ }
+ } else if(it_v->rtti() == 0) {
+ KMyMoneyListViewItem* it_c = dynamic_cast<KMyMoneyListViewItem*>(it_v);
+ if(it_c->text(0) == txt) {
+ return true;
+ }
+ }
+ it++;
+ }
+ return false;
+}
+
+void KMyMoneySelector::slotListRightMouse(QListViewItem* it_v, const QPoint& pos, int /* col */)
+{
+ if(it_v && (it_v->rtti() == 1)) {
+ KMyMoneyCheckListItem* it_c = static_cast<KMyMoneyCheckListItem*>(it_v);
+ if(it_c->type() == QCheckListItem::CheckBox) {
+ // the following is copied from QCheckListItem::activate() et al
+ int boxsize = m_listView->style().pixelMetric(QStyle::PM_CheckListButtonSize, m_listView);
+ int align = m_listView->columnAlignment( 0 );
+ int marg = m_listView->itemMargin();
+ int y = 0;
+
+ if ( align & AlignVCenter )
+ y = ( ( height() - boxsize ) / 2 ) + marg;
+ else
+ y = (m_listView->fontMetrics().height() + 2 + marg - boxsize) / 2;
+
+ QRect r( 0, y, boxsize-3, boxsize-3 );
+ // columns might have been swapped
+ r.moveBy( m_listView->header()->sectionPos( 0 ), 0 );
+
+ QPoint topLeft = m_listView->itemRect(it_v).topLeft(); //### inefficient?
+ QPoint p = m_listView->mapFromGlobal( pos ) - topLeft;
+
+ int xdepth = m_listView->treeStepSize() * (it_v->depth() + (m_listView->rootIsDecorated() ? 1 : 0))
+ + m_listView->itemMargin();
+ xdepth += m_listView->header()->sectionPos( m_listView->header()->mapToSection( 0 ) );
+ p.rx() -= xdepth;
+ // copy ends around here
+
+ if ( r.contains( p ) ) {
+ // we get down here, if we have a right click onto the checkbox
+ selectAllSubItems(it_c, it_c->isOn());
+ }
+ }
+ }
+}
+
+QStringList KMyMoneySelector::selectedItems(void) const
+{
+ QStringList list;
+ selectedItems(list);
+ return list;
+}
+
+QStringList KMyMoneySelector::itemList(void) const
+{
+ QStringList list;
+ itemList(list);
+ return list;
+}
+
+#include "kmymoneyselector.moc"
diff --git a/kmymoney2/widgets/kmymoneyselector.h b/kmymoney2/widgets/kmymoneyselector.h
new file mode 100644
index 0000000..2b389d6
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneyselector.h
@@ -0,0 +1,387 @@
+/***************************************************************************
+ kmymoneyselector.h
+ -------------------
+ begin : Thu Jun 29 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYSELECTOR_H
+#define KMYMONEYSELECTOR_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qlistview.h>
+class QHBoxLayout;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KListView;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyutils.h>
+
+/**
+ * This class implements a general selector for id based objects. It is based
+ * on a tree view. Using this widget, one can select one or multiple
+ * items depending on the mode of operation and the set of items
+ * selected to be displayed. (see setSelectionMode() ).
+ *
+ * - Single selection mode\n
+ * In this mode the widget allows to select a single entry out of
+ * the set of displayed items.
+ *
+ * - Multi selection mode\n
+ * In this mode, the widget allows to select one or more entries
+ * out of the set of displayed items. Selection is performed
+ * by marking the item in the view.
+ */
+class KMyMoneySelector : public QWidget
+{
+ Q_OBJECT
+public:
+ KMyMoneySelector(QWidget *parent=0, const char *name=0, QWidget::WFlags flags = 0);
+ virtual ~KMyMoneySelector();
+
+ /**
+ * This method sets the mode of operation of this widget.
+ * Supported values are @p QListView::Single and @p QListView::Multi.
+ *
+ * @param mode @p QListView::Single selects single selection mode and
+ * @p QListView::Multi selects multi selection mode
+ *
+ * @note When the widget is created, it defaults to QListView::Single.
+ * Any items loaded into the widget will be cleared if the mode changes.
+ * Changing the selection mode also changes the type of the items
+ * created through newItem(). You should therefor set the selection mode
+ * before you create items.
+ */
+ void setSelectionMode(const QListView::SelectionMode mode);
+
+ /**
+ * returns the selection mode of the widget.
+ *
+ * @sa setSelectionMode()
+ */
+ QListView::SelectionMode selectionMode(void) const { return m_selMode; }
+
+ /**
+ * This method returns the list of selected item ids. If
+ * no item is selected, the list is empty. The list is cleared
+ * when the method is called.
+ *
+ * @param list reference to id list
+ */
+ void selectedItems(QStringList& list) const;
+
+ /**
+ * Convenience method for above method. Requires more resources.
+ * Provided only for backward compatibility.
+ *
+ * @todo Deprecated after 1.0
+ */
+ QStringList selectedItems(void) const;
+
+ /**
+ * This method returns the list of all item ids.
+ * The list is cleared when the method is called.
+ *
+ * @param list reference to id list
+ */
+ void itemList(QStringList& list) const;
+
+ /**
+ * Convenience method for above method. Requires more resources.
+ * Provided only for backward compatibility.
+ *
+ * @todo Deprecated after 1.0
+ */
+ QStringList itemList(void) const;
+
+ /**
+ * This method returns an information if all items
+ * currently shown are selected or not.
+ *
+ * @retval true All items shown are selected
+ * @retval false Not all items are selected
+ *
+ * @note If the selection mode is set to Single, this
+ * method always returns false.
+ */
+ bool allItemsSelected(void) const;
+
+ /**
+ * This method sets the current selected item and marks the
+ * checkbox according to @p state in multi-selection-mode.
+ *
+ * @param id id of account
+ * @param state state of checkbox in multi-selection-mode
+ * @p true checked
+ * @p false not checked (default)
+ */
+ void setSelected(const QString& id, const bool state = false);
+
+ /**
+ * Return a pointer to the KListView object
+ */
+ KListView* listView(void) const { return m_listView; };
+
+ /**
+ * This method selects/deselects all items that
+ * are currently in the item list according
+ * to the parameter @p state.
+ *
+ * @param state select items if @p true, deselect otherwise
+ */
+ void selectAllItems(const bool state);
+
+ /**
+ * This method selects/deselects all items that
+ * are currently in this object's item list AND are present in the supplied
+ * @p itemList of items to select, according to the @p state.
+ *
+ * @param itemList of item ids to apply @p state to
+ * @param state select items if @p true, deselect otherwise
+ */
+ void selectItems(const QStringList& itemList, const bool state);
+
+ /**
+ * Protect an entry from selection. Protection is controlled by
+ * the parameter @p protect.
+ *
+ * @param itemId id of item for which to modify the protection
+ * @param protect if true, the entry specified by @p accId cannot be
+ * selected. If false, it can be selected. Defaults to @p true.
+ */
+ void protectItem(const QString& itemId, const bool protect = true);
+
+ /**
+ * This method modifies the width of the widget to match its optimal size
+ * so that all entries fit completely.
+ */
+ void setOptimizedWidth(void);
+
+ /**
+ * This method removes an item with a given id from the list.
+ *
+ * @param id QString containing id of item to be removed
+ */
+ void removeItem(const QString& id);
+
+ /**
+ * This method creates a new top level KMyMoneyCheckListItem object in the list view.
+ * The type can be influenced with the @a type argument. It defaults
+ * to QCheckListItem::RadioButtonController. If @a id is empty, the item is not
+ * selectable. It will be shown 'opened' (see QListViewItem::setOpen())
+ *
+ * @return pointer to newly created object
+ */
+ QListViewItem* newItem(const QString& name, const QString& key = QString(), const QString& id = QString(), QCheckListItem::Type type = QCheckListItem::RadioButtonController);
+
+ /**
+ * Same as above, but create the item following the item pointed to by @c after.
+ * If @c after is 0, then behave as previous method
+ */
+ QListViewItem* newItem(const QString& name, QListViewItem* after, const QString& key = QString(), const QString& id = QString(), QCheckListItem::Type type = QCheckListItem::RadioButtonController);
+
+ /**
+ * This method creates a new selectable object depending on the
+ * selection mode. This is either a KListViewItem for single
+ * selection mode or a KMyMoneyCheckListItem for multi selection mode
+ *
+ * @note The new item will be the first one in the selection
+ *
+ * @param parent pointer to parent item
+ * @param name the displayed name
+ * @param key String to be used for completion. If empty defaults to @a name
+ * @param id the id used to identify the objects
+ *
+ * @return pointer to newly created object
+ */
+ QListViewItem* newItem(QListViewItem* parent, const QString& name, const QString& key, const QString& id);
+
+ /**
+ * This method creates a new selectable object depending on the
+ * selection mode. This is either a KListViewItem for single
+ * selection mode or a KMyMoneyCheckListItem for multi selection mode.
+ * In contrast to the above method, the parent is always the view.
+ *
+ * @note The new item will be the first one in the selection
+ *
+ * @param name the displayed name
+ * @param key String to be used for completion. If empty defaults to @a name
+ * @param id the id used to identify the objects
+ *
+ * @return pointer to newly created object
+ */
+ QListViewItem* newTopItem(const QString& name, const QString& key, const QString& id);
+
+ /**
+ * This method checks if a given @a item matches the given regular expression @a exp.
+ *
+ * @param exp const reference to a regular expression object
+ * @param item pointer to QListViewItem
+ *
+ * @retval true item matches
+ * @retval false item does not match
+ */
+ virtual bool match(const QRegExp& exp, QListViewItem* item) const;
+
+ /**
+ * This method delays the call for m_listView->ensureItemVisible(item)
+ * for about 10ms. This seems to be necessary when the widget is not (yet)
+ * visible on the screen after creation.
+ *
+ * @param item pointer to QListViewItem that should be made visible
+ *
+ * @sa slotShowSelected()
+ */
+ void ensureItemVisible(const QListViewItem *item);
+
+ /**
+ * This method returns a pointer to the QListViewItem with the id @a id.
+ * If such an item is not contained in the list, @a 0 will be returned.
+ *
+ * @param id id to be used to find a QListViewItem pointer for
+ */
+ QListViewItem* item(const QString& id) const;
+
+ /**
+ * This method returns, if any of the items in the selector contains
+ * the text @a txt.
+ *
+ * @param txt const reference to string to be looked for
+ * @retval true exact match found
+ * @retval false no match found
+ */
+ virtual bool contains(const QString& txt) const;
+
+ /**
+ * Clears all items of the selector and the associated listview.
+ */
+ virtual void clear(void);
+
+ /**
+ * This method returns the optimal width for the widget
+ */
+ int optimizedWidth(void) const;
+
+public slots:
+ /**
+ * This slot selects all items that are currently in
+ * the item list of the widget.
+ */
+ void slotSelectAllItems(void) { selectAllItems(true); };
+
+ /**
+ * This slot deselects all items that are currently in
+ * the item list of the widget.
+ */
+ void slotDeselectAllItems(void) { selectAllItems(false); };
+
+signals:
+ void stateChanged(void);
+
+ void itemSelected(const QString& id);
+
+protected:
+ /**
+ * Helper method for selectedItems() to traverse the tree.
+ *
+ * @param list list of selected ids
+ * @param item pointer to item to start with
+ */
+ void selectedItems(QStringList& list, QListViewItem* item) const;
+
+ /**
+ * Helper method for allItemsSelected() to traverse the tree.
+ *
+ * @param item pointer to item to start with
+ */
+ bool allItemsSelected(const QListViewItem *item) const;
+
+ /**
+ * This is a helper method for selectAllItems().
+ *
+ * @param item pointer to item to start with
+ * @param state selection state (@a true = selected, @a false = not selected)
+ */
+ void selectAllSubItems(QListViewItem* item, const bool state);
+
+ /**
+ * This is a helper method for selectItems().
+ *
+ * @param item pointer to item to start with
+ * @param itemList list of ids to be selected
+ * @param state selection state (@a true = selected, @a false = not selected)
+ */
+ void selectSubItems(QListViewItem* item, const QStringList& itemList, const bool state);
+
+public slots:
+ /**
+ * Hide all listview items that do not match the regular expression @a exp.
+ * This method returns the number of visible items
+ *
+ * @param exp const reference to QRegExp that an item must match to stay visible
+ *
+ * @return number of visible items
+ */
+ int slotMakeCompletion(const QRegExp& exp);
+
+ /**
+ * This is an overloaded member function, provided for convenience. It behaves essentially like the above function.
+ *
+ * @param txt contains the pattern for a QRegExp
+ */
+ int slotMakeCompletion(const QString& txt);
+
+
+protected slots:
+ /**
+ * This slot is usually connected to a timer signal and simply
+ * calls m_listView->ensureItemVisible() for the last selected item
+ * in this widget.
+ *
+ * @sa ensureItemVisible(), setSelected(const QString&)
+ */
+ void slotShowSelected(void);
+
+ /**
+ * This slot is connected to the KListView executed signal
+ */
+ void slotItemSelected(QListViewItem *it_v);
+
+ /**
+ * This slot processes the right mouse button press on a list view item.
+ *
+ * @param it_v pointer to list view item that was pressed
+ * @param p the position where the mouse was pressed
+ */
+ void slotListRightMouse(QListViewItem* it_v, const QPoint& p, int /* col */);
+
+protected:
+ KListView* m_listView;
+ QStringList m_itemList;
+ QString m_baseName;
+ QListView::SelectionMode m_selMode;
+ QHBoxLayout* m_layout;
+
+private:
+ const QListViewItem* m_visibleItem;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneytitlelabel.cpp b/kmymoney2/widgets/kmymoneytitlelabel.cpp
new file mode 100644
index 0000000..9dc5140
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneytitlelabel.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+ kmymoneytitlelabel.cpp
+ -------------------
+ begin : Sun Feb 05 2005
+ copyright : (C) 2005 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+#include <qvariant.h>
+#include <qstyle.h>
+#include <qpainter.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneytitlelabel.h"
+
+KMyMoneyTitleLabel::KMyMoneyTitleLabel(QWidget *parent, const char *name) :
+ QLabel(parent, name),
+ m_bgColor( KGlobalSettings::highlightColor() ),
+ m_textColor( KGlobalSettings::highlightedTextColor() )
+{
+ setFont(KGlobalSettings::windowTitleFont());
+}
+
+KMyMoneyTitleLabel::~KMyMoneyTitleLabel()
+{
+}
+
+void KMyMoneyTitleLabel::setLeftImageFile(const QString& _file)
+{
+ m_leftImageFile = _file;
+ QString lfullpath = KGlobal::dirs()->findResource("appdata", m_leftImageFile);
+ m_leftImage.load(lfullpath);
+ m_leftImage.setAlphaBuffer(true);
+}
+
+void KMyMoneyTitleLabel::setRightImageFile(const QString& _file)
+{
+ m_rightImageFile = _file;
+ QString rfullpath = KGlobal::dirs()->findResource("appdata", m_rightImageFile);
+ m_rightImage.load(rfullpath);
+ m_rightImage.setAlphaBuffer(true);
+ if(m_rightImage.height() < 30)
+ setMinimumHeight(30);
+ else {
+ setMinimumHeight( m_rightImage.height() );
+ setMaximumHeight( m_rightImage.height() );
+ }
+}
+
+void KMyMoneyTitleLabel::resizeEvent ( QResizeEvent * )
+{
+ QRect cr = contentsRect();
+ QImage output( cr.width(), cr.height(), 32 );
+ output.fill( m_bgColor.rgb() );
+
+ bitBlt ( &output, cr.width() - m_rightImage.width(), 0, &m_rightImage, 0, 0, m_rightImage.width(), m_rightImage.height(), 0 );
+ bitBlt ( &output, 0, 0, &m_leftImage, 0, 0, m_leftImage.width(), m_leftImage.height(), 0 );
+
+ QPixmap pix;
+ pix.convertFromImage(output);
+ setPixmap(pix);
+ setMinimumWidth( m_rightImage.width() );
+}
+
+void KMyMoneyTitleLabel::drawContents(QPainter *p)
+{
+ // first draw pixmap
+ QLabel::drawContents(p);
+
+ // then draw text on top
+ style().drawItem( p, contentsRect(), alignment(), colorGroup(), isEnabled(),
+ 0, QString(" ")+m_text, -1, &m_textColor );
+}
+
+void KMyMoneyTitleLabel::setText(const QString& txt)
+{
+ m_text = txt;
+ update();
+}
+
+#include "kmymoneytitlelabel.moc"
diff --git a/kmymoney2/widgets/kmymoneytitlelabel.h b/kmymoney2/widgets/kmymoneytitlelabel.h
new file mode 100644
index 0000000..08f9302
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneytitlelabel.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ kmymoneytitlelabel.h
+ -------------------
+ begin : Sun Feb 05 2005
+ copyright : (C) 2005 by Ace Jones
+ email : acejones@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KTITLELABEL_H
+#define KTITLELABEL_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qimage.h>
+#include <qcolor.h>
+class QPixmap;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ * @author ace jones
+ */
+class KMyMoneyTitleLabel : public QLabel
+{
+ Q_OBJECT
+ Q_PROPERTY( QString leftImageFile READ leftImageFile WRITE setLeftImageFile DESIGNABLE true )
+ Q_PROPERTY( QString rightImageFile READ rightImageFile WRITE setRightImageFile DESIGNABLE true )
+ Q_PROPERTY( QColor bgColor READ bgColor WRITE setBgColor DESIGNABLE true )
+ Q_PROPERTY( QString text READ text WRITE setText DESIGNABLE true )
+
+public:
+ KMyMoneyTitleLabel(QWidget *parent = 0, const char *name = 0);
+ ~KMyMoneyTitleLabel();
+
+ void setBgColor(const QColor& _color) { m_bgColor = _color; }
+ void setLeftImageFile(const QString& _file);
+ void setRightImageFile(const QString& _file);
+
+ const QString& leftImageFile(void) const { return m_leftImageFile; }
+ const QString& rightImageFile(void) const { return m_rightImageFile; }
+ QColor bgColor(void) const { return m_bgColor; }
+ QString text(void) const { return m_text; }
+
+public slots:
+ virtual void setText(const QString& txt);
+
+protected:
+ void updatePixmap(void);
+ virtual void resizeEvent ( QResizeEvent * );
+ void drawContents(QPainter *);
+
+private:
+ QImage m_leftImage;
+ QImage m_rightImage;
+ QColor m_bgColor;
+ QColor m_textColor;
+ QString m_text;
+
+ QString m_leftImageFile;
+ QString m_rightImageFile;
+};
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneywizard.cpp b/kmymoney2/widgets/kmymoneywizard.cpp
new file mode 100644
index 0000000..d7fcfdb
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneywizard.cpp
@@ -0,0 +1,376 @@
+/***************************************************************************
+ kmymoneywizard.cpp
+ -------------------
+ copyright : (C) 2006 by Thomas Baumagrt
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpoint.h>
+#include <qfont.h>
+#include <qframe.h>
+#include <qtooltip.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneywizard.h>
+#include "kmymoneywizard_p.h"
+#include <kmymoney/kmymoneytitlelabel.h>
+#include <kmymoney/kguiutils.h>
+
+KMyMoneyWizardPagePrivate::KMyMoneyWizardPagePrivate(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+void KMyMoneyWizardPagePrivate::emitCompleteStateChanged(void)
+{
+ emit completeStateChanged();
+}
+
+
+KMyMoneyWizardPage::KMyMoneyWizardPage(unsigned int step, QWidget* widget, const char* name) :
+ m_step(step),
+ m_widget(widget),
+ d(new KMyMoneyWizardPagePrivate(widget, name))
+{
+ m_mandatoryGroup = new kMandatoryFieldGroup(widget);
+ QObject::connect(m_mandatoryGroup, SIGNAL(stateChanged()), object(), SIGNAL(completeStateChanged()));
+ widget->hide();
+}
+
+QObject* KMyMoneyWizardPage::object(void) const
+{
+ return d;
+}
+
+void KMyMoneyWizardPage::completeStateChanged(void) const
+{
+ d->emitCompleteStateChanged();
+}
+
+void KMyMoneyWizardPage::resetPage(void)
+{
+}
+
+void KMyMoneyWizardPage::enterPage(void)
+{
+}
+
+void KMyMoneyWizardPage::leavePage(void)
+{
+}
+
+KMyMoneyWizardPage* KMyMoneyWizardPage::nextPage(void) const
+{
+ return 0;
+}
+
+bool KMyMoneyWizardPage::isLastPage(void) const
+{
+ return nextPage() == 0;
+}
+
+bool KMyMoneyWizardPage::isComplete(void) const
+{
+ if(!isLastPage())
+ QToolTip::add(wizard()->m_nextButton, i18n("Continue with next page"));
+ else
+ QToolTip::add(wizard()->m_finishButton, i18n("Finish wizard"));
+ return m_mandatoryGroup->isEnabled();
+}
+
+const QString& KMyMoneyWizardPage::helpContext(void) const
+{
+ return QString::null;
+}
+
+KMyMoneyWizard::KMyMoneyWizard(QWidget *parent, const char *name, bool modal, WFlags f) :
+ QDialog(parent, name, modal, f),
+ m_step(0)
+{
+ // enable the little grip in the right corner
+ setSizeGripEnabled(true);
+
+ // create buttons
+ m_cancelButton = new KPushButton(i18n("&Cancel"), this);
+ m_backButton = new KPushButton(i18n("&Back"), this);
+ m_nextButton = new KPushButton(i18n("&Next"), this);
+ m_finishButton = new KPushButton(i18n("&Finish"), this);
+ m_helpButton = new KPushButton(i18n("&Help"), this);
+
+ if ( KGlobalSettings::showIconsOnPushButtons() )
+ {
+ m_backButton->setIconSet( KStdGuiItem::back( KStdGuiItem::UseRTL ).iconSet() );
+ m_nextButton->setIconSet( KStdGuiItem::forward( KStdGuiItem::UseRTL ).iconSet() );
+ m_finishButton->setIconSet( SmallIconSet( "apply" ) );
+ m_cancelButton->setIconSet( SmallIconSet( "button_cancel" ) );
+ m_helpButton->setIconSet( SmallIconSet( "help" ) );
+ }
+
+ // create button layout
+ m_buttonLayout = new QHBoxLayout;
+ m_buttonLayout->addWidget(m_helpButton);
+ m_buttonLayout->addStretch(1);
+ m_buttonLayout->addWidget(m_backButton);
+ m_buttonLayout->addWidget(m_nextButton);
+ m_buttonLayout->addWidget(m_finishButton);
+ m_buttonLayout->addWidget(m_cancelButton);
+
+ // create wizard layout
+ m_wizardLayout = new QVBoxLayout(this, 6, 0, "wizardLayout");
+ m_titleLabel = new KMyMoneyTitleLabel(this, "titleLabel");
+ m_wizardLayout->addWidget(m_titleLabel);
+
+ QHBoxLayout* hboxLayout = new QHBoxLayout(0, 0, 6, "hboxLayout");
+
+ // create stage layout and frame
+ m_stepFrame = new QFrame(this, "stepFrame");
+ m_stepFrame->setPaletteBackgroundColor(KGlobalSettings::highlightColor());
+ m_stepLayout = new QVBoxLayout(m_stepFrame, 11, 6, "stepLayout");
+ m_stepLayout->addWidget(new QLabel("", m_stepFrame));
+ m_stepLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
+ m_stepLabel = new QLabel(m_stepFrame, "stepLabel");
+ m_stepLabel->setAlignment(Qt::AlignHCenter);
+ m_stepLayout->addWidget(m_stepLabel);
+ hboxLayout->addWidget(m_stepFrame);
+
+ // FIXME use the protected virtual method QWidget::paletteChange() to update the palette
+ // information when the user selected a different color set using the KConfigCenter
+ m_stepPalette = m_stepLabel->palette();
+ QColorGroup::ColorRole role = QColorGroup::Foreground;
+ QColor color = KGlobalSettings::highlightedTextColor();
+ m_stepPalette.setColor( QPalette::Active, role, color );
+ m_stepPalette.setColor( QPalette::Inactive, role, color );
+ m_stepPalette.setColor( QPalette::Disabled, role, color );
+ m_stepLabel->setPalette(m_stepPalette);
+
+ // create page layout
+ m_pageLayout = new QVBoxLayout(0, 0, 6, "pageLayout");
+
+ // the page will be inserted later dynamically above this line
+ QFrame* line = new QFrame( this, "line" );
+ line->setFrameShadow( QFrame::Sunken );
+ line->setFrameShape( QFrame::HLine );
+ m_pageLayout->addWidget( line );
+ m_pageLayout->addLayout(m_buttonLayout);
+
+ // now glue everything together
+ hboxLayout->addLayout(m_pageLayout);
+ m_wizardLayout->addLayout(hboxLayout);
+
+ resize(QSize(770, 520).expandedTo(minimumSizeHint()));
+ clearWState(WState_Polished);
+
+ m_titleLabel->setText("No Title specified");
+ m_titleLabel->setRightImageFile("pics/titlelabel_background.png");
+
+ m_finishButton->hide();
+
+ connect(m_backButton, SIGNAL(clicked()), this, SLOT(backButtonClicked()));
+ connect(m_nextButton, SIGNAL(clicked()), this, SLOT(nextButtonClicked()));
+ connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_finishButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_helpButton, SIGNAL(clicked()), this, SLOT(helpButtonClicked()));
+}
+
+void KMyMoneyWizard::setTitle(const QString& txt)
+{
+ m_titleLabel->setText(txt);
+}
+
+void KMyMoneyWizard::addStep(const QString& text)
+{
+ QLabel* step = new QLabel(text, m_stepFrame);
+ step->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ step->setAlignment(Qt::AlignHCenter);
+ step->setFrameStyle(QFrame::Box | QFrame::Sunken);
+ step->setMargin(2);
+ step->setPalette( m_stepPalette );
+
+ m_steps.append(step);
+ m_stepLayout->insertWidget(m_steps.count(), step);
+
+ QFont font(step->font());
+ font.setBold(true);
+ QFontMetrics fm(font);
+ int w = fm.width(text)+30;
+ if(m_stepFrame->minimumWidth() < w) {
+ m_stepFrame->setMinimumWidth(w);
+ }
+}
+
+void KMyMoneyWizard::setStepHidden(unsigned int step, bool hidden)
+{
+ if((step < 1) || (step > m_steps.count()))
+ return;
+
+ m_steps[--step]->setHidden(hidden);
+ updateStepCount();
+}
+
+void KMyMoneyWizard::selectStep(unsigned int step)
+{
+ if((step < 1) || (step > m_steps.count()))
+ return;
+
+ m_step = step;
+ QValueList<QLabel*>::iterator it_l;
+ QFont f = m_steps[0]->font();
+ for(it_l = m_steps.begin(); it_l != m_steps.end(); ++it_l) {
+ f.setBold(false);
+ (*it_l)->setFrameStyle(QFrame::NoFrame);
+ if(--step == 0) {
+ f.setBold(true);
+ (*it_l)->setFrameStyle(QFrame::Box | QFrame::Sunken);
+ }
+ (*it_l)->setFont(f);
+ }
+ updateStepCount();
+}
+
+void KMyMoneyWizard::reselectStep(void)
+{
+ selectStep(m_step);
+}
+
+void KMyMoneyWizard::updateStepCount(void)
+{
+ QValueList<QLabel*>::iterator it_l;
+ int stepCount = 0;
+ int hiddenAdjust = 0;
+ int step = 0;
+ for(it_l = m_steps.begin(); it_l != m_steps.end(); ++it_l) {
+ if(!(*it_l)->isHidden())
+ ++stepCount;
+ else if(step < m_step)
+ hiddenAdjust++;
+ ++step;
+ }
+ m_stepLabel->setText(i18n("Step %1 of %2").arg(m_step - hiddenAdjust).arg(stepCount));
+}
+
+void KMyMoneyWizard::setFirstPage(KMyMoneyWizardPage* page)
+{
+ page->resetPage();
+ m_history.clear();
+ m_history.append(page);
+ switchPage(0);
+}
+
+void KMyMoneyWizard::switchPage(KMyMoneyWizardPage* oldPage)
+{
+ if(oldPage) {
+ oldPage->widget()->hide();
+ m_pageLayout->remove(oldPage->widget());
+ disconnect(oldPage->object(), SIGNAL(completeStateChanged()), this, SLOT(completeStateChanged()));
+ }
+ KMyMoneyWizardPage* newPage = m_history.back();
+ if(newPage) {
+ m_pageLayout->insertWidget(0, newPage->widget());
+ connect(newPage->object(), SIGNAL(completeStateChanged()), this, SLOT(completeStateChanged()));
+ newPage->widget()->show();
+ selectStep(newPage->step());
+ if(newPage->isLastPage()) {
+ m_nextButton->setDefault(false);
+ m_finishButton->setDefault(true);
+ } else {
+ m_finishButton->setDefault(false);
+ m_nextButton->setDefault(true);
+ }
+ QWidget* w = newPage->initialFocusWidget();
+ if(w)
+ w->setFocus();
+ }
+ completeStateChanged();
+}
+
+void KMyMoneyWizard::backButtonClicked(void)
+{
+ KMyMoneyWizardPage* oldPage = m_history.back();
+ m_history.pop_back();
+ oldPage->leavePage();
+ oldPage->resetPage();
+ switchPage(oldPage);
+}
+
+void KMyMoneyWizard::nextButtonClicked(void)
+{
+ // make sure it is really complete. Some widgets only change state during focusOutEvent,
+ // so we just create such an animal by changing the focus to the next button and
+ // check again for copmpleness
+ m_nextButton->setFocus();
+ KMyMoneyWizardPage* oldPage = m_history.back();
+ if(oldPage->isComplete()) {
+ KMyMoneyWizardPage* newPage = oldPage->nextPage();
+ m_history.append(newPage);
+ newPage->enterPage();
+ newPage->resetPage();
+ switchPage(oldPage);
+ }
+}
+
+void KMyMoneyWizard::helpButtonClicked(void)
+{
+ KMyMoneyWizardPage* currentPage = m_history.back();
+ QString ctx = currentPage->helpContext();
+ if(ctx.isEmpty())
+ ctx = m_helpContext;
+ kapp->invokeHelp(ctx);
+}
+
+void KMyMoneyWizard::completeStateChanged(void)
+{
+ KMyMoneyWizardPage* currentPage = m_history.back();
+ bool lastPage = currentPage->isLastPage();
+
+ m_finishButton->setShown(lastPage);
+ m_nextButton->setShown(!lastPage);
+
+ KPushButton* button;
+
+ button = lastPage ? m_finishButton : m_nextButton;
+
+ bool rc = currentPage->isComplete();
+ button->setEnabled(rc);
+
+ m_backButton->setEnabled(m_history.count() > 1);
+}
+
+void KMyMoneyWizard::accept(void)
+{
+ // make sure it is really complete. Some widgets only change state during focusOutEvent,
+ // so we just create such an animal by changing the focus to the finish button and
+ // check again for completeness.
+ m_finishButton->setFocus();
+ KMyMoneyWizardPage* page = m_history.back();
+ if(page->isComplete())
+ QDialog::accept();
+}
+
+#include "kmymoneywizard.moc"
+
diff --git a/kmymoney2/widgets/kmymoneywizard.h b/kmymoney2/widgets/kmymoneywizard.h
new file mode 100644
index 0000000..21b57b4
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneywizard.h
@@ -0,0 +1,539 @@
+/***************************************************************************
+ kmymoneywizard.h
+ -------------------
+ copyright : (C) 2006 by Thomas Baumagrt
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYWIZARD_H
+#define KMYMONEYWIZARD_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdialog.h>
+#include <qvaluelist.h>
+#include <qpalette.h>
+class QVBoxLayout;
+class QHBoxLayout;
+class QLabel;
+class QFrame;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KPushButton;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KMyMoneyTitleLabel;
+class KMyMoneyWizard;
+class KMyMoneyWizardPagePrivate;
+class kMandatoryFieldGroup;
+
+/**
+ * @author Thomas Baumgart (C) 2006
+ *
+ * @note: the following documentation is somewhat outdated
+ * as of May 2007. Wizards should use a namespace
+ * for the pages and can use the WizardPage<T> template class.
+ * See the NewUserWizard class and NewUserWizardPages namespace
+ * as an example of this setup.
+ *
+ * This class represents the base class for wizard pages for the
+ * KMyMoneyWizard. One cannot create a wizard page directly, but
+ * must derive from it. The KMyMoneyWizardPage class provides the
+ * necessary functionality to work in concert with KMyMoneyWizard.
+ *
+ * Therefore, few steps are necessary to use this class. They seem to
+ * be awkward at some stage, but I wanted to be able to use Qt designer
+ * to actually design the widget for the page. That's why some things
+ * aren't implemented in a more straight fashion than one would
+ * normally do this.
+ *
+ * The first step is to derive a specific base page for the specific wizard.
+ * In this example we use the name NewUser as template for the specific wizard.
+ * This class provides a 'back'-pointer to the actual wizard object
+ * for all pages.
+ *
+ * @code
+ * class KNewUserPage : public KMyMoneyWizardPage
+ * {
+ * public:
+ * KNewUserPage(unsigned int step, QWidget* widget, KNewUserWizard* parent, const char* name);
+ *
+ * protected:
+ * KNewUserWizard* m_wizard;
+ * }
+ * @endcode
+ *
+ * The implementation of this class is rather straight-forward:
+ *
+ * @code
+ * KNewUserPage::KNewUserPage(unsigned int step, QWidget* widget, KNewUserWizard* parent, const char* name) :
+ * KMyMoneyWizardPage(step, widget, name),
+ * m_wizard(parent)
+ * {
+ * }
+ * @endcode
+ *
+ * For each page of the wizard, you will have to create a @p ui file with
+ * Qt designer.
+ * Let's assume we call the first page of the wizard 'General' and go
+ * from there.
+ * We also assume, that the wizard has more than one page.
+ * The ui designer generated class should have the name KNewUserGeneralDecl
+ * as all other dialogs. The class definition of KNewUserGeneral will
+ * look like this:
+ *
+ * @code
+ * class KNewUserGeneral : public KNewUserGeneralDecl, public KNewUserPage
+ * {
+ * Q_OBJECT
+ * public:
+ * KNewUserGeneral(KNewUserWizard* parent, const char* name = 0);
+ * KMyMoneyWizardPage* nextPage(void);
+ * bool isLastPage(void) { return false; }
+ *
+ * protected:
+ * KNewUserWizard* m_wizard;
+ * }
+ * @endcode
+ *
+ * The implementation depends heavily on the logic of your code. If you only
+ * fill some widgets, it could be as simple as:
+ *
+ * @code
+ * KNewUserGeneral::KNewUserGeneral(KNewUserWizard* parent, const char* name) :
+ * KNewUserGeneralDecl(parent),
+ * KNewUserPage(1, this, parent, name)
+ * {
+ * kMandatoryFieldGroup* mandatoryGroup = new kMandatoryFieldGroup(this);
+ * mandatoryGroup->add(m_userName);
+ * connect(m_mandatoryGroup, SIGNAL(stateChanged()), object(), SIGNAL(completeStateChanged()));
+ * }
+ *
+ * KMyMoneyWizardPage* KNewUserGeneral::nextPage(void)
+ * {
+ * return m_wizard->m_personalPage;
+ * }
+ * @endcode
+ *
+ * A note on the first parameter to KNewUserPage in the above example: it ties
+ * this page to be part of step 1 (see KMyMoneyWizard::addStep() for details).
+ *
+ * Depending on the actual logic of the page, you would want to override the
+ * following methods: resetPage, nextPage, isLastPage and isComplete.
+ *
+ * @note The implementation of this class is heavily based on ideas found at
+ * http://doc.trolltech.com/4.1/dialogs-complexwizard.html
+ */
+class KMyMoneyWizardPage
+{
+public:
+ /**
+ * This method is called by the wizard when the page is entered from
+ * the previous page. The default implementation does nothing.
+ */
+ virtual void enterPage(void);
+
+ /**
+ * This method is called by the wizard when the page is left to return to
+ * the previous page. The default implementation does nothing.
+ */
+ virtual void leavePage(void);
+
+ /**
+ * This method is called by the wizard whenever a page is entered
+ * (either in forward or backward direction). The default
+ * implementation does nothing.
+ */
+ virtual void resetPage(void);
+
+ /**
+ * This method returns a pointer to the next page that should be
+ * shown when the user presses the 'Next' button.
+ *
+ * @return pointer to next wizard page
+ */
+ virtual KMyMoneyWizardPage* nextPage(void) const;
+
+ /**
+ * This returns, if the current page is the last page of the wizard.
+ * The default implementation returns @p false if nextPage() returns 0,
+ * @p true otherwise.
+ *
+ * @retval false more pages follow
+ * @retval true this is the last page of the wizard
+ */
+ virtual bool isLastPage(void) const;
+
+ /**
+ * This returns, if all necessary data for this page has been
+ * filled. It is used to enabled the 'Next' or 'Finish' button.
+ * The button is only enabled, if this method returns @p true,
+ * which is the default implementation.
+ *
+ * @retval false more data required from the user before we can proceed
+ * @retval true all data available, we allow to switch to the next page
+ */
+ virtual bool isComplete(void) const;
+
+ /**
+ * This method returns the step to which this page belongs.
+ * It is required by the KMyMoneyWizard and is not intended
+ * to be used by application code.
+ *
+ * @return step of wizard this page belongs to
+ */
+ unsigned int step(void) const { return m_step; }
+
+ /**
+ * This method returns a pointer to the widget of the page.
+ * It is required by the KMyMoneyWizard and is not intended
+ * to be used by application code.
+ *
+ * @return pointer to widget of page
+ */
+ QWidget* widget(void) const { return m_widget; }
+
+ /**
+ * This method returns a pointer to the QObject used for
+ * the signal/slot mechanism.
+ * It is required by the KMyMoneyWizard and can be used
+ * by application code for signal/slot connections as well.
+ * Other use is not foreseen.
+ */
+ QObject* object(void) const;
+
+ /**
+ * This method returns a pointer to the widget which should
+ * receive the focus when the page is opened.
+ *
+ * @return pointer to widget or 0 if none is to be selected
+ * The default implementation returns 0
+ */
+ virtual QWidget* initialFocusWidget(void) const { return 0; }
+
+ virtual KMyMoneyWizard* wizard(void) const = 0;
+
+ /**
+ * This method returns a specific help context for the page shown
+ * The default returns an empty string.
+ */
+ virtual const QString& helpContext(void) const;
+
+ virtual ~KMyMoneyWizardPage() {}
+protected:
+ /**
+ * Constructor (kept protected, so that one cannot create such an object directly)
+ */
+ KMyMoneyWizardPage(unsigned int step, QWidget* widget, const char* name = 0);
+
+ /**
+ * This method must be called by the implementation when the
+ * data in the fields of the wizard change and the state of
+ * completeness changed.
+ *
+ * @note If you do not override isComplete() then there is no need
+ * to call this method.
+ */
+ void completeStateChanged(void) const;
+
+protected:
+ kMandatoryFieldGroup* m_mandatoryGroup;
+
+private:
+ unsigned int m_step;
+ QWidget* m_widget;
+ KMyMoneyWizardPagePrivate* const d;
+};
+
+
+/**
+ * The general base class for wizard pages
+ *
+ * @author Thomas Baumgart
+ */
+template <class T>
+ class WizardPage : public KMyMoneyWizardPage
+{
+public:
+ WizardPage(unsigned int step, QWidget* widget, T* parent, const char* name) :
+ KMyMoneyWizardPage(step, widget, name),
+ m_wizard(parent),
+ m_wizardBase(parent)
+ {
+ }
+ virtual ~WizardPage() {}
+ virtual KMyMoneyWizard* wizard(void) const { return m_wizardBase; }
+
+protected:
+ T* m_wizard;
+ KMyMoneyWizard* m_wizardBase;
+};
+
+
+/**
+ * @author Thomas Baumgart (C) 2006
+ *
+ * This is a base class for implementation of the KMyMoneyWizard. It provides
+ * the following layout of a wizard:
+ *
+ * @code
+ * +-wizardLayout-----------------------------------------------+
+ * | |
+ * +------------------------------------------------------------+
+ * |+-stepLayout--++-------------------------------------------+|
+ * || ||+-pageLayout------------------------------+||
+ * || ||| |||
+ * || ||| |||
+ * || ||| |||
+ * || ||| |||
+ * || ||| |||
+ * || ||| |||
+ * || ||+-----------------------------------------+||
+ * || |||+-buttonLayout--------------------------+|||
+ * || |||| ||||
+ * || |||+---------------------------------------+|||
+ * || ||+-----------------------------------------+||
+ * |+-------------++-------------------------------------------+|
+ * +------------------------------------------------------------+
+ * @endcode
+ *
+ * The top bar is filled with a KMyMoneyTitleLabel as known from
+ * KMyMoney's views. To the left there is an area in the same color
+ * as the title bar showing the steps for this wizard. Each such step
+ * can consist of one or more wizard pages. At the bottom of this area
+ * the text "Step x of y" is shown and updated. To the right of this
+ * part, the actual wizard page is shown. At the bottom of the page
+ * the class inserts a standard button widget consisting of a Help,
+ * Back, Next/Finish and Cancel button.
+ *
+ * The wizard serves as container for the wizard pages. In order to access
+ * the data filled into the pages, one would have to provide getter methods.
+ *
+ * Here is an example how this object could be used. Please also see the
+ * example described with the KMyMoneyWizardPage class.
+ *
+ * @code
+ *
+ * class KNewUserGeneral;
+ * class KNewUserPersonal;
+ *
+ * class KNewUserWizard : public KMyMoneyWizard
+ * {
+ * Q_OBJECT
+ * public:
+ * KNewUserWizard(QWidget* parent = 0, const char* name = 0, bool modal = false, WFlags flags = 0);
+ *
+ * private:
+ * KNewUserGeneral* m_generalPage;
+ * KNewUserPersonal* m_personalPage;
+ * KNewUserFinal* m_finalPage;
+ * // add more pages here
+ *
+ * friend class KNewUserGeneral;
+ * friend class KNewUserPersonal;
+ * friend class KNewUserFinal;
+ * // add more pages here
+ * };
+ * @endcode
+ *
+ * The implementation is also easy and looks like this:
+ *
+ * @code
+ * KNewUserWizard::KNewUserWizard(QWidget* parent, const char* name, bool modal, WFlags flags) :
+ * KMyMoneyWizard(parent, name, modal, flags)
+ * {
+ * setTitle("KMyMoney New User Setup");
+ * addStep("General Data");
+ * addStep("Personal Data");
+ * addStep("Finish");
+ *
+ * m_generalPage = new KNewUserGeneral(this);
+ * m_personalPage = new KNewUserPersonal(this);
+ * m_finalPage = new KNewUserFinal(this);
+ *
+ * setFirstPage(m_testPage1);
+ * }
+ * @endcode
+ *
+ * Don't forget to call setFirstPage() to get things started.
+ *
+ * The code to use this whole structure would then look something like this:
+ *
+ * @code
+ * KNewUserWizard* wizard = new KNewUserWizard(this, "NewUserWizard");
+ * int rc = wizard->exec();
+ * @endcode
+ *
+ * The return code of exec() is either @p QDialog::Accepted or
+ * @p QDialog::Rejected.
+ *
+ * @note The implementation of this class is heavily based on ideas found at
+ * http://doc.trolltech.com/4.1/dialogs-complexwizard.html
+ */
+class KMyMoneyWizard : public QDialog
+{
+ friend class KMyMoneyWizardPage;
+
+ Q_OBJECT
+public:
+ /**
+ * Modify the title of the wizard to be @p txt.
+ *
+ * @param txt The text that should be used as title
+ */
+ void setTitle(const QString& txt);
+
+ /**
+ * Add step @p text to the wizard
+ *
+ * @param text Text to be shown for this step
+ */
+ void addStep(const QString& text);
+
+ QValueList<KMyMoneyWizardPage*> historyPages(void) const { return m_history; }
+
+ /**
+ * This method repeats selection of the current step in the
+ * step frame.
+ * This is used to allow changes made to showing and hiding
+ * pages to immediately to be reflected in the step frame
+ */
+ void reselectStep(void);
+
+ /**
+ * Setup a global help context for the wizard. It will be used whenever
+ * there is no specific help context available for the current page.
+ *
+ * @sa KMyMoneyWizardPage::helpContext()
+ */
+ void setHelpContext(const QString& ctx) { m_helpContext = ctx; }
+
+ virtual ~KMyMoneyWizard(){}
+
+signals:
+ /**
+ * This signal is sent out, when a new payee needs to be created
+ * @sa KMyMoneyCombo::createItem()
+ *
+ * @param txt The name of the payee to be created
+ * @param id A connected slot should store the id of the created object in this variable
+ */
+ void createPayee(const QString& txt, QString& id);
+
+ /**
+ * This signal is sent out, when a new category needs to be created
+ * @sa KMyMoneyCombo::createItem()
+ *
+ * @param txt The name of the category to be created
+ * @param id A connected slot should store the id of the created object in this variable
+ */
+ void createCategory(const QString& txt, QString& id);
+
+protected:
+ /**
+ * Constructor (kept protected, so that one cannot create such an object directly)
+ */
+ KMyMoneyWizard(QWidget *parent = 0, const char *name = 0, bool modal = false, WFlags f = 0);
+
+ /**
+ * This method sets up the first page after creation of the object
+ *
+ * @param page pointer to first page of wizard
+ */
+ void setFirstPage(KMyMoneyWizardPage* page);
+
+ /**
+ * This method allows to hide or show a @p step.
+ *
+ * @param step step to be shown/hidden
+ * @param hidden hide step if true (the default) or show it if false
+ */
+ void setStepHidden(unsigned int step, bool hidden = true);
+
+protected slots:
+ virtual void accept(void);
+ void completeStateChanged(void);
+
+private:
+ void updateStepCount(void);
+
+private slots:
+ void backButtonClicked(void);
+ void nextButtonClicked(void);
+ void helpButtonClicked(void);
+
+protected:
+ /*
+ * The buttons
+ */
+ KPushButton* m_cancelButton;
+ KPushButton* m_backButton;
+ KPushButton* m_nextButton;
+ KPushButton* m_finishButton;
+ KPushButton* m_helpButton;
+
+private:
+ /**
+ * Switch to page which is currently the top of the history stack.
+ * @p oldPage is a pointer to the current page or 0 if no page
+ * is shown.
+ *
+ * @param oldPage pointer to currently displayed page
+ */
+ void switchPage(KMyMoneyWizardPage* oldPage);
+
+ /**
+ * This method selects the step given by @p step.
+ *
+ * @param step step to be selected
+ */
+ void selectStep(unsigned int step);
+
+ /*
+ * The layouts
+ */
+ QVBoxLayout* m_wizardLayout;
+ QVBoxLayout* m_stepLayout;
+ QVBoxLayout* m_pageLayout;
+ QHBoxLayout* m_buttonLayout;
+
+ /*
+ * Some misc. widgets required
+ */
+ QFrame* m_stepFrame;
+ QLabel* m_stepLabel;
+ QPalette m_stepPalette;
+
+ QValueList<QLabel*> m_steps; // the list of step labels
+ int m_step; // the currently selected step
+
+ /*
+ * The title bar
+ */
+ KMyMoneyTitleLabel* m_titleLabel;
+
+ /*
+ * The history stack
+ */
+ QValueList<KMyMoneyWizardPage*> m_history;
+
+ QString m_helpContext;
+};
+
+
+
+#endif
diff --git a/kmymoney2/widgets/kmymoneywizard_p.h b/kmymoney2/widgets/kmymoneywizard_p.h
new file mode 100644
index 0000000..92d1152
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneywizard_p.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ kmymoneywizard_p.h
+ -------------------
+ copyright : (C) 2006 by Thomas Baumagrt
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYWIZARD_P_H
+#define KMYMONEYWIZARD_P_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+/**
+ * @author Thomas Baumgart (C) 2006
+ *
+ * This class represents a helper object required
+ * to be able to use Qt's signal/slot mechanism within
+ * the KMyMoneyWizardPage object which cannot be
+ * derived from QObject directly.
+ */
+class KMyMoneyWizardPagePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KMyMoneyWizardPagePrivate(QObject* parent, const char* name = 0);
+
+ void emitCompleteStateChanged(void);
+
+signals:
+ void completeStateChanged(void);
+};
+
+#endif
diff --git a/kmymoney2/widgets/kschedulebriefwidget.ui b/kmymoney2/widgets/kschedulebriefwidget.ui
new file mode 100644
index 0000000..7dc523d
--- /dev/null
+++ b/kmymoney2/widgets/kschedulebriefwidget.ui
@@ -0,0 +1,351 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>kScheduleBriefWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kScheduleBriefWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>341</width>
+ <height>339</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Schedules</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="midLineWidth">
+ <number>100</number>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_prevButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_indexLabel</cstring>
+ </property>
+ <property name="text">
+ <string>n of n</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>70</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_nextButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>60</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>60</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_name</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_account</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_type</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>60</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Account:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>m_details</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>35</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_buttonEnter</cstring>
+ </property>
+ <property name="text">
+ <string>Enter...</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_skipButton</cstring>
+ </property>
+ <property name="text">
+ <string>Skip</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ <property name="stdItem" stdset="0">
+ <number>13</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>43</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/makekdewidgets.in b/kmymoney2/widgets/makekdewidgets.in
new file mode 100755
index 0000000..364ca1b
--- /dev/null
+++ b/kmymoney2/widgets/makekdewidgets.in
@@ -0,0 +1,197 @@
+#!@PERL@
+
+# copied from KDELIBS 3.1.4
+# modified for usage with KMyMoney
+
+use strict;
+use vars qw($group $incpath $name $out @includes $init $destroy %widgets);
+
+sub usage
+{
+ print STDERR "$_[0]\n" if @_;
+ print STDERR <<EOT;
+Usage: $0 [options] [<widget spec> ...]
+Generates a Qt designer-plugin for the widget set defined in widget spec
+or STDIN if no filename is given
+
+Options:
+ -g <group> default widget group name to display in designer
+ (default: KDE)
+ -i <path> path to prepend to include file (default: none)
+ -n <plugin name> name of the plugin class to generate
+ (default: <group>WidgetsPlugin)
+ -o <filename> write output to filename (default: STDOUT)
+EOT
+ exit 1;
+}
+
+sub warning($) { print STDERR "Warning: $_[0]\n" }
+
+my ($class, %defs);
+sub addwidget
+{
+ return if $class =~ /^(Includes|Init|Destroy)$/;
+ if(! exists $defs{IncludeFile}) {
+ $defs{IncludeFile} = join('/', $incpath, lc "$class.h") if ($incpath ne "");
+ $defs{IncludeFile} = lc "$class.h" unless ($incpath ne "");
+ }
+ $defs{ImplClass} = $class unless exists $defs{ImplClass};
+ $defs{Group} = $group unless exists $defs{Group};
+ $defs{ToolTip} = $class unless exists $defs{ToolTip};
+ $defs{WhatsThis} = $class unless exists $defs{Long};
+ $defs{IconSet} = lc "$class.png" unless exists $defs{IconSet};
+ $defs{ConstructorArgs} = '(parent, name)' unless exists $defs{ConstructorArgs};
+ $defs{IsContainer} = $defs{IsContainer} ? 'true' : 'false';
+ $widgets{$class} = { %defs };
+}
+
+$group = 'KDE';
+$incpath = "";
+
+while ($ARGV[0] =~ /^-/)
+{
+ my $opt = shift @ARGV;
+ usage "missing parameter for $opt" unless @ARGV;
+ if ($opt eq '-g') { $group = shift @ARGV }
+ elsif ($opt eq '-n') { $name = shift @ARGV }
+ elsif ($opt eq '-o') { $out = shift @ARGV }
+ elsif ($opt eq '-i') { $incpath = shift @ARGV }
+ else { usage "Unknown option $opt" }
+}
+
+$name = "${group}WidgetsPlugin" unless $name;
+warning "classname changed to \"$name\""
+ if $name =~ s/(^[^A-Za-z_]+|[^A-Za-z0-9_])/_/g;
+
+while (<>)
+{
+ chomp;
+ next if /^(#|\s*$)/;
+
+ if (/^\s*\[([A-Za-z_][A-Za-z0-9_:]*)\]\s*$/)
+ {
+ addwidget if $class;
+ %defs = {};
+ $class = $1;
+ next;
+ }
+ elsif (/^\s*\[(.*)\]\s*$/) { die "Invalid class name \"$1\"" }
+ die "Not in a widget definition" unless $class;
+ if ($class eq 'Includes') { push @includes, $_ }
+ elsif ($class eq 'Init') { $init .= "\n\t$_" }
+ elsif ($class eq 'Destroy') { $destroy .= "\n\t$_" }
+ elsif (/^\s*(IncludeFile|ImplClass|Group|ToolTip|WhatsThis|IconSet|ConstructorArgs|IsContainer)\s*=\s*(.*)\s*/)
+ {
+ $defs{$1} = $2;
+ }
+ else { die "Syntax error on line $." }
+}
+addwidget if $class;
+
+warning "Nothing to do", exit 0 unless %widgets;
+
+my @keys = sort keys %widgets;
+
+if ($out) { open OUT, ">$out" or die "Can't open $out for writing" }
+else { open OUT, ">&STDOUT" }
+
+(my $scriptname = $0) =~ s|^.*/||;
+print OUT <<EOT;
+/*
+ * This file was autogenerated by $scriptname. Any changes will be lost!
+ */
+
+#include <qwidgetplugin.h>
+// for pixmap search
+#include <kstandarddirs.h>
+
+EOT
+
+print OUT map { "#include \"$_\"\n" } @includes, map { $widgets{$_}->{IncludeFile} } @keys;
+
+print OUT <<EOT;
+
+class $name : public QWidgetPlugin
+{
+public:
+ $name();
+ virtual ~$name();
+
+ virtual QStringList keys() const
+ {
+ QStringList result;
+ for (WidgetInfos::ConstIterator it = m_widgets.begin(); it != m_widgets.end(); ++it)
+ result << it.key();
+ return result;
+ }
+ virtual QWidget *create(const QString &key, QWidget *parent = 0, const char *name = 0);
+ virtual QIconSet iconSet(const QString &key) const
+ {
+ QString path = locate("data", "kmymoney2/pics/" + m_widgets[key].iconSet);
+ return QIconSet(path);
+ }
+ virtual bool isContainer(const QString &key) const
+ {
+ return m_widgets[key].isContainer;
+ }
+EOT
+
+print OUT map { <<EOT } qw(group includeFile toolTip whatsThis);
+ virtual QString $_(const QString &key) const
+ {
+ return m_widgets[key].$_;
+ }
+EOT
+
+print OUT <<EOT;
+
+private:
+ struct WidgetInfo
+ {
+ QString group;
+ QString iconSet;
+ QString includeFile;
+ QString toolTip;
+ QString whatsThis;
+ bool isContainer;
+ };
+ typedef QMap<QString, WidgetInfo> WidgetInfos;
+ WidgetInfos m_widgets;
+};
+
+${name}::$name()
+{
+ WidgetInfo widget;
+EOT
+
+print OUT map { my $w = $_; "\n", (map { my $attr = ucfirst $_; <<EOT } qw(group iconSet includeFile toolTip whatsThis)), <<EOT } @keys;
+ widget.$_ = "$widgets{$w}->{$attr}";
+EOT
+ widget.isContainer = $widgets{$w}->{IsContainer};
+ m_widgets.insert("$_", widget);
+EOT
+
+print OUT <<EOT;
+$init
+}
+
+${name}::~$name()
+{$destroy
+}
+
+QWidget *${name}::create(const QString &key, QWidget *parent, const char *name)
+{
+EOT
+
+print OUT map { <<EOT } @keys;
+ if (key == "$_")
+ return new $widgets{$_}->{ImplClass}$widgets{$_}->{ConstructorArgs};
+EOT
+
+print OUT <<EOT;
+ return 0;
+}
+
+Q_EXPORT_PLUGIN($name)
+EOT
+
diff --git a/kmymoney2/widgets/register.cpp b/kmymoney2/widgets/register.cpp
new file mode 100644
index 0000000..974ae23
--- /dev/null
+++ b/kmymoney2/widgets/register.cpp
@@ -0,0 +1,2438 @@
+/***************************************************************************
+ register.cpp - description
+ -------------------
+ begin : Fri Mar 10 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <typeinfo>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qtimer.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qtooltip.h>
+#include <qimage.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kurldrag.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/register.h>
+#include <kmymoney/transactionform.h>
+#include <kmymoney/stdtransactiondownloaded.h>
+#include <kmymoney/stdtransactionmatched.h>
+#include "scheduledtransaction.h"
+#include "../kmymoneyglobalsettings.h"
+
+const int LinesPerMemo = 3;
+
+static QString sortOrderText[] = {
+ I18N_NOOP("Unknown"),
+ I18N_NOOP("Post date"),
+ I18N_NOOP("Date entered"),
+ I18N_NOOP("Payee"),
+ I18N_NOOP("Amount"),
+ I18N_NOOP("Number"),
+ I18N_NOOP("Entry order"),
+ I18N_NOOP("Type"),
+ I18N_NOOP("Category"),
+ I18N_NOOP("Reconcile state"),
+ I18N_NOOP("Security")
+ // add new values above this comment line
+ };
+
+using namespace KMyMoneyRegister;
+
+static unsigned char fancymarker_bg_image[] = {
+/* 200x49 */
+ 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,
+ 0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,
+ 0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0x31,
+ 0x08,0x06,0x00,0x00,0x00,0x9F,0xC5,0xE6,
+ 0x4F,0x00,0x00,0x00,0x06,0x62,0x4B,0x47,
+ 0x44,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xA0,
+ 0xBD,0xA7,0x93,0x00,0x00,0x00,0x09,0x70,
+ 0x48,0x59,0x73,0x00,0x00,0x0B,0x13,0x00,
+ 0x00,0x0B,0x13,0x01,0x00,0x9A,0x9C,0x18,
+ 0x00,0x00,0x00,0x86,0x49,0x44,0x41,0x54,
+ 0x78,0xDA,0xED,0xDD,0x31,0x0A,0x84,0x40,
+ 0x10,0x44,0xD1,0x1A,0x19,0x10,0xCF,0xE6,
+ 0xFD,0x4F,0xB2,0x88,0x08,0x22,0x9B,0x18,
+ 0x4E,0x1B,0x2C,0x1B,0x18,0xBC,0x07,0x7D,
+ 0x81,0x82,0x1F,0x77,0x4B,0xB2,0x06,0x18,
+ 0xEA,0x49,0x3E,0x66,0x00,0x81,0x80,0x40,
+ 0xE0,0xDF,0x81,0x6C,0x66,0x80,0x3A,0x90,
+ 0xDD,0x0C,0x50,0x07,0x72,0x98,0x01,0xEA,
+ 0x40,0x4E,0x33,0x40,0x1D,0xC8,0x65,0x06,
+ 0x18,0x6B,0xF7,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xF0,0x16,0x3E,
+ 0x4C,0xC1,0x83,0x9E,0x64,0x32,0x03,0x08,
+ 0x04,0x7E,0x0A,0xA4,0x9B,0x01,0xEA,0x40,
+ 0x66,0x33,0x40,0x1D,0xC8,0x62,0x06,0x18,
+ 0xFB,0x02,0x05,0x87,0x08,0x55,0xFE,0xDE,
+ 0xA2,0x9D,0x00,0x00,0x00,0x00,0x49,0x45,
+ 0x4E,0x44,0xAE,0x42,0x60,0x82
+};
+
+QPixmap* GroupMarker::m_bg = 0;
+int GroupMarker::m_bgRefCnt = 0;
+
+void ItemPtrVector::sort(void)
+{
+ if(count() > 0) {
+ // get rid of 0 pointers in the list
+ KMyMoneyRegister::ItemPtrVector::iterator it_l;
+ RegisterItem *item;
+ for(it_l = begin(); it_l != end(); ++it_l) {
+ if(*it_l == 0) {
+ item = last();
+ *it_l = item;
+ pop_back();
+ --it_l;
+ }
+ }
+
+ std::sort(begin(), end(), item_cmp);
+ }
+}
+
+bool ItemPtrVector::item_cmp(RegisterItem* i1, RegisterItem* i2)
+{
+ const QValueList<TransactionSortField>& sortOrder = i1->parent()->sortOrder();
+ QValueList<TransactionSortField>::const_iterator it;
+ int rc = 0;
+ bool ok1, ok2;
+ Q_ULLONG n1, n2;
+
+ MyMoneyMoney tmp;
+
+ for(it = sortOrder.begin(); it != sortOrder.end(); ++it) {
+ TransactionSortField sortField = static_cast<TransactionSortField>(abs(*it));
+ switch(sortField) {
+ case PostDateSort:
+ rc = i2->sortPostDate().daysTo(i1->sortPostDate());
+ if(rc == 0) {
+ rc = i1->sortSamePostDate() - i2->sortSamePostDate();
+ }
+ break;
+
+ case EntryDateSort:
+ rc = i2->sortEntryDate().daysTo(i1->sortEntryDate());
+ break;
+
+ case PayeeSort:
+ rc = QString::localeAwareCompare(i1->sortPayee(), i2->sortPayee());
+ break;
+
+ case ValueSort:
+ tmp = i1->sortValue() - i2->sortValue();
+ if(tmp.isZero())
+ rc = 0;
+ else if(tmp.isNegative())
+ rc = -1;
+ else
+ rc = 1;
+ break;
+
+ case NoSort:
+ // convert both values to numbers
+ n1 = i1->sortNumber().toULongLong(&ok1);
+ n2 = i2->sortNumber().toULongLong(&ok2);
+ // the following four cases exist:
+ // a) both are converted correct
+ // compare them directly
+ // b) n1 is numeric, n2 is not
+ // numbers come first, so return -1
+ // c) n1 is not numeric, n2 is
+ // numbers come first, so return 1
+ // d) both are non numbers
+ // compare using localeAwareCompare
+ if(ok1 && ok2) { // case a)
+ rc = (n1 > n2) ? 1 : ((n1 == n2 ) ? 0 : -1);
+ } else if(ok1 && !ok2) {
+ rc = -1;
+ } else if(!ok1 && ok2) {
+ rc = 1;
+ } else
+ rc = QString::localeAwareCompare(i1->sortNumber(), i2->sortNumber());
+ break;
+
+ case EntryOrderSort:
+ rc = qstrcmp(i1->sortEntryOrder(), i2->sortEntryOrder());
+ break;
+
+ case TypeSort:
+ rc = i1->sortType() - i2->sortType();
+ break;
+
+ case CategorySort:
+ rc = QString::localeAwareCompare(i1->sortCategory(), i2->sortCategory());
+ break;
+
+ case ReconcileStateSort:
+ rc = static_cast<int>(i1->sortReconcileState()) - static_cast<int>(i2->sortReconcileState());
+ break;
+
+ case SecuritySort:
+ rc = QString::localeAwareCompare(i1->sortSecurity(), i2->sortSecurity());
+ break;
+
+ default:
+ qDebug("Invalid sort key %d", *it);
+ break;
+ }
+
+ // the items differ for this sort key so we can return a result
+ if(rc != 0)
+ return (*it < 0) ? rc >= 0 : rc < 0;
+ }
+
+ if(rc == 0) {
+ rc = qstrcmp(i1->sortEntryOrder(), i2->sortEntryOrder());
+ }
+
+ return rc < 0;
+}
+
+GroupMarker::GroupMarker(Register *parent, const QString& txt) :
+ RegisterItem(parent),
+ m_txt(txt),
+ m_drawCounter(parent->drawCounter()-1), // make sure we get painted the first time around
+ m_showDate(false)
+{
+ int h;
+ if(m_parent) {
+ h = m_parent->rowHeightHint();
+ } else {
+ QFontMetrics fm( KMyMoneyGlobalSettings::listCellFont() );
+ h = fm.lineSpacing()+6;
+ }
+
+ if(m_bg && (m_bg->height() != h)) {
+ delete m_bg;
+ m_bg = 0;
+ }
+
+ // convert the backgroud once
+ if(m_bg == 0) {
+ m_bg = new QPixmap;
+ m_bg->loadFromData(fancymarker_bg_image, sizeof(fancymarker_bg_image));
+
+ // for now, we can't simply resize the m_bg member as Qt does not support
+ // alpha resizing. So we take the (slow) detour through a QImage object
+ // which is ok, since we do this only once.
+ // m_bg->resize(m_bg->width(), h);
+ QImage img(m_bg->convertToImage());
+ img = img.smoothScale(img.width(), h);
+ m_bg->convertFromImage(img);
+ }
+
+ ++m_bgRefCnt;
+}
+
+GroupMarker::~GroupMarker()
+{
+ --m_bgRefCnt;
+ if(!m_bgRefCnt) {
+ delete m_bg;
+ m_bg = 0;
+ }
+}
+
+void GroupMarker::paintRegisterCell(QPainter* painter, int row, int /* col */, const QRect& _r, bool /*selected*/, const QColorGroup& _cg)
+{
+ // avoid painting the marker twice for the same update round
+ unsigned int drawCounter = m_parent->drawCounter();
+ if(m_drawCounter == drawCounter) {
+ return;
+ }
+ m_drawCounter = drawCounter;
+
+ QRect r(_r);
+ painter->save();
+ painter->translate(-r.x(), -r.y());
+
+ // the group marker always uses all cols
+ r.setX(m_parent->columnPos(0));
+ r.setWidth(m_parent->visibleWidth());
+ painter->translate(r.x(), r.y());
+
+ QRect cellRect;
+ cellRect.setX(0);
+ cellRect.setY(0);
+ cellRect.setWidth(m_parent->visibleWidth());
+ cellRect.setHeight(m_parent->rowHeight(row + m_startRow));
+
+ // clear out cell rectangle
+ QColorGroup cg(_cg);
+ setupColors(cg);
+
+ QBrush backgroundBrush(cg.base());
+ painter->fillRect(cellRect, backgroundBrush);
+ painter->setPen(KMyMoneyGlobalSettings::listGridColor());
+ painter->drawLine(cellRect.x(), cellRect.height()-1, cellRect.width(), cellRect.height()-1);
+
+ // now write the text
+ painter->setPen(cg.text());
+ QFont font = painter->font();
+ font.setBold(true);
+ painter->setFont(font);
+
+ painter->drawText(cellRect, Qt::AlignVCenter | Qt::AlignCenter, m_txt);
+
+ cellRect.setHeight(m_bg->height());
+ int curWidth = m_bg->width();
+
+ // if the background image is too small (not wide enough) we need to increase its width.
+ if(curWidth < cellRect.width()) {
+ QPixmap* newPic = new QPixmap(cellRect.width(), cellRect.height());
+ int x = 0;
+ while(x < cellRect.width()) {
+ copyBlt(newPic, x, 0, m_bg, 0, 0, curWidth, m_bg->height());
+ x += curWidth;
+ }
+ delete m_bg;
+ m_bg = newPic;
+ }
+
+ // now it's time to draw the background
+ painter->drawPixmap(cellRect, *m_bg);
+
+ // translate back
+ painter->translate(-r.x(), -r.y());
+
+ // in case we need to show the date, we just paint it in col 1
+ if(m_showDate) {
+ r.setX(m_parent->columnPos(1));
+ r.setWidth(m_parent->columnWidth(1));
+ painter->translate(r.x(), r.y());
+
+ cellRect.setX(0);
+ cellRect.setY(0);
+ cellRect.setWidth(m_parent->columnWidth(1));
+ cellRect.setHeight(m_parent->rowHeight(row + m_startRow));
+
+ font.setBold(false);
+ painter->setFont(font);
+ painter->drawText(cellRect, Qt::AlignVCenter | Qt::AlignCenter, KGlobal::locale()->formatDate(sortPostDate(), true));
+ }
+
+ painter->restore();
+}
+
+void GroupMarker::setupColors(QColorGroup& cg)
+{
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::groupMarkerColor());
+}
+
+int GroupMarker::rowHeightHint(void) const
+{
+ if(!m_visible)
+ return 0;
+
+ return m_bg->height();
+}
+
+StatementGroupMarker::StatementGroupMarker(Register* parent, CashFlowDirection dir, const QDate& date, const QString& txt) :
+ FancyDateGroupMarker(parent, date, txt),
+ m_dir(dir)
+{
+ m_showDate = true;
+}
+
+FancyDateGroupMarker::FancyDateGroupMarker(Register* parent, const QDate& date, const QString& txt) :
+ GroupMarker(parent, txt),
+ m_date(date)
+{
+}
+
+FiscalYearGroupMarker::FiscalYearGroupMarker(Register* parent, const QDate& date, const QString& txt) :
+ FancyDateGroupMarker(parent, date, txt)
+{
+}
+
+void FiscalYearGroupMarker::setupColors(QColorGroup& cg)
+{
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::groupMarkerColor());
+}
+
+
+SimpleDateGroupMarker::SimpleDateGroupMarker(Register* parent, const QDate& date, const QString& txt) :
+ FancyDateGroupMarker(parent, date, txt)
+{
+}
+
+int SimpleDateGroupMarker::rowHeightHint(void) const
+{
+ if(!m_visible)
+ return 0;
+
+ return RegisterItem::rowHeightHint() / 2;
+}
+
+void SimpleDateGroupMarker::paintRegisterCell(QPainter* painter, int row, int /*col*/, const QRect& _r, bool /*selected*/, const QColorGroup& _cg)
+{
+ QRect r(_r);
+ painter->save();
+ painter->translate(-r.x(), -r.y());
+
+ // the group marker always uses all cols
+ r.setX(m_parent->columnPos(0));
+ r.setWidth(m_parent->visibleWidth());
+ painter->translate(r.x(), r.y());
+
+ QRect cellRect;
+ cellRect.setX(0);
+ cellRect.setY(0);
+ cellRect.setWidth(m_parent->visibleWidth());
+ cellRect.setHeight(m_parent->rowHeight(row + m_startRow));
+
+ // clear out cell rectangle
+ QColorGroup cg(_cg);
+ if(m_alternate)
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+ QBrush backgroundBrush(cg.base());
+ // backgroundBrush.setStyle(Qt::DiagCrossPattern);
+ backgroundBrush.setStyle(Qt::Dense5Pattern);
+ backgroundBrush.setColor(KMyMoneyGlobalSettings::listGridColor());
+ painter->eraseRect(cellRect);
+ painter->fillRect(cellRect, backgroundBrush);
+ painter->setPen(KMyMoneyGlobalSettings::listGridColor());
+ painter->drawLine(cellRect.x(), cellRect.height()-1, cellRect.width(), cellRect.height()-1);
+
+ painter->restore();
+}
+
+TypeGroupMarker::TypeGroupMarker(Register* parent, CashFlowDirection dir, MyMoneyAccount::accountTypeE accType) :
+ GroupMarker(parent),
+ m_dir(dir)
+{
+ switch(dir) {
+ case Deposit:
+ m_txt = i18n("Deposits onto account", "Deposits");
+ if(accType == MyMoneyAccount::CreditCard) {
+ m_txt = i18n("Payments towards credit card", "Payments");
+ }
+ break;
+ case Payment:
+ m_txt = i18n("Payments made from account", "Payments");
+ if(accType == MyMoneyAccount::CreditCard) {
+ m_txt = i18n("Payments made with credit card", "Charges");
+ }
+ break;
+ default:
+ qDebug("Unknown CashFlowDirection %d for TypeGroupMarker constructor", dir);
+ break;
+ }
+}
+
+PayeeGroupMarker::PayeeGroupMarker(Register* parent, const QString& name) :
+ GroupMarker(parent, name)
+{
+}
+
+CategoryGroupMarker::CategoryGroupMarker(Register* parent, const QString& category) :
+ GroupMarker(parent, category)
+{
+}
+
+ReconcileGroupMarker::ReconcileGroupMarker(Register* parent, MyMoneySplit::reconcileFlagE state) :
+ GroupMarker(parent),
+ m_state(state)
+{
+ switch(state) {
+ case MyMoneySplit::NotReconciled:
+ m_txt = i18n("Reconcile state 'Not reconciled'", "Not reconciled");
+ break;
+ case MyMoneySplit::Cleared:
+ m_txt = i18n("Reconcile state 'Cleared'", "Cleared");
+ break;
+ case MyMoneySplit::Reconciled:
+ m_txt = i18n("Reconcile state 'Reconciled'", "Reconciled");
+ break;
+ case MyMoneySplit::Frozen:
+ m_txt = i18n("Reconcile state 'Frozen'", "Frozen");
+ break;
+ default:
+ m_txt = i18n("Unknown");
+ break;
+ }
+}
+
+class RegisterToolTip : public QToolTip
+{
+public:
+ RegisterToolTip(QWidget* parent, Register* reg);
+ void maybeTip(const QPoint& pos);
+ virtual ~RegisterToolTip() {}
+
+private:
+ Register* m_register;
+};
+
+RegisterToolTip::RegisterToolTip(QWidget* parent, Register * reg) :
+ QToolTip(parent),
+ m_register(reg)
+{
+}
+
+void RegisterToolTip::maybeTip(const QPoint& pos)
+{
+ // if we update the register, there's no need to show tooltips
+ if(!m_register->isUpdatesEnabled())
+ return;
+
+ QPoint cpos = m_register->viewportToContents(pos);
+ // qDebug("RegisterToolTip::mayBeTip(%d,%d)", cpos.x(), cpos.y());
+ int row = m_register->rowAt(cpos.y());
+ int col = m_register->columnAt(cpos.x());
+ RegisterItem* item = m_register->itemAtRow(row);
+ if(!item)
+ return;
+
+ QPoint relPos(cpos.x() - m_register->columnPos(0), cpos.y() - m_register->rowPos(item->startRow()));
+ row = row - item->startRow();
+
+ // qDebug("row = %d, col = %d", row, col);
+ // qDebug("relpos = %d,%d", relPos.x(), relPos.y());
+ QString msg;
+ QRect rect;
+ if(!item->maybeTip(cpos, row, col, rect, msg))
+ return;
+
+ QPoint tl(rect.topLeft());
+ QPoint br(rect.bottomRight());
+ QRect r = QRect(m_register->contentsToViewport(tl), m_register->contentsToViewport(br));
+ tip(r, msg);
+ return;
+}
+
+Register::Register(QWidget *parent, const char *name ) :
+ TransactionEditorContainer(parent, name),
+ m_selectAnchor(0),
+ m_focusItem(0),
+ m_firstItem(0),
+ m_lastItem(0),
+ m_firstErronous(0),
+ m_lastErronous(0),
+ m_markErronousTransactions(0),
+ m_rowHeightHint(0),
+ m_ledgerLensForced(false),
+ m_selectionMode(Multi),
+ m_listsDirty(false),
+ m_ignoreNextButtonRelease(false),
+ m_needInitialColumnResize(false),
+ m_buttonState(Qt::ButtonState(0)),
+ m_drawCounter(0)
+{
+ m_tooltip = new RegisterToolTip(viewport(), this);
+
+ setNumCols(MaxColumns);
+ setCurrentCell(0, 1);
+ // we do our own sorting
+ setSorting(false);
+
+ // keep the following list in sync with KMyMoneyRegister::Column in transaction.h
+ horizontalHeader()->setLabel(NumberColumn, i18n("No."));
+ horizontalHeader()->setLabel(DateColumn, i18n("Date"));
+ horizontalHeader()->setLabel(AccountColumn, i18n("Account"));
+ horizontalHeader()->setLabel(SecurityColumn, i18n("Security"));
+ horizontalHeader()->setLabel(DetailColumn, i18n("Details"));
+ horizontalHeader()->setLabel(ReconcileFlagColumn, i18n("C"));
+ horizontalHeader()->setLabel(PaymentColumn, i18n("Payment"));
+ horizontalHeader()->setLabel(DepositColumn, i18n("Deposit"));
+ horizontalHeader()->setLabel(QuantityColumn, i18n("Quantity"));
+ horizontalHeader()->setLabel(PriceColumn, i18n("Price"));
+ horizontalHeader()->setLabel(ValueColumn, i18n("Value"));
+ horizontalHeader()->setLabel(BalanceColumn, i18n("Balance"));
+
+ setLeftMargin(0);
+ verticalHeader()->hide();
+
+ for(int i = 0; i < numCols(); ++i)
+ setColumnStretchable(i, false);
+
+ horizontalHeader()->setResizeEnabled(false);
+ horizontalHeader()->setMovingEnabled(false);
+ horizontalHeader()->setClickEnabled(false);
+
+ horizontalHeader()->installEventFilter(this);
+
+ // never show horizontal scroll bars
+ setHScrollBarMode(QScrollView::AlwaysOff);
+
+ connect(this, SIGNAL(clicked(int, int, int, const QPoint&)), this, SLOT(selectItem(int, int, int, const QPoint&)));
+ connect(this, SIGNAL(doubleClicked(int, int, int, const QPoint&)), this, SLOT(slotDoubleClicked(int, int, int, const QPoint&)));
+
+ // double clicking the header turns on auto column sizing
+ connect(horizontalHeader(), SIGNAL(sectionSizeChanged(int)), this, SLOT(slotAutoColumnSizing(int)));
+
+ //DND
+ setAcceptDrops(true);
+}
+
+// DND
+Transaction* Register::dropTransaction(QPoint cPos) const
+{
+ Transaction* t = 0;
+ cPos -= QPoint( verticalHeader()->width(), horizontalHeader()->height() );
+ if(cPos.y() >= 0) {
+ cPos += QPoint(contentsX(), contentsY());
+ int row = rowAt(cPos.y());
+ t = dynamic_cast<Transaction*>(itemAtRow(row));
+ }
+ return t;
+}
+
+void Register::dragMoveEvent(QDragMoveEvent* event)
+{
+ if ( KURLDrag::canDecode(event) ) {
+ event->ignore();
+ Transaction* t = dropTransaction(event->pos());
+ if(t && !t->isScheduled()) {
+ event->accept();
+ }
+ }
+}
+
+void Register::dropEvent(QDropEvent* event)
+{
+ qDebug("Register::dropEvent");
+ if ( KURLDrag::canDecode(event) ) {
+ event->ignore();
+ Transaction* t = dropTransaction(event->pos());
+ if(t && !t->isScheduled()) {
+ qDebug("Drop was ok");
+ KURL::List urls;
+ KURLDrag::decode(event, urls);
+ qDebug("List is '%s'", urls.toStringList().join(";").data());
+ event->accept();
+ }
+ }
+}
+// DND end
+
+
+Register::~Register()
+{
+ clear();
+ delete m_tooltip;
+ m_tooltip = 0;
+}
+
+void Register::slotAutoColumnSizing(int section)
+{
+ Q_UNUSED(section)
+#if 0
+ // this is some trial code to make the col sizes adjustable
+ // there are some drawbacks though: what when we have a register
+ // but no account? (ipwizard 2007-11-06)
+ if(isUpdatesEnabled()) {
+ int w = visibleWidth();
+ QString size;
+ for(int i=0; i < numCols(); ++i) {
+ if(i)
+ size += ",";
+ if(i == DetailColumn) {
+ size += "0";
+ continue;
+ }
+ size += QString("%1").arg((columnWidth(i) * 100) / w);
+ }
+ qDebug("size = %s", size.data());
+ m_account.setValue("kmm-ledger-column-width", size);
+ }
+#endif
+}
+
+bool Register::eventFilter(QObject* o, QEvent* e)
+{
+ if(o == horizontalHeader() && e->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *me = dynamic_cast<QMouseEvent*>(e);
+ if(me->button() == Qt::RightButton) {
+ emit headerClicked();
+ }
+ // eat up left mouse button press for now
+ return true;
+
+ } else if(o == horizontalHeader() && e->type() == QEvent::Paint) {
+ // always show the header in bold (to suppress cell selection)
+ QFont f(horizontalHeader()->font());
+ f.setBold(true);
+ horizontalHeader()->setFont(f);
+
+ } else if(o == this && e->type() == QEvent::KeyPress) {
+ QKeyEvent* ke = dynamic_cast<QKeyEvent*>(e);
+ if(ke->key() == Qt::Key_Menu) {
+ emit openContextMenu();
+ return true;
+ }
+ }
+
+ return QTable::eventFilter(o, e);
+}
+
+void Register::setupRegister(const MyMoneyAccount& account, const QValueList<Column>& cols)
+{
+ m_account = account;
+ bool enabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ for(int i = 0; i < MaxColumns; ++i)
+ hideColumn(i);
+
+ m_needInitialColumnResize = true;
+
+ m_lastCol = static_cast<Column>(0);
+ QValueList<Column>::const_iterator it_c;
+ for(it_c = cols.begin(); it_c != cols.end(); ++it_c) {
+ if((*it_c) > MaxColumns)
+ continue;
+ showColumn(*it_c);
+ if(*it_c > m_lastCol)
+ m_lastCol = *it_c;
+ }
+
+ setUpdatesEnabled(enabled);
+}
+
+void Register::setupRegister(const MyMoneyAccount& account, bool showAccountColumn)
+{
+ m_account = account;
+ bool enabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ for(int i = 0; i < MaxColumns; ++i)
+ hideColumn(i);
+
+ horizontalHeader()->setLabel(PaymentColumn, i18n("Payment made from account", "Payment"));
+ horizontalHeader()->setLabel(DepositColumn, i18n("Deposit into account", "Deposit"));
+
+ if(account.id().isEmpty()) {
+ setUpdatesEnabled(enabled);
+ return;
+ }
+
+ m_needInitialColumnResize = true;
+
+ // turn on standard columns
+ showColumn(DateColumn);
+ showColumn(DetailColumn);
+ showColumn(ReconcileFlagColumn);
+
+ // balance
+ switch(account.accountType()) {
+ case MyMoneyAccount::Stock:
+ break;
+ default:
+ showColumn(BalanceColumn);
+ break;
+ }
+
+ // Number column
+ switch(account.accountType()) {
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::Loan:
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Equity:
+ if(KMyMoneyGlobalSettings::alwaysShowNrField())
+ showColumn(NumberColumn);
+ break;
+
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::CreditCard:
+ showColumn(NumberColumn);
+ break;
+
+ default:
+ hideColumn(NumberColumn);
+ break;
+ }
+
+ switch(account.accountType()) {
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ showAccountColumn = true;
+ break;
+ default:
+ break;
+ }
+
+ if(showAccountColumn)
+ showColumn(AccountColumn);
+
+ // Security, activity, payment, deposit, amount, price and value column
+ switch(account.accountType()) {
+ default:
+ showColumn(PaymentColumn);
+ showColumn(DepositColumn);
+ break;
+
+ case MyMoneyAccount::Investment:
+ showColumn(SecurityColumn);
+ showColumn(QuantityColumn);
+ showColumn(PriceColumn);
+ showColumn(ValueColumn);
+ break;
+ }
+
+ // headings
+ switch(account.accountType()) {
+ case MyMoneyAccount::CreditCard:
+ horizontalHeader()->setLabel(PaymentColumn, i18n("Payment made with credit card", "Charge"));
+ horizontalHeader()->setLabel(DepositColumn, i18n("Payment towards credit card", "Payment"));
+ break;
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::AssetLoan:
+ horizontalHeader()->setLabel(PaymentColumn, i18n("Decrease of asset/liability value", "Decrease"));
+ horizontalHeader()->setLabel(DepositColumn, i18n("Increase of asset/liability value", "Increase"));
+ break;
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Loan:
+ horizontalHeader()->setLabel(PaymentColumn, i18n("Increase of asset/liability value", "Increase"));
+ horizontalHeader()->setLabel(DepositColumn, i18n("Decrease of asset/liability value", "Decrease"));
+ break;
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ horizontalHeader()->setLabel(PaymentColumn, i18n("Income"));
+ horizontalHeader()->setLabel(DepositColumn, i18n("Expense"));
+ break;
+
+ default:
+ break;
+ }
+
+ switch(account.accountType()) {
+ default:
+ m_lastCol = BalanceColumn;
+ break;
+ }
+
+ setUpdatesEnabled(enabled);
+}
+
+bool Register::focusNextPrevChild(bool next)
+{
+ return QFrame::focusNextPrevChild(next);
+}
+
+void Register::setSortOrder(const QString& order)
+{
+ QStringList orderList = QStringList::split(",", order);
+ QStringList::const_iterator it;
+ m_sortOrder.clear();
+ for(it = orderList.begin(); it != orderList.end(); ++it) {
+ m_sortOrder << static_cast<TransactionSortField>((*it).toInt());
+ }
+}
+
+void Register::sortItems(void)
+{
+ if(m_items.count() == 0)
+ return;
+
+ // sort the array of pointers to the transactions
+ m_items.sort();
+
+ // update the next/prev item chains
+ RegisterItem* prev = 0;
+ RegisterItem* item;
+ m_firstItem = m_lastItem = 0;
+ for(QValueVector<RegisterItem*>::size_type i = 0; i < m_items.size(); ++i) {
+ item = m_items[i];
+ if(!item)
+ continue;
+
+ if(!m_firstItem)
+ m_firstItem = item;
+ m_lastItem = item;
+ if(prev)
+ prev->setNextItem(item);
+ item->setPrevItem(prev);
+ item->setNextItem(0);
+ prev = item;
+ }
+
+ // update the balance visibility settings
+ item = m_lastItem;
+ bool showBalance = true;
+ while(item) {
+ Transaction* t = dynamic_cast<Transaction*>(item);
+ if(t) {
+ t->setShowBalance(showBalance);
+ if(!t->isVisible()) {
+ showBalance = false;
+ }
+ }
+ item = item->prevItem();
+ }
+
+ // force update of the item index (row to item array)
+ m_listsDirty = true;
+}
+
+TransactionSortField Register::primarySortKey(void) const
+{
+ if(!m_sortOrder.isEmpty())
+ return static_cast<KMyMoneyRegister::TransactionSortField>(abs(m_sortOrder.first()));
+ return UnknownSort;
+}
+
+
+void Register::clear(void)
+{
+ m_firstErronous = m_lastErronous = 0;
+ m_ensureVisibleItem = 0;
+
+ RegisterItem* p;
+ while((p = firstItem()) != 0) {
+ delete p;
+ }
+ m_items.clear();
+
+ m_firstItem = m_lastItem = 0;
+
+ m_listsDirty = true;
+ m_selectAnchor = 0;
+ m_focusItem = 0;
+
+#ifndef KMM_DESIGNER
+ // recalculate row height hint
+ QFontMetrics fm( KMyMoneyGlobalSettings::listCellFont() );
+ m_rowHeightHint = fm.lineSpacing()+6;
+#endif
+
+ m_needInitialColumnResize = true;
+}
+
+void Register::insertItemAfter(RegisterItem*p, RegisterItem* prev)
+{
+ RegisterItem* next = 0;
+ if(!prev)
+ prev = lastItem();
+
+ if(prev) {
+ next = prev->nextItem();
+ prev->setNextItem(p);
+ }
+ if(next)
+ next->setPrevItem(p);
+
+ p->setPrevItem(prev);
+ p->setNextItem(next);
+
+ if(!m_firstItem)
+ m_firstItem = p;
+ if(!m_lastItem)
+ m_lastItem = p;
+
+ if(prev == m_lastItem)
+ m_lastItem = p;
+
+ m_listsDirty = true;
+}
+
+void Register::addItem(RegisterItem* p)
+{
+ RegisterItem* q = lastItem();
+ if(q)
+ q->setNextItem(p);
+ p->setPrevItem(q);
+ p->setNextItem(0);
+
+ m_items.append(p);
+
+ if(!m_firstItem)
+ m_firstItem = p;
+ m_lastItem = p;
+ m_listsDirty = true;
+}
+
+void Register::removeItem(RegisterItem* p)
+{
+ // remove item from list
+ if(p->prevItem())
+ p->prevItem()->setNextItem(p->nextItem());
+ if(p->nextItem())
+ p->nextItem()->setPrevItem(p->prevItem());
+
+ // update first and last pointer if required
+ if(p == m_firstItem)
+ m_firstItem = p->nextItem();
+ if(p == m_lastItem)
+ m_lastItem = p->prevItem();
+
+ // make sure we don't do it twice
+ p->setNextItem(0);
+ p->setPrevItem(0);
+
+ // remove it from the m_items array
+ for(QValueVector<RegisterItem*>::size_type i = 0; i < m_items.size(); ++i) {
+ RegisterItem* item = m_items[i];
+ if(!item)
+ continue;
+ if(item == p) {
+ m_items[i] = 0;
+ break;
+ }
+ }
+ m_listsDirty = true;
+}
+
+RegisterItem* Register::firstItem(void) const
+{
+ return m_firstItem;
+}
+
+RegisterItem* Register::lastItem(void) const
+{
+ return m_lastItem;
+}
+
+void Register::setupItemIndex(int rowCount)
+{
+ // setup index array
+ m_itemIndex.clear();
+ m_itemIndex.reserve(rowCount);
+
+ // fill index array
+ rowCount = 0;
+ RegisterItem* prev = 0;
+ m_firstItem = m_lastItem = 0;
+ for(QValueVector<RegisterItem*>::size_type i = 0; i < m_items.size(); ++i) {
+ RegisterItem* item = m_items[i];
+ if(!item)
+ continue;
+ if(!m_firstItem)
+ m_firstItem = item;
+ m_lastItem = item;
+ if(prev)
+ prev->setNextItem(item);
+ item->setPrevItem(prev);
+ item->setNextItem(0);
+ prev = item;
+ for(int j = item->numRowsRegister(); j; --j) {
+ m_itemIndex.push_back(item);
+ }
+ }
+}
+
+void Register::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
+{
+ // the QTable::drawContents() method does not honor the block update flag
+ // so we take care of it here
+ if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
+ return;
+
+ if(m_listsDirty) {
+ updateRegister(KMyMoneyGlobalSettings::ledgerLens() | !KMyMoneyGlobalSettings::transactionForm());
+ }
+
+ ++m_drawCounter;
+ QTable::drawContents(p, cx, cy, cw, ch);
+}
+
+void Register::updateAlternate(void) const
+{
+ bool alternate = false;
+ for(QValueVector<RegisterItem*>::size_type i = 0; i < m_items.size(); ++i) {
+ RegisterItem* item = m_items[i];
+ if(!item)
+ continue;
+ if(item->isVisible()) {
+ item->setAlternate(alternate);
+ alternate ^= true;
+ }
+ }
+}
+
+void Register::suppressAdjacentMarkers(void)
+{
+ bool lastWasGroupMarker = false;
+ KMyMoneyRegister::RegisterItem* p = lastItem();
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t && t->transaction().id().isEmpty()) {
+ lastWasGroupMarker = true;
+ p = p->prevItem();
+ }
+ while(p) {
+ KMyMoneyRegister::GroupMarker* m = dynamic_cast<KMyMoneyRegister::GroupMarker*>(p);
+ if(m) {
+ // make adjacent group marker invisible except those that show statement information
+ if(lastWasGroupMarker && (dynamic_cast<KMyMoneyRegister::StatementGroupMarker*>(m) == 0)) {
+ m->setVisible(false);
+ }
+ lastWasGroupMarker = true;
+ } else if(p->isVisible())
+ lastWasGroupMarker = false;
+ p = p->prevItem();
+ }
+}
+
+void Register::updateRegister(bool forceUpdateRowHeight)
+{
+ ::timetrace("Update register");
+ if(m_listsDirty || forceUpdateRowHeight) {
+ // don't get in here recursively
+ m_listsDirty = false;
+
+ int rowCount = 0;
+ // determine the number of rows we need to display all items
+ // while going through the list, check for erronous transactions
+ for(QValueVector<RegisterItem*>::size_type i = 0; i < m_items.size(); ++i) {
+ RegisterItem* item = m_items[i];
+ if(!item)
+ continue;
+ item->setStartRow(rowCount);
+ item->setNeedResize();
+ rowCount += item->numRowsRegister();
+
+ if(item->isErronous()) {
+ if(!m_firstErronous)
+ m_firstErronous = item;
+ m_lastErronous = item;
+ }
+ }
+
+ updateAlternate();
+
+ // create item index
+ setupItemIndex(rowCount);
+
+ bool needUpdateHeaders = (numRows() != rowCount) | forceUpdateRowHeight;
+
+ // setup QTable. Make sure to suppress screen updates for now
+ bool updatesEnabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+ setNumRows(rowCount);
+
+ // if we need to update the headers, we do it now for all rows
+ // again we make sure to suppress screen updates
+ if(needUpdateHeaders) {
+ // int height = rowHeightHint();
+
+ verticalHeader()->setUpdatesEnabled(false);
+
+ for(int i = 0; i < rowCount; ++i) {
+ RegisterItem* item = itemAtRow(i);
+ if(item->isVisible()) {
+ showRow(i);
+ } else {
+ hideRow(i);
+ }
+ verticalHeader()->resizeSection(i, item->rowHeightHint());
+ }
+ verticalHeader()->setUpdatesEnabled(true);
+ }
+
+ // add or remove scrollbars as required
+ updateScrollBars();
+
+ setUpdatesEnabled(updatesEnabled);
+
+ // force resizeing of the columns if necessary
+ if(m_needInitialColumnResize) {
+ QTimer::singleShot(0, this, SLOT(resize()));
+ m_needInitialColumnResize = false;
+ } else {
+ updateContents();
+
+ // if the number of rows changed, we might need to resize the register
+ // to make sure we reflect the current visibility of the scrollbars.
+ if(needUpdateHeaders)
+ QTimer::singleShot(0, this, SLOT(resize()));
+ }
+ }
+ ::timetrace("Done updateing register");
+}
+
+int Register::rowHeightHint(void) const
+{
+ if(!m_rowHeightHint) {
+ qDebug("Register::rowHeightHint(): m_rowHeightHint is zero!!");
+ }
+ return m_rowHeightHint;
+}
+
+void Register::paintCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg)
+{
+ // determine the item that we need to paint in the row and call it's paintRegisterCell() method
+ if((row < 0) || ((unsigned)row > m_itemIndex.size())) {
+ qDebug("Register::paintCell: row %d out of bounds %d", row, (int)m_itemIndex.size());
+ return;
+ }
+
+ // qDebug("paintCell(%d,%d)", row, col);
+ RegisterItem* const item = m_itemIndex[row];
+ item->paintRegisterCell(painter, row - item->startRow(), col, r, selected, cg);
+}
+
+void Register::focusInEvent(QFocusEvent* ev)
+{
+ QTable::focusInEvent(ev);
+ if(m_focusItem) {
+ m_focusItem->setFocus(true, false);
+ repaintItems(m_focusItem);
+ }
+}
+
+void Register::focusOutEvent(QFocusEvent* ev)
+{
+ if(m_focusItem) {
+ m_focusItem->setFocus(false, false);
+ repaintItems(m_focusItem);
+ }
+ QTable::focusOutEvent(ev);
+}
+
+void Register::resize(void)
+{
+ resize(DetailColumn);
+}
+
+void Register::resize(int col)
+{
+ bool enabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ // resize the register
+ int w = visibleWidth();
+
+ // TODO I was playing a bit with manual ledger resizing but could not get
+ // a good solution. I just leave the code around, so that maybe others
+ // pick it up again. So far, it's not clear to me where to store the
+ // size of the sections:
+ //
+ // a) with the account (as it is done now)
+ // b) with the application for the specific account type
+ // c) ????
+ //
+ // Ideas are welcome (ipwizard: 2007-07-19)
+ // Note: currently there's no way to switch back to automatic
+ // column sizing once the manual sizing option has been saved
+#if 0
+ if(m_account.value("kmm-ledger-column-width").isEmpty()) {
+#endif
+
+ // check which space we need
+ if(columnWidth(NumberColumn))
+ adjustColumn(NumberColumn);
+ if(columnWidth(AccountColumn))
+ adjustColumn(AccountColumn);
+ if(columnWidth(PaymentColumn))
+ adjustColumn(PaymentColumn);
+ if(columnWidth(DepositColumn))
+ adjustColumn(DepositColumn);
+ if(columnWidth(BalanceColumn))
+ adjustColumn(BalanceColumn);
+ if(columnWidth(PriceColumn))
+ adjustColumn(PriceColumn);
+ if(columnWidth(ValueColumn))
+ adjustColumn(ValueColumn);
+
+ // make amount columns all the same size
+ // only extend the entry columns to make sure they fit
+ // the widget
+ int dwidth = 0;
+ int ewidth = 0;
+ if(ewidth < columnWidth(PaymentColumn))
+ ewidth = columnWidth(PaymentColumn);
+ if(ewidth < columnWidth(DepositColumn))
+ ewidth = columnWidth(DepositColumn);
+ if(dwidth < columnWidth(BalanceColumn))
+ dwidth = columnWidth(BalanceColumn);
+ if(ewidth < columnWidth(PriceColumn))
+ ewidth = columnWidth(PriceColumn);
+ if(dwidth < columnWidth(ValueColumn))
+ dwidth = columnWidth(ValueColumn);
+
+ int swidth = columnWidth(SecurityColumn);
+ if(swidth > 0) {
+ adjustColumn(SecurityColumn);
+ swidth = columnWidth(SecurityColumn);
+ }
+
+#ifndef KMM_DESIGNER
+ // Resize the date and money fields to either
+ // a) the size required by the input widget if no transaction form is shown
+ // b) the adjusted value for the input widget if the transaction form is visible
+ if(!KMyMoneyGlobalSettings::transactionForm()) {
+ kMyMoneyDateInput* dateField = new kMyMoneyDateInput;
+ kMyMoneyEdit* valField = new kMyMoneyEdit;
+
+ dateField->setFont(KMyMoneyGlobalSettings::listCellFont());
+ setColumnWidth(DateColumn, dateField->minimumSizeHint().width());
+ valField->setMinimumWidth(ewidth);
+ ewidth = valField->minimumSizeHint().width();
+
+ if(swidth > 0) {
+ swidth = columnWidth(SecurityColumn) + 40;
+ }
+ delete valField;
+ delete dateField;
+ } else {
+ adjustColumn(DateColumn);
+ }
+#endif
+
+ if(columnWidth(PaymentColumn))
+ setColumnWidth(PaymentColumn, ewidth);
+ if(columnWidth(DepositColumn))
+ setColumnWidth(DepositColumn, ewidth);
+ if(columnWidth(BalanceColumn))
+ setColumnWidth(BalanceColumn, dwidth);
+ if(columnWidth(PriceColumn))
+ setColumnWidth(PriceColumn, ewidth);
+ if(columnWidth(ValueColumn))
+ setColumnWidth(ValueColumn, dwidth);
+
+ if(columnWidth(ReconcileFlagColumn))
+ setColumnWidth(ReconcileFlagColumn, 20);
+
+ if(swidth > 0)
+ setColumnWidth(SecurityColumn, swidth);
+#if 0
+ // see comment above
+ } else {
+ QStringList colSizes = QStringList::split(",", m_account.value("kmm-ledger-column-width"), true);
+ for(int i; i < colSizes.count(); ++i) {
+ int colWidth = colSizes[i].toInt();
+ if(colWidth == 0)
+ continue;
+ setColumnWidth(i, w * colWidth / 100);
+ }
+ }
+#endif
+
+ for(int i = 0; i < numCols(); ++i) {
+ if(i == col)
+ continue;
+
+ w -= columnWidth(i);
+ }
+ setColumnWidth(col, w);
+
+ setUpdatesEnabled(enabled);
+ updateContents();
+}
+
+
+void Register::adjustColumn(int col)
+{
+#ifdef KMM_DESIGNER
+ Q_UNUSED(col)
+#else
+ QString msg = "%1 adjusting column %2";
+ ::timetrace((msg.arg("Start").arg(col)).data());
+ QHeader *topHeader = horizontalHeader();
+ QFontMetrics cellFontMetrics(KMyMoneyGlobalSettings::listCellFont());
+
+ int w = topHeader->fontMetrics().width( topHeader->label( col ) ) + 10;
+ if ( topHeader->iconSet( col ) )
+ w += topHeader->iconSet( col )->pixmap().width();
+ w = QMAX( w, 20 );
+
+ int maxWidth = 0;
+ switch(col) {
+ case NumberColumn:
+ maxWidth = cellFontMetrics.width("0123456789");
+ break;
+ default:
+ break;
+ }
+
+ // check for date column
+ if(col == DateColumn) {
+ QString txt = KGlobal::locale()->formatDate(QDate(6999,12,29), true);
+ int nw = cellFontMetrics.width(txt+" ");
+ w = QMAX( w, nw );
+ } else {
+
+ // scan through the transactions
+ for(unsigned i = 0; i < m_items.size(); ++i) {
+ RegisterItem* const item = m_items[i];
+ if(!item)
+ continue;
+ Transaction* t = dynamic_cast<Transaction*>(item);
+ if(t) {
+ int nw = t->registerColWidth(col, cellFontMetrics);
+ w = QMAX( w, nw );
+ if(maxWidth) {
+ if(w > maxWidth) {
+ w = maxWidth;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ setColumnWidth( col, w );
+#endif
+}
+
+void Register::repaintItems(RegisterItem* first, RegisterItem* last)
+{
+ if(first == 0 && last == 0) {
+ first = firstItem();
+ last = lastItem();
+ }
+
+ if(first == 0)
+ return;
+
+ if(last == 0)
+ last = first;
+
+ // qDebug("repaintItems from row %d to row %d", first->startRow(), last->startRow()+last->numRowsRegister()-1);
+
+ // the following code is based on code I found in
+ // QTable::cellGeometry() and QTable::updateCell() (ipwizard)
+ QRect cg(0,
+ rowPos(first->startRow()),
+ visibleWidth(),
+ rowPos(last->startRow()+last->numRowsRegister()-1) - rowPos(first->startRow()) + rowHeight(last->startRow()+last->numRowsRegister()-1));
+
+ QRect r(contentsToViewport(QPoint (cg.x() - 2, cg.y() - 2 )), QSize(cg.width() + 4, cg.height() + 4 ));
+
+ QRect tmp = m_lastRepaintRect | r;
+ if(abs(tmp.height()) > 3000) {
+ // make sure that the previously triggered repaint has been done before we
+ // trigger the next. Not having this used to cause some trouble when changing
+ // the focus within a 2000 item ledger from the last to the first item.
+ QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 10);
+ }
+ m_lastRepaintRect = r;
+ QApplication::postEvent( viewport(), new QPaintEvent( r, FALSE ) );
+
+}
+
+void Register::clearSelection(void)
+{
+ unselectItems();
+}
+
+void Register::doSelectItems(int from, int to, bool selected)
+{
+ int start, end;
+ // make sure start is smaller than end
+ if(from <= to) {
+ start = from;
+ end = to;
+ } else {
+ start = to;
+ end = from;
+ }
+ // make sure we stay in bounds
+ if(start < 0)
+ start = 0;
+ if((end <= -1) || ((unsigned)end > (m_items.size()-1)))
+ end = m_items.size()-1;
+
+ RegisterItem* firstItem;
+ RegisterItem* lastItem;
+ firstItem = lastItem = 0;
+ for(int i = start; i <= end; ++i) {
+ RegisterItem* const item = m_items[i];
+ if(item) {
+ if(selected != item->isSelected()) {
+ if(!firstItem)
+ firstItem = item;
+ item->setSelected(selected);
+ lastItem = item;
+ }
+ }
+ }
+
+ // anything changed?
+ if(firstItem || lastItem)
+ repaintItems(firstItem, lastItem);
+}
+
+RegisterItem* Register::itemAtRow(int row) const
+{
+ if(row >= 0 && (unsigned)row < m_itemIndex.size()) {
+ return m_itemIndex[row];
+ }
+ return 0;
+}
+
+int Register::rowToIndex(int row) const
+{
+ for(unsigned i = 0; i < m_items.size(); ++i) {
+ RegisterItem* const item = m_items[i];
+ if(!item)
+ continue;
+ if(row >= item->startRow() && row < (item->startRow() + item->numRowsRegister()))
+ return i;
+ }
+ return -1;
+}
+
+void Register::selectedTransactions(SelectedTransactions& list) const
+{
+ if(m_focusItem && m_focusItem->isSelected() && m_focusItem->isVisible()) {
+ Transaction* t = dynamic_cast<Transaction*>(m_focusItem);
+ if(t) {
+ QString id;
+ if(t->isScheduled())
+ id = t->transaction().id();
+ SelectedTransaction s(t->transaction(), t->split(), id);
+ list << s;
+ }
+ }
+
+ for(unsigned i = 0; i < m_items.size(); ++i) {
+ RegisterItem* const item = m_items[i];
+ // make sure, we don't include the focus item twice
+ if(item == m_focusItem)
+ continue;
+ if(item && item->isSelected() && item->isVisible()) {
+ Transaction* t = dynamic_cast<Transaction*>(item);
+ if(t) {
+ QString id;
+ if(t->isScheduled())
+ id = t->transaction().id();
+ SelectedTransaction s(t->transaction(), t->split(), id);
+ list << s;
+ }
+ }
+ }
+}
+
+QValueList<RegisterItem*> Register::selectedItems(void) const
+{
+ QValueList<RegisterItem*> list;
+
+ RegisterItem* item = m_firstItem;
+ while(item) {
+ if(item && item->isSelected() && item->isVisible()) {
+ list << item;
+ }
+ item = item->nextItem();
+ }
+ return list;
+}
+
+int Register::selectedItemsCount(void) const
+{
+ int cnt = 0;
+ RegisterItem* item = m_firstItem;
+ while(item) {
+ if(item->isSelected() && item->isVisible())
+ ++cnt;
+ item = item->nextItem();
+ }
+ return cnt;
+}
+
+void Register::contentsMouseReleaseEvent( QMouseEvent *e )
+{
+ if(m_ignoreNextButtonRelease) {
+ m_ignoreNextButtonRelease = false;
+ return;
+ }
+
+ m_buttonState = e->state();
+ QTable::contentsMouseReleaseEvent(e);
+}
+
+void Register::selectItem(int row, int col, int button, const QPoint& /* mousePos */)
+{
+ if(row >= 0 && (unsigned)row < m_itemIndex.size()) {
+ RegisterItem* item = m_itemIndex[row];
+
+ // don't support selecting when the item has an editor
+ // or the item itself is not selectable
+ if(item->hasEditorOpen() || !item->isSelectable())
+ return;
+
+ QString id = item->id();
+ selectItem(item);
+ // selectItem() might have changed the pointers, so we
+ // need to reconstruct it here
+ item = itemById(id);
+ Transaction* t = dynamic_cast<Transaction*>(item);
+ if(t) {
+ if(!id.isEmpty()) {
+ switch(button & Qt::MouseButtonMask) {
+ case Qt::RightButton:
+ emit openContextMenu();
+ break;
+
+ case Qt::LeftButton:
+ if(t && col == ReconcileFlagColumn && selectedItemsCount() == 1 && !t->isScheduled())
+ emit reconcileStateColumnClicked(t);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ emit emptyItemSelected();
+ }
+ }
+ }
+}
+
+void Register::setAnchorItem(RegisterItem* anchorItem)
+{
+ m_selectAnchor = anchorItem;
+}
+
+bool Register::setFocusItem(RegisterItem* focusItem)
+{
+ if(focusItem && focusItem->canHaveFocus()) {
+ if(m_focusItem) {
+ m_focusItem->setFocus(false);
+ // issue a repaint here only if we move the focus
+ if(m_focusItem != focusItem)
+ repaintItems(m_focusItem);
+ }
+ Transaction* item = dynamic_cast<Transaction*>(focusItem);
+ if(m_focusItem != focusItem && item) {
+ emit focusChanged(item);
+ }
+
+ m_focusItem = focusItem;
+ m_focusItem->setFocus(true);
+ if(m_listsDirty)
+ updateRegister(KMyMoneyGlobalSettings::ledgerLens() | !KMyMoneyGlobalSettings::transactionForm());
+ ensureItemVisible(m_focusItem);
+ repaintItems(m_focusItem);
+ return true;
+ } else
+ return false;
+}
+
+bool Register::setFocusToTop(void)
+{
+ RegisterItem* rgItem=m_firstItem;
+ while (rgItem) {
+ if (setFocusItem(rgItem))
+ return true;
+ rgItem=rgItem->nextItem();
+ }
+ return false;
+}
+
+void Register::selectItem(RegisterItem* item, bool dontChangeSelections)
+{
+ if(!item)
+ return;
+
+ // kdDebug(2) << "Register::selectItem(" << item << "): type is " << typeid(*item).name() << endl;
+
+ Qt::ButtonState buttonState = m_buttonState;
+ m_buttonState = Qt::NoButton;
+
+ if(m_selectionMode == NoSelection)
+ return;
+
+ if(item->isSelectable()) {
+ QString id = item->id();
+ QValueList<RegisterItem*> itemList = selectedItems();
+ bool okToSelect = true;
+ int cnt = itemList.count();
+ bool sameEntryType = true;
+ if(cnt > 0) {
+ if(typeid(*itemList.begin()) != typeid(item))
+ sameEntryType = false;
+ }
+
+ if(buttonState & Qt::LeftButton) {
+ if(!(buttonState & (Qt::ShiftButton | Qt::ControlButton))) {
+ if((cnt != 1) || ((cnt == 1) && !item->isSelected())) {
+ emit aboutToSelectItem(item, okToSelect);
+ if(okToSelect) {
+ // pointer 'item' might have changed. reconstruct it.
+ item = itemById(id);
+ unselectItems();
+ item->setSelected(true);
+ setFocusItem(item);
+ }
+ }
+ if(okToSelect)
+ m_selectAnchor = item;
+ }
+
+ if(m_selectionMode == Multi) {
+ switch(buttonState & (Qt::ShiftButton | Qt::ControlButton)) {
+ case Qt::ControlButton:
+ okToSelect = sameEntryType;
+ if(typeid(*item) == typeid(StdTransactionScheduled))
+ okToSelect = false;
+ // toggle selection state of current item
+ emit aboutToSelectItem(item, okToSelect);
+ if(okToSelect) {
+ // pointer 'item' might have changed. reconstruct it.
+ item = itemById(id);
+ item->setSelected(!item->isSelected());
+ setFocusItem(item);
+ }
+ break;
+
+ case Qt::ShiftButton:
+ okToSelect = sameEntryType;
+ if(typeid(*item) == typeid(StdTransactionScheduled))
+ okToSelect = false;
+ emit aboutToSelectItem(item, okToSelect);
+ if(okToSelect) {
+ // pointer 'item' might have changed. reconstruct it.
+ item = itemById(id);
+ unselectItems();
+ selectItems(rowToIndex(m_selectAnchor->startRow()), rowToIndex(item->startRow()));
+ setFocusItem(item);
+ }
+ break;
+ }
+ }
+ } else if(buttonState & Qt::RightButton) {
+ // if the right button is pressed then only change the
+ // selection if none of the Shift/Ctrl button is pressed and
+ // one of the following conditions is true:
+ //
+ // a) single transaction is selected
+ // b) multiple transactions are selected and the one to be selected is not
+ if(!(buttonState & (Qt::ShiftButton | Qt::ControlButton))) {
+ if((cnt > 0) && (!item->isSelected())) {
+ okToSelect = sameEntryType;
+ emit aboutToSelectItem(item, okToSelect);
+ if(okToSelect) {
+ // pointer 'item' might have changed. reconstruct it.
+ item = itemById(id);
+ unselectItems();
+ item->setSelected(true);
+ setFocusItem(item);
+ }
+ }
+ if(okToSelect)
+ m_selectAnchor = item;
+ }
+ } else {
+ // we get here when called by application logic
+ emit aboutToSelectItem(item, okToSelect);
+ if(okToSelect) {
+ // pointer 'item' might have changed. reconstruct it.
+ item = itemById(id);
+ if(!dontChangeSelections)
+ unselectItems();
+ item->setSelected(true);
+ setFocusItem(item);
+ m_selectAnchor = item;
+ }
+ }
+ if(okToSelect) {
+ SelectedTransactions list(this);
+ emit selectionChanged(list);
+ }
+ }
+}
+
+void Register::ensureItemVisible(RegisterItem* item)
+{
+ if(!item)
+ return;
+
+ m_ensureVisibleItem = item;
+ QTimer::singleShot(0, this, SLOT(slotEnsureItemVisible()));
+}
+
+void Register::slotDoubleClicked(int row, int, int, const QPoint&)
+{
+ if(row >= 0 && (unsigned)row < m_itemIndex.size()) {
+ RegisterItem* p = m_itemIndex[row];
+ if(p->isSelectable()) {
+ m_ignoreNextButtonRelease = true;
+ // double click to start editing only works if the focus
+ // item is among the selected ones
+ if(!focusItem()) {
+ setFocusItem(p);
+ if(m_selectionMode != NoSelection)
+ p->setSelected(true);
+ }
+
+ if(m_focusItem->isSelected()) {
+ // don't emit the signal right away but wait until
+ // we come back to the Qt main loop
+ QTimer::singleShot(0, this, SIGNAL(editTransaction()));
+ }
+ }
+ }
+}
+
+void Register::slotEnsureItemVisible(void)
+{
+ // if clear() has been called since the timer was
+ // started, we just ignore the call
+ if(!m_ensureVisibleItem)
+ return;
+
+ // make sure to catch latest changes
+ bool enabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+ updateRegister();
+ setUpdatesEnabled(enabled);
+
+ RegisterItem* item = m_ensureVisibleItem;
+ RegisterItem* prev = item->prevItem();
+ while(prev && !prev->isVisible())
+ prev = prev->prevItem();
+ RegisterItem* next = item->nextItem();
+ while(next && !next->isVisible())
+ next = next->nextItem();
+
+ int rowPrev, rowNext;
+ rowPrev = item->startRow();
+ rowNext = item->startRow() + item->numRowsRegister() - 1;
+
+ if(prev)
+ rowPrev = prev->startRow();
+ if(next)
+ rowNext = next->startRow() + next->numRowsRegister() - 1;
+
+ if(rowPrev < 0)
+ rowPrev = 0;
+ if(rowNext >= numRows())
+ rowNext = numRows()-1;
+
+ int wt = contentsY(); // window top
+ int wh = visibleHeight(); // window height
+ int lt = rowPos(rowPrev); // top of line above lens
+ int lb = rowPos(rowNext)+rowHeight(rowNext); // bottom of line below lens
+
+ // only update widget, if the transaction is not fully visible
+ if(lt < wt || lb >= (wt + wh)) {
+ if(rowPrev >= 0) {
+ ensureCellVisible(rowPrev, 0);
+ }
+
+ ensureCellVisible(item->startRow(), 0);
+
+ if(rowNext < numRows()) {
+ ensureCellVisible(rowNext, 0);
+ }
+ }
+}
+
+TransactionSortField KMyMoneyRegister::textToSortOrder(const QString& text)
+{
+ for(int idx = 1; idx < static_cast<int>(MaxSortFields); ++idx) {
+ if(text == i18n(sortOrderText[idx])) {
+ return static_cast<TransactionSortField>(idx);
+ }
+ }
+ return UnknownSort;
+}
+
+const QString KMyMoneyRegister::sortOrderToText(TransactionSortField idx)
+{
+ if(idx < PostDateSort || idx >= MaxSortFields)
+ idx = UnknownSort;
+ return i18n(sortOrderText[idx]);
+}
+
+QString Register::text(int /*row*/, int /*col*/) const
+{
+ return QString("a");
+}
+
+QWidget* Register::cellWidget(int row, int col) const
+{
+ // separeted here in two if()s, because this method is called for each
+ // event from QTable::eventFilter and in the most cases it is -1, -1
+ if(row < 0 || col < 0)
+ return 0;
+
+ if(row > numRows() - 1 || col > numCols() - 1) {
+ if(numRows() && numCols())
+ qWarning("Register::cellWidget(%d,%d) out of bounds (%d,%d)", row, col, numRows(), numCols());
+ return 0;
+ }
+
+ if(!m_cellWidgets.count())
+ return 0;
+
+ QWidget* w = 0;
+ QPair<int, int> idx = qMakePair(row, col);
+ QMap<QPair<int, int>, QWidget*>::const_iterator it_w;
+
+ it_w = m_cellWidgets.find(idx);
+ if(it_w != m_cellWidgets.end())
+ w = *it_w;
+ return w;
+}
+
+void Register::insertWidget(int row, int col, QWidget* w)
+{
+ if(row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1) {
+ qWarning("Register::insertWidget(%d,%d) out of bounds", row, col);
+ return;
+ }
+
+ QPair<int, int> idx = qMakePair(row, col);
+ m_cellWidgets[idx] = w;
+}
+
+void Register::clearCellWidget(int row, int col)
+{
+ if(row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1) {
+ qWarning("Register::clearCellWidget(%d,%d) out of bounds", row, col);
+ return;
+ }
+
+ QPair<int, int> idx = qMakePair(row, col);
+ QMap<QPair<int, int>, QWidget*>::iterator it_w;
+
+ it_w = m_cellWidgets.find(idx);
+ if(it_w != m_cellWidgets.end()) {
+ (*it_w)->deleteLater();
+ m_cellWidgets.remove(it_w);
+ }
+}
+
+QWidget* Register::createEditor(int /*row*/, int /*col*/, bool /*initFromCell*/) const
+{
+ return 0;
+}
+
+void Register::setCellContentFromEditor(int /*row*/, int /*col*/)
+{
+}
+
+void Register::endEdit(int /*row*/, int /*col*/, bool /*accept*/, bool /*replace*/)
+{
+}
+
+void Register::arrangeEditWidgets(QMap<QString, QWidget*>& editWidgets, KMyMoneyRegister::Transaction* t)
+{
+ t->arrangeWidgetsInRegister(editWidgets);
+ ensureItemVisible(t);
+ // updateContents();
+}
+
+void Register::tabOrder(QWidgetList& tabOrderWidgets, KMyMoneyRegister::Transaction* t) const
+{
+ t->tabOrderInRegister(tabOrderWidgets);
+}
+
+void Register::removeEditWidgets(QMap<QString, QWidget*>& editWidgets)
+{
+ // remove pointers from map
+ QMap<QString, QWidget*>::iterator it;
+ for(it = editWidgets.begin(); it != editWidgets.end(); ) {
+ if((*it)->parentWidget() == this) {
+ editWidgets.remove(it);
+ it = editWidgets.begin();
+ } else
+ ++it;
+ }
+
+ // now delete the widgets
+ KMyMoneyRegister::Transaction* t = dynamic_cast<KMyMoneyRegister::Transaction*>(focusItem());
+ for(int row = t->startRow(); row < t->startRow() + t->numRowsRegister(true); ++row) {
+ for(int col = 0; col < numCols(); ++col) {
+ if(cellWidget(row, col))
+ clearCellWidget(row, col);
+ }
+ // make sure to reduce the possibly size to what it was before editing started
+ setRowHeight(row, t->rowHeightHint());
+ }
+}
+
+void Register::slotToggleErronousTransactions(void)
+{
+ // toggle switch
+ m_markErronousTransactions ^= 1;
+
+ // check if anything needs to be redrawn
+ KMyMoneyRegister::RegisterItem* p = m_firstErronous;
+ while(p && p->prevItem() != m_lastErronous) {
+ if(p->isErronous())
+ repaintItems(p);
+ p = p->nextItem();
+ }
+
+ // restart timer
+ QTimer::singleShot(500, this, SLOT(slotToggleErronousTransactions()));
+}
+
+RegisterItem* Register::itemById(const QString& id) const
+{
+ if(id.isEmpty())
+ return m_lastItem;
+
+ for(QValueVector<RegisterItem*>::size_type i = 0; i < m_items.size(); ++i) {
+ RegisterItem* item = m_items[i];
+ if(!item)
+ continue;
+ if(item->id() == id)
+ return item;
+ }
+ return 0;
+}
+
+void Register::handleItemChange(RegisterItem* old, bool shift, bool control)
+{
+ if(m_selectionMode == Multi) {
+ if(shift) {
+ selectRange(m_selectAnchor ? m_selectAnchor : old,
+ m_focusItem, false, true, (m_selectAnchor && !control) ? true : false);
+ } else if(!control) {
+ selectItem(m_focusItem, false);
+ }
+ }
+}
+
+void Register::selectRange(RegisterItem* from, RegisterItem* to, bool invert, bool includeFirst, bool clearSel)
+{
+ if(!from || !to)
+ return;
+ if(from == to && !includeFirst)
+ return;
+ bool swap = false;
+ if(to == from->prevItem())
+ swap = true;
+
+ RegisterItem* item;
+ if(!swap && from != to && from != to->prevItem()) {
+ bool found = false;
+ for(item = from; item; item = item->nextItem()) {
+ if(item == to) {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ swap = true;
+ }
+
+ if(swap) {
+ item = from;
+ from = to;
+ to = item;
+ if(!includeFirst)
+ to = to->prevItem();
+
+ } else if(!includeFirst) {
+ from = from->nextItem();
+ }
+
+ bool changed = false;
+ if(clearSel) {
+ for(item = firstItem(); item; item = item->nextItem()) {
+ if(item->isSelected() && item->isVisible()) {
+ item->setSelected(false);
+ changed = true;
+ }
+ }
+ }
+
+ for(item = from; item; item = item->nextItem()) {
+ if(item->isSelectable()) {
+ if(!invert) {
+ if(!item->isSelected() && item->isVisible()) {
+ item->setSelected(true);
+ changed = true;
+ }
+ } else {
+ bool sel = !item->isSelected();
+ if((item->isSelected() != sel) && (sel || !sel)) {
+ if(item->isVisible()) {
+ item->setSelected(sel);
+ changed = true;
+ }
+ }
+ }
+ }
+ if(item == to)
+ break;
+ }
+}
+
+void Register::scrollPage(int key, ButtonState state)
+{
+ RegisterItem* oldFocusItem = m_focusItem;
+
+ // make sure we have a focus item
+ if(!m_focusItem)
+ setFocusItem(m_firstItem);
+ if(!m_focusItem && m_firstItem)
+ setFocusItem(m_firstItem->nextItem());
+ if(!m_focusItem)
+ return;
+
+ RegisterItem* item = m_focusItem;
+ int height = 0;
+
+ switch(key) {
+ case Qt::Key_PageUp:
+ while(height < visibleHeight() && item->prevItem()) {
+ do {
+ item = item->prevItem();
+ if(item->isVisible())
+ height += item->rowHeightHint();
+ } while((!item->isSelectable() || !item->isVisible()) && item->prevItem());
+ }
+ break;
+ case Qt::Key_PageDown:
+ while(height < visibleHeight() && item->nextItem()) {
+ do {
+ if(item->isVisible())
+ height += item->rowHeightHint();
+ item = item->nextItem();
+ } while((!item->isSelectable() || !item->isVisible()) && item->nextItem());
+ }
+ break;
+
+ case Qt::Key_Up:
+ if(item->prevItem()) {
+ do {
+ item = item->prevItem();
+ } while((!item->isSelectable() || !item->isVisible()) && item->prevItem());
+ }
+ break;
+
+ case Qt::Key_Down:
+ if(item->nextItem()) {
+ do {
+ item = item->nextItem();
+ } while((!item->isSelectable() || !item->isVisible()) && item->nextItem());
+ }
+ break;
+
+ case Qt::Key_Home:
+ item = m_firstItem;
+ while((!item->isSelectable() || !item->isVisible()) && item->nextItem())
+ item = item->nextItem();
+ break;
+
+ case Qt::Key_End:
+ item = m_lastItem;
+ while((!item->isSelectable() || !item->isVisible()) && item->prevItem())
+ item = item->prevItem();
+ break;
+ }
+
+ // make sure to avoid selecting a possible empty transaction at the end
+ Transaction* t = dynamic_cast<Transaction*>(item);
+ if(t && t->transaction().id().isEmpty()) {
+ if(t->prevItem()) {
+ item = t->prevItem();
+ }
+ }
+
+ if(!(state & ShiftButton) || !m_selectAnchor)
+ m_selectAnchor = item;
+
+ setFocusItem(item);
+
+ if(item->isSelectable()) {
+ handleItemChange(oldFocusItem, state & Qt::ShiftButton, state & Qt::ControlButton);
+ // tell the world about the changes in selection
+ SelectedTransactions list(this);
+ emit selectionChanged(list);
+ }
+
+ if(m_focusItem && !m_focusItem->isSelected() && m_selectionMode == Single)
+ selectItem(item);
+}
+
+void Register::keyPressEvent(QKeyEvent* ev)
+{
+ switch(ev->key()) {
+ case Qt::Key_Space:
+ if(m_selectionMode != NoSelection) {
+ // get the state out of the event ...
+ m_buttonState = ev->state();
+ // ... and pretend that we have pressed the left mouse button ;)
+ m_buttonState = static_cast<Qt::ButtonState>(m_buttonState | Qt::LeftButton);
+ selectItem(m_focusItem);
+ }
+ break;
+
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_Down:
+ case Qt::Key_Up:
+ scrollPage(ev->key(), ev->state());
+ break;
+
+ default:
+ QTable::keyPressEvent(ev);
+ break;
+ }
+}
+
+Transaction* Register::transactionFactory(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId)
+{
+ Transaction* t = 0;
+ MyMoneySplit s = split;
+
+ if(parent->account() == MyMoneyAccount()) {
+ t = new KMyMoneyRegister::StdTransaction(parent, transaction, s, uniqueId);
+ return t;
+ }
+
+ switch(parent->account().accountType()) {
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::CreditCard:
+ case MyMoneyAccount::Loan:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Currency:
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Equity:
+ if(s.accountId().isEmpty())
+ s.setAccountId(parent->account().id());
+ if(s.isMatched())
+ t = new KMyMoneyRegister::StdTransactionMatched(parent, transaction, s, uniqueId);
+ else if(transaction.isImported())
+ t = new KMyMoneyRegister::StdTransactionDownloaded(parent, transaction, s, uniqueId);
+ else
+ t = new KMyMoneyRegister::StdTransaction(parent, transaction, s, uniqueId);
+ break;
+
+ case MyMoneyAccount::Investment:
+ if(s.isMatched())
+ t = new KMyMoneyRegister::InvestTransaction/* Matched */(parent, transaction, s, uniqueId);
+ else if(transaction.isImported())
+ t = new KMyMoneyRegister::InvestTransactionDownloaded(parent, transaction, s, uniqueId);
+ else
+ t = new KMyMoneyRegister::InvestTransaction(parent, transaction, s, uniqueId);
+ break;
+
+ case MyMoneyAccount::CertificateDep:
+ case MyMoneyAccount::MoneyMarket:
+ case MyMoneyAccount::Stock:
+ default:
+ qDebug("Register::transactionFactory: invalid accountTypeE %d", parent->account().accountType());
+ break;
+ }
+ return t;
+}
+
+void Register::addGroupMarkers(void)
+{
+ QMap<QString, int> list;
+ QMap<QString, int>::const_iterator it;
+ KMyMoneyRegister::RegisterItem* p = firstItem();
+ KMyMoneyRegister::Transaction* t;
+ QString name;
+ QDate today;
+ QDate yesterday, thisWeek, lastWeek;
+ QDate thisMonth, lastMonth;
+ QDate thisYear;
+ int weekStartOfs;
+
+ switch(primarySortKey()) {
+ case KMyMoneyRegister::PostDateSort:
+ case KMyMoneyRegister::EntryDateSort:
+ today = QDate::currentDate();
+ thisMonth.setYMD(today.year(), today.month(), 1);
+ lastMonth = thisMonth.addMonths(-1);
+ yesterday = today.addDays(-1);
+ // a = QDate::dayOfWeek() todays weekday (1 = Monday, 7 = Sunday)
+ // b = KLocale::weekStartDay() first day of week (1 = Monday, 7 = Sunday)
+ weekStartOfs = today.dayOfWeek() - KGlobal::locale()->weekStartDay();
+ if(weekStartOfs < 0) {
+ weekStartOfs = 7 + weekStartOfs;
+ }
+ thisWeek = today.addDays(-weekStartOfs);
+ lastWeek = thisWeek.addDays(-7);
+ thisYear.setYMD(today.year(), 1, 1);
+ if(KMyMoneyGlobalSettings::startDate().date() != QDate(1900,1,1))
+ new KMyMoneyRegister::FancyDateGroupMarker(this, KMyMoneyGlobalSettings::startDate().date(), i18n("Prior transactions possibly filtered"));
+
+ if(KMyMoneyGlobalSettings::showFancyMarker()) {
+ if(m_account.lastReconciliationDate().isValid())
+ new KMyMoneyRegister::StatementGroupMarker(this, KMyMoneyRegister::Deposit, m_account.lastReconciliationDate(), i18n("Last reconciliation"));
+
+ if(!m_account.value("lastImportedTransactionDate").isEmpty()
+ && !m_account.value("lastStatementBalance").isEmpty()) {
+ MyMoneyMoney balance(m_account.value("lastStatementBalance"));
+ if(m_account.accountGroup() == MyMoneyAccount::Liability)
+ balance = -balance;
+ QString txt = i18n("Online Statement Balance: %1").arg(balance.formatMoney(m_account.fraction()));
+ new KMyMoneyRegister::StatementGroupMarker(this, KMyMoneyRegister::Deposit, QDate::fromString(m_account.value("lastImportedTransactionDate"), Qt::ISODate), txt);
+ }
+
+ new KMyMoneyRegister::FancyDateGroupMarker(this, thisYear, i18n("This year"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, lastMonth, i18n("Last month"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, thisMonth, i18n("This month"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, lastWeek, i18n("Last week"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, thisWeek, i18n("This week"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, yesterday, i18n("Yesterday"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, today, i18n("Today"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, today.addDays(1), i18n("Future transactions"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, thisWeek.addDays(7), i18n("Next week"));
+ new KMyMoneyRegister::FancyDateGroupMarker(this, thisMonth.addMonths(1), i18n("Next month"));
+
+ } else {
+ new KMyMoneyRegister::SimpleDateGroupMarker(this, today.addDays(1), i18n("Future transactions"));
+ }
+ if(KMyMoneyGlobalSettings::showFiscalMarker()) {
+ QDate currentFiscalYear(QDate::currentDate().year(), KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay());
+
+ if(QDate::currentDate() < currentFiscalYear)
+ currentFiscalYear = currentFiscalYear.addYears(-1);
+ QDate previousFiscalYear = currentFiscalYear.addYears(-1);
+ new KMyMoneyRegister::FiscalYearGroupMarker(this, currentFiscalYear, i18n("Current fiscal year"));
+ new KMyMoneyRegister::FiscalYearGroupMarker(this, currentFiscalYear.addYears(-1), i18n("Previous fiscal year"));
+ new KMyMoneyRegister::FiscalYearGroupMarker(this, currentFiscalYear.addYears(1), i18n("Next fiscal year"));
+ }
+ break;
+
+ case KMyMoneyRegister::TypeSort:
+ if(KMyMoneyGlobalSettings::showFancyMarker()) {
+ new KMyMoneyRegister::TypeGroupMarker(this, KMyMoneyRegister::Deposit, m_account.accountType());
+ new KMyMoneyRegister::TypeGroupMarker(this, KMyMoneyRegister::Payment, m_account.accountType());
+ }
+ break;
+
+ case KMyMoneyRegister::ReconcileStateSort:
+ if(KMyMoneyGlobalSettings::showFancyMarker()) {
+ new KMyMoneyRegister::ReconcileGroupMarker(this, MyMoneySplit::NotReconciled);
+ new KMyMoneyRegister::ReconcileGroupMarker(this, MyMoneySplit::Cleared);
+ new KMyMoneyRegister::ReconcileGroupMarker(this, MyMoneySplit::Reconciled);
+ new KMyMoneyRegister::ReconcileGroupMarker(this, MyMoneySplit::Frozen);
+ }
+ break;
+
+ case KMyMoneyRegister::PayeeSort:
+ if(KMyMoneyGlobalSettings::showFancyMarker()) {
+ while(p) {
+ t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t) {
+ list[t->sortPayee()] = 1;
+ }
+ p = p->nextItem();
+ }
+ for(it = list.begin(); it != list.end(); ++it) {
+ name = it.key();
+ if(name.isEmpty()) {
+ name = i18n("Unknown payee", "Unknown");
+ }
+ new KMyMoneyRegister::PayeeGroupMarker(this, name);
+ }
+ }
+ break;
+
+ case KMyMoneyRegister::CategorySort:
+ if(KMyMoneyGlobalSettings::showFancyMarker()) {
+ while(p) {
+ t = dynamic_cast<KMyMoneyRegister::Transaction*>(p);
+ if(t) {
+ list[t->sortCategory()] = 1;
+ }
+ p = p->nextItem();
+ }
+ for(it = list.begin(); it != list.end(); ++it) {
+ name = it.key();
+ if(name.isEmpty()) {
+ name = i18n("Unknown category", "Unknown");
+ }
+ new KMyMoneyRegister::CategoryGroupMarker(this, name);
+ }
+ }
+ break;
+
+ case KMyMoneyRegister::SecuritySort:
+ if(KMyMoneyGlobalSettings::showFancyMarker()) {
+ while(p) {
+ t = dynamic_cast<KMyMoneyRegister::InvestTransaction*>(p);
+ if(t) {
+ list[t->sortSecurity()] = 1;
+ }
+ p = p->nextItem();
+ }
+ for(it = list.begin(); it != list.end(); ++it) {
+ name = it.key();
+ if(name.isEmpty()) {
+ name = i18n("Unknown security", "Unknown");
+ }
+ new KMyMoneyRegister::CategoryGroupMarker(this, name);
+ }
+ }
+ break;
+
+ default: // no markers supported
+ break;
+ }
+}
+
+void Register::removeUnwantedGroupMarkers(void)
+{
+ // remove all trailing group markers except statement markers
+ KMyMoneyRegister::RegisterItem* q;
+ KMyMoneyRegister::RegisterItem* p = lastItem();
+ while(p) {
+ q = p;
+ if(dynamic_cast<KMyMoneyRegister::Transaction*>(p)
+ || dynamic_cast<KMyMoneyRegister::StatementGroupMarker*>(p))
+ break;
+
+ p = p->prevItem();
+ delete q;
+ }
+
+ // remove all adjacent group markers
+ bool lastWasGroupMarker = false;
+ p = lastItem();
+ while(p) {
+ q = p;
+ KMyMoneyRegister::GroupMarker* m = dynamic_cast<KMyMoneyRegister::GroupMarker*>(p);
+ p = p->prevItem();
+ if(m) {
+ m->markVisible(true);
+ // make adjacent group marker invisible except those that show statement information
+ if(lastWasGroupMarker && (dynamic_cast<KMyMoneyRegister::StatementGroupMarker*>(m) == 0)) {
+ m->markVisible(false);
+ }
+ lastWasGroupMarker = true;
+ } else if(q->isVisible())
+ lastWasGroupMarker = false;
+ }
+}
+
+
+#include "register.moc"
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/widgets/register.h b/kmymoney2/widgets/register.h
new file mode 100644
index 0000000..d9d2627
--- /dev/null
+++ b/kmymoney2/widgets/register.h
@@ -0,0 +1,605 @@
+/***************************************************************************
+ register.h
+ ----------
+ begin : Fri Mar 10 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REGISTER_H
+#define REGISTER_H
+
+// Some STL headers in GCC4.3 contain operator new. Memory checker mangles these
+#ifdef _CHECK_MEMORY
+ #undef new
+#endif
+
+#include <algorithm>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtable.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qwidgetlist.h>
+#include <qmap.h>
+#include <qpair.h>
+#include <qevent.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+#ifdef _CHECK_MEMORY
+ #include <kmymoney/mymoneyutils.h>
+#endif
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/registeritem.h>
+#include <kmymoney/transaction.h>
+#include <kmymoney/transactioneditorcontainer.h>
+#include <kmymoney/selectedtransaction.h>
+#include <kmymoney/transactionsortoption.h>
+
+class RegisterToolTip;
+
+namespace KMyMoneyRegister {
+
+typedef enum {
+ UnknownSort = 0, //< unknown sort criteria
+ PostDateSort = 1, //< sort by post date
+ EntryDateSort, //< sort by entry date
+ PayeeSort, //< sort by payee name
+ ValueSort, //< sort by value
+ NoSort, //< sort by number field
+ EntryOrderSort, //< sort by entry order
+ TypeSort, //< sort by CashFlowDirection
+ CategorySort, //< sort by Category
+ ReconcileStateSort, //< sort by reconciliation state
+ SecuritySort, //< sort by security (only useful for investment accounts)
+ // insert new values in front of this line
+ MaxSortFields
+} TransactionSortField;
+
+typedef enum {
+ Ascending = 0, //< sort in ascending order
+ Descending //< sort in descending order
+} SortDirection;
+
+class Register;
+class RegisterItem;
+class ItemPtrVector;
+
+const QString sortOrderToText(TransactionSortField idx);
+TransactionSortField textToSortOrder(const QString& text);
+
+
+class QWidgetContainer : public QMap<QString, QWidget*>
+{
+public:
+ QWidgetContainer() {}
+
+ QWidget* haveWidget(const QString& name) const {
+ QWidgetContainer::const_iterator it_w;
+ it_w = find(name);
+ if(it_w != end())
+ return *it_w;
+ return 0;
+ }
+
+ void removeOrphans(void) {
+ QWidgetContainer::iterator it_w;
+ for(it_w = begin(); it_w != end(); ) {
+ if((*it_w) && (*it_w)->parent())
+ ++it_w;
+ else {
+ delete (*it_w);
+ remove(it_w);
+ it_w = begin();
+ }
+ }
+ }
+
+};
+
+class GroupMarker : public RegisterItem
+{
+public:
+ GroupMarker(Register* parent, const QString& txt = QString());
+ ~GroupMarker();
+ void setText(const QString& txt) { m_txt = txt; }
+ const QString& text(void) const { return m_txt; }
+ bool isSelectable(void) const { return false; }
+ bool canHaveFocus(void) const { return false; }
+ int numRows(void) const { return 1; }
+
+ virtual const char* className(void) { return "GroupMarker"; }
+
+ bool isErronous(void) const { return false; }
+
+ void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+ void paintFormCell(QPainter* /* painter */, int /* row */, int /* col */, const QRect& /* r */, bool /* selected */, const QColorGroup& /* cg */) {}
+
+ int rowHeightHint(void) const;
+
+ bool matches(const QString&) const { return true; }
+ virtual int sortSamePostDate(void) const { return 0; }
+
+protected:
+ void setupColors(QColorGroup& cg);
+
+protected:
+ QString m_txt;
+ unsigned int m_drawCounter;
+ bool m_showDate;
+
+ static QPixmap* m_bg;
+ static int m_bgRefCnt;
+};
+
+
+class FancyDateGroupMarker : public GroupMarker
+{
+public:
+ FancyDateGroupMarker(Register* parent, const QDate& date, const QString& txt);
+
+ virtual const QDate& sortPostDate(void) const { return m_date; }
+ virtual const QDate& sortEntryDate(void) const { return m_date; }
+ virtual const char* className(void) { return "FancyDateGroupMarker"; }
+private:
+ QDate m_date;
+};
+
+class StatementGroupMarker : public FancyDateGroupMarker
+{
+public:
+ StatementGroupMarker(Register* parent, CashFlowDirection dir, const QDate& date, const QString& txt );
+ CashFlowDirection sortType(void) const { return m_dir; }
+ virtual int sortSamePostDate(void) const { return 3; }
+private:
+ CashFlowDirection m_dir;
+};
+
+class SimpleDateGroupMarker : public FancyDateGroupMarker
+{
+public:
+ SimpleDateGroupMarker(Register* parent, const QDate& date, const QString& txt);
+ void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+ int rowHeightHint(void) const;
+ virtual const char* className(void) { return "SimpleDateGroupMarker"; }
+};
+
+class TypeGroupMarker : public GroupMarker
+{
+public:
+ TypeGroupMarker(Register* parent, CashFlowDirection dir, MyMoneyAccount::accountTypeE accType);
+ CashFlowDirection sortType(void) const { return m_dir; }
+private:
+ CashFlowDirection m_dir;
+};
+
+class FiscalYearGroupMarker : public FancyDateGroupMarker
+{
+public:
+ FiscalYearGroupMarker(Register* parent, const QDate& date, const QString& txt);
+ virtual const char* className(void) { return "FiscalYearGroupMarker"; }
+ virtual int sortSamePostDate(void) const { return 1; }
+
+protected:
+ void setupColors(QColorGroup& cg);
+};
+
+class PayeeGroupMarker : public GroupMarker
+{
+public:
+ PayeeGroupMarker(Register* parent, const QString& name);
+ const QString& sortPayee(void) const { return m_txt; }
+};
+
+class CategoryGroupMarker : public GroupMarker
+{
+public:
+ CategoryGroupMarker(Register* parent, const QString& category);
+ const QString& sortCategory(void) const { return m_txt; }
+ const QString& sortSecurity(void) const { return m_txt; }
+
+ virtual const char* className(void) { return "CategoryGroupMarker"; }
+};
+
+class ReconcileGroupMarker : public GroupMarker
+{
+public:
+ ReconcileGroupMarker(Register* parent, MyMoneySplit::reconcileFlagE state);
+ virtual MyMoneySplit::reconcileFlagE sortReconcileState(void) const { return m_state; }
+private:
+ MyMoneySplit::reconcileFlagE m_state;
+};
+
+
+class ItemPtrVector : public QValueVector<RegisterItem *>
+{
+public:
+ ItemPtrVector() {}
+
+ void sort(void);
+
+protected:
+ /**
+ * sorter's compare routine. Returns true if i1 < i2
+ */
+ static bool item_cmp(RegisterItem* i1, RegisterItem* i2);
+};
+
+
+class Register : public TransactionEditorContainer
+{
+ Q_OBJECT
+
+ // friend class QHeader;
+ // friend class QTableHeader;
+ // friend class RegisterItem;
+ friend class Transaction;
+ friend class StdTransaction;
+ friend class InvestTransaction;
+
+public:
+ Register(QWidget *parent = 0, const char *name = 0);
+ virtual ~Register();
+
+ /**
+ * add the item @a p to the register
+ */
+ void addItem(RegisterItem* p);
+
+ /**
+ * insert the item @a p into the register after item @a q
+ */
+ void insertItemAfter(RegisterItem* p, RegisterItem* q);
+
+ /**
+ * remove the item @p from the register
+ */
+ void removeItem(RegisterItem* p);
+
+ /**
+ * This method returns a list of pointers to all selected items
+ * in the register
+ *
+ * @retval QValueList<RegisterItem*>
+ */
+ QValueList<RegisterItem*> selectedItems(void) const;
+
+ /**
+ * Construct a list of all currently selected transactions in the register.
+ * If the current item carrying the focus (see focusItem() ) is selected
+ * it will be the first one contained in the list.
+ *
+ * @param list reference to QValueList receiving the SelectedTransaction()'s
+ */
+ void selectedTransactions(SelectedTransactions& list) const;
+
+ QString text(int row, int col) const;
+ QWidget* createEditor(int row, int col, bool initFromCell) const;
+ void setCellContentFromEditor(int row, int col);
+ QWidget* cellWidget(int row, int col) const;
+ void endEdit(int row, int col, bool accept, bool replace);
+ void paintCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+
+ void resizeData(int) {}
+ QTableItem* item(int, int) { return 0; }
+ void setItem(int, int, QTableItem*) {}
+ void clearCell(int, int) {}
+ void clearCellWidget(int, int);
+
+ /**
+ * Override the QTable member function to avoid display of focus
+ */
+ void paintFocus(QPainter*, const QRect& ) {}
+
+ /**
+ * Override the QTable member function to avoid functionality
+ */
+ void updateCell(int /* row */, int /* col */) {}
+
+ RegisterItem* focusItem(void) const { return m_focusItem; }
+ RegisterItem* anchorItem(void) const { return m_selectAnchor; }
+
+ /**
+ * set focus to specific item.
+ * @return true if the item got focus
+ */
+ bool setFocusItem(RegisterItem* focusItem);
+
+ void setAnchorItem(RegisterItem* anchorItem);
+
+ /**
+ * Set focus to the first focussable item
+ * @return true if a focussable item was found
+ */
+ bool setFocusToTop(void);
+
+ /**
+ * Select @a item and unselect all others if @a dontChangeSelections
+ * is @a false. If m_buttonState differs from Qt::NoButton (method is
+ * called as a result of a mouse button press), then the setting of
+ * @a dontChangeSelections has no effect.
+ */
+ void selectItem(RegisterItem* item, bool dontChangeSelections = false);
+
+ /**
+ * Clears all items in the register. All objects
+ * added to the register will be deleted.
+ */
+ void clear(void);
+
+ void updateRegister(bool forceUpdateRowHeight = false);
+
+ /**
+ * Assign all visible items an alternate background color
+ */
+ void updateAlternate(void) const;
+
+ /**
+ * make sure, we only show a single marker in a row
+ * through hiding unused ones
+ */
+ void suppressAdjacentMarkers(void);
+
+ /**
+ * Adjusts column @a col so that all data fits in width.
+ */
+ void adjustColumn(int col);
+
+ /**
+ * Convenience method to setup the register to show the columns
+ * based on the account type of @a account. If @a showAccountColumn
+ * is @a true then the account column is shown independant of the
+ * account type. If @a account does not have an @a id, all columns
+ * will be hidden.
+ */
+ void setupRegister(const MyMoneyAccount& account, bool showAccountColumn = false);
+
+ /**
+ * Show the columns contained in @a cols for @a account. @a account
+ * can be left empty ( MyMoneyAccount() ) e.g. for the search dialog.
+ */
+ void setupRegister(const MyMoneyAccount& account, const QValueList<Column>& cols);
+
+ void setSortOrder(const QString& order);
+ const QValueList<TransactionSortField>& sortOrder(void) const { return m_sortOrder; }
+ TransactionSortField primarySortKey(void) const;
+ void sortItems(void);
+
+ /**
+ * This member returns the last visible column that is used by the register
+ * after it has been setup using setupRegister().
+ *
+ * @return last actively used column (base 0)
+ */
+ Column lastCol(void) const { return m_lastCol; }
+
+ RegisterItem* firstItem(void) const;
+ RegisterItem* firstVisibleItem(void) const;
+ RegisterItem* nextItem(RegisterItem*) const;
+ RegisterItem* lastItem(void) const;
+ RegisterItem* lastVisibleItem(void) const;
+ RegisterItem* prevItem(RegisterItem*) const;
+ RegisterItem* itemAtRow(int row) const;
+
+ void resize(int col);
+
+ void forceUpdateLists(void) { m_listsDirty = true; }
+
+ void ensureItemVisible(RegisterItem* item);
+
+ void arrangeEditWidgets(QMap<QString, QWidget*>& editWidgets, Transaction* t);
+ void removeEditWidgets(QMap<QString, QWidget*>& editWidgets);
+ void tabOrder(QWidgetList& tabOrderWidgets, KMyMoneyRegister::Transaction* t) const;
+
+ int rowHeightHint(void) const;
+
+ void clearSelection(void);
+
+ bool markErronousTransactions(void) const { return (m_markErronousTransactions & 0x01) != 0; }
+
+ /**
+ * This method creates a specifc transaction according to the
+ * transaction passed in @a transaction.
+ *
+ * @param parent pointer to register where the created object should be added
+ * @param transaction the transaction which should be used to create the object
+ * @param split the split of the transaction which should be used to create the object
+ * @param uniqueId an int that will be used to construct the id of the item
+ *
+ * @return pointer to created object (0 upon failure)
+ */
+ static Transaction* transactionFactory(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+
+ const MyMoneyAccount& account(void) const { return m_account; }
+
+ void repaintItems(RegisterItem* first = 0, RegisterItem* last = 0);
+
+ unsigned int drawCounter(void) const { return m_drawCounter; }
+
+ /**
+ * This method creates group marker items and adds them to the register
+ */
+ void addGroupMarkers(void);
+
+ /**
+ * This method removes all trailing group markers and in a second
+ * run reduces all adjacent group markers to show only one. In that
+ * case the last one will remain.
+ */
+ void removeUnwantedGroupMarkers(void);
+
+ void setLedgerLensForced(bool forced=true) { m_ledgerLensForced = forced; }
+
+ /**
+ * Sets the selection mode to @a mode. Supported modes are QTable::Single and
+ * QTable::Multi. QTable::Multi is the default when the object is created.
+ */
+ void setSelectionMode(SelectionMode mode) { m_selectionMode = mode; }
+
+protected:
+
+ void drawContents(QPainter *p, int cx, int cy, int cw, int ch);
+
+ void contentsMouseReleaseEvent( QMouseEvent *e );
+
+ void unselectItems(int from = -1, int to = -1) { doSelectItems(from, to, false); }
+ void selectItems(int from, int to) { doSelectItems(from, to, true); }
+ void doSelectItems(int from, int to, bool selected);
+ int selectedItemsCount(void) const;
+
+ void focusOutEvent(QFocusEvent*);
+ void focusInEvent(QFocusEvent*);
+ void keyPressEvent(QKeyEvent*);
+
+ int rowToIndex(int row) const;
+ void setupItemIndex(int rowCount);
+
+ /**
+ * This method determines the register item that is one page
+ * further down or up in the ledger from the previous focus item.
+ * The height to scroll is determined by visibleHeight()
+ *
+ * @param key Qt::Page_Up or Qt::Page_Down depending on the direction to scroll
+ * @param state state of Qt::ShiftButton, Qt::ControlButton, Qt::AltButton and
+ * Qt::MetaButton.
+ */
+ void scrollPage(int key, ButtonState state);
+
+ /**
+ * This method determines the pointer to a RegisterItem
+ * based on the item's @a id. If @a id is empty, this method
+ * returns @a m_lastItem.
+ *
+ * @param id id of the item to be searched
+ * @return pointer to RegisterItem or 0 if not found
+ */
+ RegisterItem* itemById(const QString& id) const;
+
+ void insertWidget(int row, int col, QWidget* w);
+
+ /**
+ * Override logic and use standard QFrame behaviour
+ */
+ bool focusNextPrevChild(bool next);
+
+ bool eventFilter(QObject* o, QEvent* e);
+
+ void handleItemChange(RegisterItem* old, bool shift, bool control);
+
+ void selectRange(RegisterItem* from, RegisterItem* to, bool invert, bool includeFirst, bool clearSel);
+
+ // DND
+ void dragMoveEvent(QDragMoveEvent* event);
+ void dropEvent(QDropEvent* event);
+ Transaction* dropTransaction(QPoint cPos) const;
+
+protected slots:
+ void resize(void);
+
+ void selectItem(int row, int col, int button, const QPoint & mousePos );
+ void slotEnsureItemVisible(void);
+ void slotDoubleClicked(int, int, int, const QPoint&);
+
+ void slotToggleErronousTransactions(void);
+ void slotAutoColumnSizing(int section);
+
+signals:
+ void selectionChanged(void);
+ void selectionChanged(const KMyMoneyRegister::SelectedTransactions& list);
+ /**
+ * This signal is emitted when the focus and selection changes to @p item.
+ *
+ * @param item pointer to transaction that received the focus and was selected
+ */
+ void focusChanged(KMyMoneyRegister::Transaction* item);
+
+ /**
+ * This signal is emitted when the focus changes but the selection remains
+ * the same. This usually happens when the focus is changed using the keyboard.
+ */
+ void focusChanged(void);
+
+ /**
+ * This signal is emitted when an @p item is about to be selected. The boolean
+ * @p okToSelect is preset to @c true. If the @p item should not be selected
+ * for whatever reason, the boolean @p okToSelect should be reset to @c false
+ * by the connected slot.
+ */
+ void aboutToSelectItem(KMyMoneyRegister::RegisterItem* item, bool& okToSelect);
+
+ void editTransaction(void);
+ void headerClicked(void);
+
+ /**
+ * This signal is sent out when the user clicks on the ReconcileStateColumn and
+ * only a single transaction is selected.
+ */
+ void reconcileStateColumnClicked(KMyMoneyRegister::Transaction* item);
+
+ /**
+ * This signal is sent out, if an item without a transaction id has been selected.
+ */
+ void emptyItemSelected(void);
+
+ /**
+ * This signal is sent out, if the user selects an item with the right mouse button
+ */
+ void openContextMenu(void);
+
+ /**
+ * This signal is sent out when a new item has been added to the register
+ */
+ void itemAdded(RegisterItem* item);
+
+protected:
+ ItemPtrVector m_items;
+ QValueVector<RegisterItem*> m_itemIndex;
+ RegisterItem* m_selectAnchor;
+ RegisterItem* m_focusItem;
+ RegisterItem* m_ensureVisibleItem;
+ RegisterItem* m_firstItem;
+ RegisterItem* m_lastItem;
+ RegisterItem* m_firstErronous;
+ RegisterItem* m_lastErronous;
+
+ int m_markErronousTransactions;
+ int m_rowHeightHint;
+
+ MyMoneyAccount m_account;
+
+ bool m_ledgerLensForced;
+ SelectionMode m_selectionMode;
+
+private:
+ bool m_listsDirty;
+ bool m_ignoreNextButtonRelease;
+ bool m_needInitialColumnResize;
+ Qt::ButtonState m_buttonState;
+ Column m_lastCol;
+ QValueList<TransactionSortField> m_sortOrder;
+ QMap<QPair<int, int>, QWidget*> m_cellWidgets;
+ RegisterToolTip* m_tooltip;
+ QRect m_lastRepaintRect;
+ unsigned int m_drawCounter;
+};
+
+} // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/widgets/registeritem.cpp b/kmymoney2/widgets/registeritem.cpp
new file mode 100644
index 0000000..6ef082f
--- /dev/null
+++ b/kmymoney2/widgets/registeritem.cpp
@@ -0,0 +1,116 @@
+/***************************************************************************
+ registeritem.cpp - description
+ -------------------
+ begin : Tue Jun 13 2006
+ copyright : (C) 2000-2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/registeritem.h>
+#include <kmymoney/register.h>
+
+#include "../kmymoneyglobalsettings.h"
+
+using namespace KMyMoneyRegister;
+
+QDate RegisterItem::nullDate;
+MyMoneyMoney RegisterItem::nullValue;
+
+RegisterItem::RegisterItem() :
+ m_parent(0),
+ m_prev(0),
+ m_next(0)
+{
+ init();
+}
+
+RegisterItem::RegisterItem(Register* parent) :
+ m_parent(parent),
+ m_prev(0),
+ m_next(0)
+{
+ init();
+ parent->addItem(this);
+}
+
+void RegisterItem::init(void)
+{
+ m_startRow = 0;
+ m_rowsRegister = 1;
+ m_rowsForm = 1;
+ m_visible = true;
+}
+
+RegisterItem::~RegisterItem()
+{
+ m_parent->removeItem(this);
+}
+
+void RegisterItem::setParent(Register* parent)
+{
+ m_parent = parent;
+}
+
+void RegisterItem::setNumRowsRegister(int rows)
+{
+ if(rows != m_rowsRegister) {
+ m_rowsRegister = rows;
+ if(m_parent)
+ m_parent->forceUpdateLists();
+ }
+}
+
+bool RegisterItem::markVisible(bool visible)
+{
+ if(m_visible == visible)
+ return false;
+ m_visible = visible;
+ return true;
+}
+
+void RegisterItem::setVisible(bool visible)
+{
+ if(markVisible(visible) && m_parent) {
+ if(visible) {
+ for(int i = startRow(); i < startRow() + numRowsRegister(); ++i) {
+ m_parent->showRow(i);
+ m_parent->setRowHeight(i, rowHeightHint());
+ }
+ } else {
+ for(int i = startRow(); i < startRow() + numRowsRegister(); ++i) {
+ m_parent->hideRow(i);
+ }
+ }
+ }
+}
+
+int RegisterItem::rowHeightHint(void) const
+{
+ if(!m_visible)
+ return 0;
+
+ if(m_parent) {
+ return m_parent->rowHeightHint();
+ }
+
+ QFontMetrics fm( KMyMoneyGlobalSettings::listCellFont() );
+ return fm.lineSpacing()+6;
+}
diff --git a/kmymoney2/widgets/registeritem.h b/kmymoney2/widgets/registeritem.h
new file mode 100644
index 0000000..84afa84
--- /dev/null
+++ b/kmymoney2/widgets/registeritem.h
@@ -0,0 +1,226 @@
+/***************************************************************************
+ registeritem.h - description
+ -------------------
+ begin : Tue Jun 13 2006
+ copyright : (C) 2000-2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REGISTERITEM_H
+#define REGISTERITEM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qpainter.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/mymoneyobject.h>
+
+namespace KMyMoneyRegister {
+
+typedef enum {
+ Deposit = 0, //< transaction is deposit
+ Payment, //< transaction is payment
+ Unknown //< transaction cashflow is unknown
+} CashFlowDirection;
+
+typedef enum {
+ ActionNone = -1,
+ ActionCheck = 0,
+ /* these should be values which qt 3.3 never uses for QTab:
+ * qt starts upwards from 0
+ */
+ ActionDeposit = 12201,
+ ActionTransfer = 12202,
+ ActionWithdrawal = 12203,
+ ActionAtm,
+ // insert new values above this line
+ MaxAction
+} Action;
+
+
+class Register;
+
+/**
+ * @author Thomas Baumgart
+ */
+class RegisterItem
+{
+public:
+ RegisterItem();
+ RegisterItem(Register* parent);
+ virtual ~RegisterItem();
+
+ virtual const char* className(void) = 0;
+
+ virtual bool isSelectable(void) const = 0;
+ virtual bool isSelected(void) const { return false; }
+ virtual void setSelected(bool /* selected*/) {}
+
+ virtual bool canHaveFocus(void) const = 0;
+ virtual bool hasFocus(void) const { return false; }
+ virtual bool hasEditorOpen(void) const { return false; }
+
+ virtual void setFocus(bool /*focus*/, bool updateLens = true) { updateLens = false; }
+
+ virtual bool isErronous(void) const = 0;
+
+ // helper functions used for sorting
+ virtual const QDate& sortPostDate(void) const { return nullDate; }
+ virtual int sortSamePostDate(void) const = 0;
+ virtual const QDate& sortEntryDate(void) const { return nullDate; }
+ virtual const QString& sortPayee(void) const { return QString::null; }
+ virtual const MyMoneyMoney& sortValue(void) const { return nullValue; }
+ virtual const QString& sortNumber(void) const { return QString::null; }
+ virtual const QString& sortEntryOrder(void) const { return QString::null; }
+ virtual CashFlowDirection sortType(void) const { return Deposit; }
+ virtual const QString& sortCategory(void) const { return QString::null; }
+ virtual MyMoneySplit::reconcileFlagE sortReconcileState(void) const { return MyMoneySplit::MaxReconcileState; }
+ virtual const QString& sortSecurity(void) const { return QString::null; }
+
+ /**
+ * This method sets the row offset of the item in the register
+ * to row.
+ *
+ * @param row row offset
+ *
+ * @note The row offset is based on QTable rows, not register
+ * items.
+ */
+ virtual void setStartRow(int row) { m_startRow = row; }
+ int startRow(void) const { return m_startRow; }
+ virtual int rowHeightHint(void) const;
+
+ /**
+ * This method modifies the number of rows required to display this item
+ * in a Register.
+ * It calls Register::forceUpdateLists() when the number differs.
+ */
+ virtual void setNumRowsRegister(int rows);
+
+ /**
+ * This method modifies the number of rows required to display this item
+ * in a Form.
+ */
+ virtual void setNumRowsForm(int rows) { m_rowsForm = rows; }
+
+ /**
+ * This method returns the number of rows required to display this item
+ * in a Register
+ */
+ virtual int numRowsRegister(void) const { return m_rowsRegister; }
+
+ /**
+ * This method returns the number of rows required to display this item
+ * in a Form
+ */
+ virtual int numRowsForm(void) const { return m_rowsForm; }
+ virtual int numColsForm(void) const { return 1; }
+
+ /**
+ * This method sets up the register item to be shown in normal (@p alternate = @p false)
+ * or alternate (@p alternate = @p true) background.
+ *
+ * @param alternate selects normal or alternate background
+ */
+ virtual void setAlternate(bool alternate) { m_alternate = alternate; }
+
+ virtual void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg) = 0;
+ virtual void paintFormCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg) = 0;
+
+ virtual const QString& id(void) const { return MyMoneyObject::emptyId(); }
+
+ /**
+ * Sets the parent of this item to be the register @p parent
+ *
+ * @param parent pointer to register
+ */
+ void setParent(Register* parent);
+
+ /**
+ * This member returns a pointer to the parent object
+ *
+ * @retval pointer to Register
+ */
+ Register* parent(void) const { return m_parent; }
+
+ void setNeedResize(void) { m_needResize = true; }
+
+ bool isVisible(void) const { return m_visible; }
+
+ /**
+ * Marks the item visible depending on @a visible and
+ * updates the underlying register object
+ */
+ virtual void setVisible(bool visible);
+
+ /**
+ * Marks the item visible depending on @a visible but
+ * does not update the underlying register object. Returns
+ * true, if visibility has changed.
+ */
+ virtual bool markVisible(bool visible);
+
+ void setNextItem(RegisterItem* p) { m_next = p; }
+ void setPrevItem(RegisterItem* p) { m_prev = p; }
+ RegisterItem* nextItem(void) const { return m_next; }
+ RegisterItem* prevItem(void) const { return m_prev; }
+
+ virtual bool matches(const QString&) const = 0;
+
+ /**
+ * Checks if the mouse hovered over an area that has a tooltip associated with it.
+ * The mouse position is given in relative coordinates to the @a startRow and the
+ * @a row and @a col of the item are also passed as relative values.
+ *
+ * If a tooltip shall be shown, this method presets the rectangle @a r with the
+ * area in register coordinates and @a msg with the string that will be passed
+ * to QToolTip::tip. @a true is returned in this case.
+ *
+ * If no tooltip is available, @a false will be returned.
+ */
+ virtual bool maybeTip(const QPoint& /* relpos */, int /* row */, int /* col */, QRect& /* r */, QString& /* msg */) { return false; }
+
+protected:
+ /// This method serves as helper for all constructors
+ void init(void);
+
+protected:
+ Register* m_parent;
+ RegisterItem* m_prev;
+ RegisterItem* m_next;
+ int m_startRow;
+ int m_rowsRegister;
+ int m_rowsForm;
+ bool m_alternate;
+ bool m_needResize;
+ bool m_visible;
+
+private:
+ static QDate nullDate;
+ static MyMoneyMoney nullValue;
+};
+
+} // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/widgets/registersearchline.cpp b/kmymoney2/widgets/registersearchline.cpp
new file mode 100644
index 0000000..f0ef6e9
--- /dev/null
+++ b/kmymoney2/widgets/registersearchline.cpp
@@ -0,0 +1,301 @@
+/***************************************************************************
+ registersearchline.cpp
+ -------------------
+ copyright : (C) 2006 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qapplication.h>
+#include <qlabel.h>
+#include <qtoolbutton.h>
+#include <qtimer.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <registersearchline.h>
+
+using namespace KMyMoneyRegister;
+
+class RegisterSearchLine::RegisterSearchLinePrivate
+{
+public:
+ RegisterSearchLinePrivate() :
+ reg(0),
+ combo(0),
+ queuedSearches(0),
+ status(0) {}
+
+ Register* reg;
+ QComboBox* combo;
+ QString search;
+ int queuedSearches;
+ int status;
+};
+
+RegisterSearchLine::RegisterSearchLine(QWidget* parent, Register* reg, const char* name) :
+ KLineEdit(parent, name),
+ d(new RegisterSearchLinePrivate)
+{
+ init(reg);
+}
+
+RegisterSearchLine::RegisterSearchLine(QWidget* parent, const char* name) :
+ KLineEdit(parent, name),
+ d(new RegisterSearchLinePrivate)
+{
+ init(0);
+}
+
+void RegisterSearchLine::init(Register *reg)
+{
+ d->reg = reg;
+ connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(queueSearch(const QString&)));
+
+ QLabel* label = new QLabel(i18n("label for status combo", "Stat&us"), parentWidget());
+ d->combo = new QComboBox(parentWidget());
+ // don't change the order of the following lines unless updating
+ // the case labels in RegisterSearchLine::itemMatches() at the same time
+ d->combo->insertItem(SmallIcon("run"), i18n("Any status"));
+ d->combo->insertItem(SmallIcon("fileimport"), i18n("Imported"));
+ d->combo->insertItem(SmallIcon("connect_creating"), i18n("Matched"));
+ d->combo->insertItem(SmallIcon("attention"), i18n("Erroneous"));
+ d->combo->insertItem(i18n("Not marked"));
+ d->combo->insertItem(i18n("Not reconciled"));
+ d->combo->insertItem(i18n("Cleared"));
+ d->combo->setCurrentItem(0);
+ connect(d->combo, SIGNAL(activated(int)), this, SLOT(slotStatusChanged(int)));
+
+ label->setBuddy(d->combo);
+
+ if(reg) {
+ connect(reg, SIGNAL(destroyed()), this, SLOT(registerDestroyed()));
+ connect(reg, SIGNAL(itemAdded(RegisterItem*)), this, SLOT(itemAdded(RegisterItem*)));
+ } else {
+ setEnabled(false);
+ }
+}
+
+RegisterSearchLine::~RegisterSearchLine()
+{
+ delete d;
+}
+
+void RegisterSearchLine::setRegister(Register* reg)
+{
+ if(d->reg) {
+ disconnect(d->reg, SIGNAL(destroyed()), this, SLOT(registerDestroyed()));
+ disconnect(d->reg, SIGNAL(itemAdded(RegisterItem*)), this, SLOT(itemAdded(RegisterItem*)));
+ }
+
+ d->reg = reg;
+
+ if(reg) {
+ connect(reg, SIGNAL(destroyed()), this, SLOT(registerDestroyed()));
+ connect(reg, SIGNAL(itemAdded(RegisterItem*)), this, SLOT(itemAdded(RegisterItem*)));
+ }
+
+ setEnabled(reg != 0);
+}
+
+void RegisterSearchLine::slotStatusChanged(int status)
+{
+ d->status = status;
+ updateSearch();
+}
+
+void RegisterSearchLine::queueSearch(const QString& search)
+{
+ d->queuedSearches++;
+ d->search = search;
+ QTimer::singleShot(200, this, SLOT(activateSearch()));
+}
+
+void RegisterSearchLine::activateSearch(void)
+{
+ --(d->queuedSearches);
+ if(d->queuedSearches == 0)
+ updateSearch(d->search);
+}
+
+void RegisterSearchLine::updateSearch(const QString& s)
+{
+ if(!d->reg)
+ return;
+
+ d->search = s.isNull() ? text() : s;
+
+ // keep track of the current focus item
+ RegisterItem* focusItem = d->reg->focusItem();
+
+ bool enabled = d->reg->isUpdatesEnabled();
+ d->reg->setUpdatesEnabled(false);
+
+ bool scrollBarVisible = d->reg->verticalScrollBar()->isVisible();
+
+ RegisterItem* p = d->reg->firstItem();
+ for(; p; p = p->nextItem()) {
+ p->setVisible(itemMatches(p, d->search));
+ }
+ d->reg->suppressAdjacentMarkers();
+ d->reg->updateAlternate();
+ d->reg->setUpdatesEnabled(enabled);
+
+ // if focus item is still visible, then make sure we have
+ // it on screen
+ if(focusItem && focusItem->isVisible()) {
+ d->reg->updateContents();
+ d->reg->ensureItemVisible(focusItem);
+ } else
+ d->reg->repaintContents();
+
+ d->reg->updateScrollBars();
+
+ // if the scrollbar's visibility changed, we need to resize the contents
+ if(scrollBarVisible != d->reg->verticalScrollBar()->isVisible()) {
+ d->reg->resize(DetailColumn);
+ }
+}
+
+bool RegisterSearchLine::itemMatches(const RegisterItem* item, const QString& s) const
+{
+ const Transaction* t = dynamic_cast<const Transaction*>(item);
+ if(t && !t->transaction().id().isEmpty()) {
+ // Keep the case list of the following switch statement
+ // in sync with the logic to fill the combo box in
+ // RegisterSearchLine::init()
+ switch(d->status) {
+ default:
+ break;
+ case 1: // Imported
+ if(!t->transaction().isImported())
+ return false;
+ break;
+ case 2: // Matched
+ if(!t->split().isMatched())
+ return false;
+ break;
+ case 3: // Erroneous
+ if(t->transaction().splitSum().isZero())
+ return false;
+ break;
+ case 4: // Not marked
+ if(t->split().reconcileFlag() != MyMoneySplit::NotReconciled)
+ return false;
+ break;
+ case 5: // Not reconciled
+ if(t->split().reconcileFlag() != MyMoneySplit::NotReconciled
+ && t->split().reconcileFlag() != MyMoneySplit::Cleared)
+ return false;
+ break;
+ case 6: // Cleared
+ if(t->split().reconcileFlag() != MyMoneySplit::Cleared)
+ return false;
+ break;
+ }
+ }
+
+ return item->matches(s);
+}
+
+void RegisterSearchLine::reset(void)
+{
+ clear();
+ d->combo->setCurrentItem(0);
+ slotStatusChanged(0);
+}
+
+void RegisterSearchLine::itemAdded(RegisterItem* item) const
+{
+ item->setVisible(itemMatches(item, text()));
+}
+
+void RegisterSearchLine::registerDestroyed(void)
+{
+ d->reg = 0;
+ setEnabled(false);
+}
+
+
+class RegisterSearchLineWidget::RegisterSearchLineWidgetPrivate
+{
+ public:
+ RegisterSearchLineWidgetPrivate() :
+ reg(0),
+ searchLine(0),
+ clearButton(0) {}
+
+ Register* reg;
+ RegisterSearchLine* searchLine;
+ QToolButton* clearButton;
+};
+
+
+RegisterSearchLineWidget::RegisterSearchLineWidget(Register* reg, QWidget* parent, const char* name) :
+ QHBox(parent, name),
+ d(new RegisterSearchLineWidgetPrivate)
+{
+ d->reg = reg;
+ setSpacing(5);
+ QTimer::singleShot(0, this, SLOT(createWidgets()));
+}
+
+RegisterSearchLineWidget::~RegisterSearchLineWidget()
+{
+ delete d;
+}
+
+RegisterSearchLine* RegisterSearchLineWidget::createSearchLine(Register* reg)
+{
+ if(!d->searchLine)
+ d->searchLine = new RegisterSearchLine(this, reg);
+ return d->searchLine;
+}
+
+void RegisterSearchLineWidget::createWidgets(void)
+{
+ if(!d->clearButton) {
+ d->clearButton = new QToolButton(this);
+ QIconSet icon = SmallIconSet(QApplication::reverseLayout() ? "clear_left" : "locationbar_erase");
+ d->clearButton->setIconSet(icon);
+ }
+
+ d->clearButton->show();
+
+ QLabel *label = new QLabel(i18n("S&earch:"), this, "kde toolbar widget");
+
+ d->searchLine = createSearchLine(d->reg);
+ d->searchLine->show();
+
+ label->setBuddy(d->searchLine);
+ label->show();
+
+ connect(d->clearButton, SIGNAL(clicked()), d->searchLine, SLOT(reset()));
+}
+
+RegisterSearchLine* RegisterSearchLineWidget::searchLine(void) const
+{
+ return d->searchLine;
+}
+
+#include "registersearchline.moc"
diff --git a/kmymoney2/widgets/registersearchline.h b/kmymoney2/widgets/registersearchline.h
new file mode 100644
index 0000000..d495ab1
--- /dev/null
+++ b/kmymoney2/widgets/registersearchline.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+ registersearchline.h
+ -------------------
+ begin : Sun Jan 14 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef REGISTERSEARCHLINE_H
+#define REGISTERSEARCHLINE_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qhbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/register.h>
+#include <kmymoney/export.h>
+
+namespace KMyMoneyRegister {
+
+/**
+ * This class makes it easy to add a search line for filtering the items
+ * in a register based on simple text. Inspired by the idea of the kdelibs
+ * class KListViewSearchLine.
+ *
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT RegisterSearchLine : public KLineEdit
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructs a RegisterSearchLine with @a reg being the register to be
+ * filtered.
+ *
+ * If @a reg is null then the widget will be disabled until a register
+ * is set with setRegister().
+ */
+ RegisterSearchLine(QWidget* parent = 0, Register* reg = 0, const char* name = 0);
+
+ /**
+ * Constructs a RegisterSearchLine
+ *
+ * The widget will be disabled until a register is set with setRegister().
+ */
+ RegisterSearchLine(QWidget* parent = 0, const char* name = 0);
+
+ /**
+ * Destroys the object
+ */
+ ~RegisterSearchLine();
+
+ /**
+ * Sets the KMyMoneyRegister that is filtered by this search line.
+ * If @a reg is null then the widget will be disabled.
+ *
+ * @see KMyMoneyRegister()
+ */
+ void setRegister(Register* reg);
+
+protected:
+ virtual bool itemMatches(const RegisterItem* item, const QString& s) const;
+
+public slots:
+ virtual void updateSearch(const QString& s = QString::null);
+ virtual void reset(void);
+
+protected slots:
+ void queueSearch(const QString& search);
+ void activateSearch(void);
+ void slotStatusChanged(int);
+
+private slots:
+ void itemAdded(RegisterItem* item) const;
+ void registerDestroyed(void);
+
+private:
+ void init(Register* reg);
+
+private:
+ class RegisterSearchLinePrivate;
+ RegisterSearchLinePrivate* const d;
+};
+
+/**
+ * Creates a widget containing a RegisterSearchLine, a label with the text
+ * "Search" and a button to clear the search. Modelled after KListViewSearchLineWidget.
+ *
+ * @author Thomas Baumgart
+ */
+class KMYMONEY_EXPORT RegisterSearchLineWidget : public QHBox
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a RegisterSearchLineWidget for @a reg with @a parent as the
+ * parent and with @a name.
+ */
+ RegisterSearchLineWidget(Register* reg = 0, QWidget* parent = 0, const char* name = 0);
+
+ /**
+ * Destroys the object
+ */
+ ~RegisterSearchLineWidget();
+
+ /**
+ * Returns a pointer to the searchline
+ */
+ RegisterSearchLine* searchLine() const;
+
+ /**
+ * Creates the search line. This can be useful to reimplement in cases where
+ * a RegisterSearchLine subclass is used.
+ */
+ virtual RegisterSearchLine* createSearchLine(Register* reg);
+
+protected slots:
+ /**
+ * Creates the widgets inside of the widget. This is called from the
+ * constructor via a single shot timer so that it is guaranteed to run
+ * after construction is complete. This makes it suitable for overriding in
+ * subclasses.
+ */
+ virtual void createWidgets(void);
+
+private:
+ class RegisterSearchLineWidgetPrivate;
+ RegisterSearchLineWidgetPrivate* const d;
+};
+
+} // namespace
+
+#endif
diff --git a/kmymoney2/widgets/scheduledtransaction.cpp b/kmymoney2/widgets/scheduledtransaction.cpp
new file mode 100644
index 0000000..98d6787
--- /dev/null
+++ b/kmymoney2/widgets/scheduledtransaction.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+ scheduledtransaction.cpp
+ -------------------
+ begin : Tue Aug 19 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <scheduledtransaction.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/register.h>
+
+using namespace KMyMoneyRegister;
+using namespace KMyMoneyTransactionForm;
+
+StdTransactionScheduled::StdTransactionScheduled(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ StdTransaction(parent, transaction, split, uniqueId),
+ m_drawCounter(parent->drawCounter()-1)
+{
+ // setup initial size
+ setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed()));
+}
+
+bool StdTransactionScheduled::paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush)
+{
+ QRect r(cellRect);
+ cg = m_parent->palette().disabled();
+
+ bool rc = Transaction::paintRegisterCellSetup(painter, row, col, cellRect, textRect, cg, brush);
+ return rc;
+}
+
+
diff --git a/kmymoney2/widgets/scheduledtransaction.h b/kmymoney2/widgets/scheduledtransaction.h
new file mode 100644
index 0000000..836ceee
--- /dev/null
+++ b/kmymoney2/widgets/scheduledtransaction.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ scheduledtransaction.h
+ -------------------
+ begin : Tue Aug 19 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef SCHEDULEDTRANSACTION_H
+#define SCHEDULEDTRANSACTION_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transaction.h>
+
+namespace KMyMoneyTransactionForm {
+ class TransactionForm;
+}; // namespace
+
+namespace KMyMoneyRegister {
+
+class StdTransactionScheduled : public StdTransaction
+{
+public:
+ StdTransactionScheduled(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~StdTransactionScheduled() {}
+
+ virtual const char* className(void) { return "StdTransactionScheduled"; }
+
+ /**
+ * This method sets the general paramaters required for the painting of a cell
+ * in the register. These are:
+ *
+ * - background color (alternating)
+ * - background color (imported transaction)
+ * - background color (matched transaction)
+ * - background color (selected transaction)
+ * - cellRect (area covering the cell)
+ * - textRect (area covering the text)
+ * - color of the pen to do the painting of text and lines
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param cellRect ref to QRect object receiving the area information for the cell
+ * @param textRect ref to QRect object receiving the area information for the text
+ * @param cg ref to QColorGroup object receiving the color information to be used
+ * @param brush ref to QBrush object receiveing the brush information to be used
+ */
+ virtual bool paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush);
+
+ bool isSelectable(void) const { return true; }
+ bool canHaveFocus(void) const { return true; }
+ virtual bool isScheduled(void) const { return true; }
+
+ virtual int sortSamePostDate(void) const { return 4; }
+
+// virtual void paintRegisterGrid(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg) const;
+
+// void registerCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+
+private:
+ unsigned int m_drawCounter;
+};
+
+}; // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
+
diff --git a/kmymoney2/widgets/selectedtransaction.cpp b/kmymoney2/widgets/selectedtransaction.cpp
new file mode 100644
index 0000000..055dc3d
--- /dev/null
+++ b/kmymoney2/widgets/selectedtransaction.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+ selectedtransaction.cpp - description
+ -------------------
+ begin : Fri Jun 2008
+ copyright : (C) 2000-2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "selectedtransaction.h"
+
+#include "register.h"
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/mymoneyfile.h>
+
+namespace KMyMoneyRegister {
+
+int SelectedTransaction::warnLevel() const
+{
+ int warnLevel = 0;
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = transaction().splits().begin(); warnLevel < 2 && it_s != transaction().splits().end(); ++it_s) {
+ const MyMoneyAccount& acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.isClosed())
+ warnLevel = 3;
+ else if((*it_s).reconcileFlag() == MyMoneySplit::Frozen)
+ warnLevel = 2;
+ else if((*it_s).reconcileFlag() == MyMoneySplit::Reconciled && warnLevel < 1)
+ warnLevel = 1;
+ }
+ return warnLevel;
+}
+
+SelectedTransactions::SelectedTransactions(const Register* r)
+{
+ r->selectedTransactions(*this);
+}
+
+int SelectedTransactions::warnLevel() const
+{
+ int warnLevel = 0;
+ SelectedTransactions::const_iterator it_t;
+ for(it_t = begin(); warnLevel < 3 && it_t != end(); ++it_t) {
+ int thisLevel = (*it_t).warnLevel();
+ if (thisLevel > warnLevel)
+ warnLevel = thisLevel;
+ }
+ return warnLevel;
+}
+
+bool SelectedTransactions::canModify() const
+{
+ return warnLevel() < 2;
+}
+
+bool SelectedTransactions::canDuplicate() const
+{
+ return warnLevel() < 3;
+}
+
+} // namespace
diff --git a/kmymoney2/widgets/selectedtransaction.h b/kmymoney2/widgets/selectedtransaction.h
new file mode 100644
index 0000000..0b82020
--- /dev/null
+++ b/kmymoney2/widgets/selectedtransaction.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ selectedtransaction.h - description
+ -------------------
+ begin : Tue Jun 13 2006
+ copyright : (C) 2000-2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef SELECTEDTRANSACTION_H
+#define SELECTEDTRANSACTION_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneyscheduled.h>
+#include <kmymoney/mymoneysplit.h>
+
+namespace KMyMoneyRegister {
+
+class SelectedTransaction
+{
+public:
+ SelectedTransaction() {}
+ SelectedTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s, const QString& scheduleId = QString()) :
+ m_transaction(t), m_split(s), m_scheduleId(scheduleId) {}
+
+ MyMoneyTransaction& transaction(void) { return m_transaction; }
+ const MyMoneyTransaction& transaction(void) const { return m_transaction; }
+ MyMoneySplit& split(void) { return m_split; }
+ const MyMoneySplit& split(void) const { return m_split; }
+
+ bool isScheduled(void) const { return !m_scheduleId.isEmpty(); }
+ const QString& scheduleId(void) const { return m_scheduleId; }
+
+ /**
+ * checks the transaction for specific reasons which would
+ * speak against editing/modifying it.
+ * @retval 0 no sweat, user can modify
+ * @retval 1 at least one split has been reconciled already
+ * @retval 2 some transactions cannot be changed anymore - parts of them are frozen
+ * @retval 3 some transactions cannot be changed anymore - they touch closed accounts
+ */
+ int warnLevel() const;
+
+private:
+ MyMoneyTransaction m_transaction;
+ MyMoneySplit m_split;
+ QString m_scheduleId;
+};
+
+class Register;
+
+class SelectedTransactions:public QValueList<SelectedTransaction>
+{
+public:
+ SelectedTransactions() {}
+ SelectedTransactions(const Register* r);
+
+ /**
+ * @return the highest warnLevel of all transactions in the list
+ */
+ int warnLevel() const;
+
+ bool canModify() const;
+ bool canDuplicate() const;
+};
+
+} // namespace
+
+#endif
+
diff --git a/kmymoney2/widgets/sortoptionlistitem.h b/kmymoney2/widgets/sortoptionlistitem.h
new file mode 100644
index 0000000..8f2cdb0
--- /dev/null
+++ b/kmymoney2/widgets/sortoptionlistitem.h
@@ -0,0 +1,390 @@
+/***************************************************************************
+ sortoptionlistitem.h
+ ----------
+ begin : Fri Jun 02 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// Note: This file will be included from transactionsortoption.ui.h
+
+static const char * sortAscendingXpm[] = {
+"16 16 145 2",
+" c None",
+". c #3368C9",
+"+ c #4276D5",
+"@ c #5284E0",
+"# c #6C95E0",
+"$ c #6A93DF",
+"% c #5585DF",
+"& c #3F72D2",
+"* c #356ACD",
+"= c #487AD7",
+"- c #4F84E6",
+"; c #B4C9EF",
+"> c #BFD1F2",
+", c #D5E1F5",
+"' c #C9D7F2",
+") c #A3BCEA",
+"! c #6A97EB",
+"~ c #3573E7",
+"{ c #376FD5",
+"] c #4378DA",
+"^ c #6B94E1",
+"/ c #D7E2F6",
+"( c #E3EAF8",
+"_ c #CDDAF4",
+": c #BED0EF",
+"< c #94B5F0",
+"[ c #4485FB",
+"} c #3A7EFB",
+"| c #3777ED",
+"1 c #386FD4",
+"2 c #4E83E7",
+"3 c #D5E0F6",
+"4 c #CADAF7",
+"5 c #C3D5F6",
+"6 c #AEC7F5",
+"7 c #C1D4F5",
+"8 c #BBCFF4",
+"9 c #9BB8F0",
+"0 c #86B0FD",
+"a c #639AFE",
+"b c #3B7FFB",
+"c c #3574E8",
+"d c #376AC8",
+"e c #4075DA",
+"f c #A9C2F2",
+"g c #E0E8F7",
+"h c #C5D6F6",
+"i c #FBFCFE",
+"j c #F8FAFE",
+"k c #FDFEFE",
+"l c #FEFEFE",
+"m c #F7F9FD",
+"n c #FAFCFE",
+"o c #A5C5FE",
+"p c #4285FE",
+"q c #4281F7",
+"r c #366DD3",
+"s c #467DE3",
+"t c #B6CCF3",
+"u c #DBE5F6",
+"v c #D1DDF5",
+"w c #E7EDF9",
+"x c #DAE5F8",
+"y c #E2EBFB",
+"z c #CDDFFE",
+"A c #508EFD",
+"B c #4C88F5",
+"C c #477CDF",
+"D c #6290E5",
+"E c #CFDCF3",
+"F c #A7C0ED",
+"G c #8FB0ED",
+"H c #EEF3FC",
+"I c #BFD6FD",
+"J c #4F8BF7",
+"K c #6696ED",
+"L c #5584DC",
+"M c #3A67BB",
+"N c #608EE4",
+"O c #C3D3F1",
+"P c #A4BEED",
+"Q c #E5EDFB",
+"R c #EFF5FE",
+"S c #DBE8FE",
+"T c #FDFDFE",
+"U c #C8DAFA",
+"V c #779FE7",
+"W c #5C88D9",
+"X c #3B67BA",
+"Y c #9DBAEC",
+"Z c #A8C1EC",
+"` c #EBF2FE",
+" . c #A6C5FE",
+".. c #B6CFFE",
+"+. c #FCFDFE",
+"@. c #DAE5F9",
+"#. c #83A7E9",
+"$. c #7EA2E4",
+"%. c #5E88D7",
+"&. c #3D73D6",
+"*. c #87A9E8",
+"=. c #9CB7EA",
+"-. c #D1DEF7",
+";. c #A8C7FE",
+">. c #669CFE",
+",. c #8CB4FD",
+"'. c #D6E2F7",
+"). c #89AAE7",
+"!. c #83A4E3",
+"~. c #4675CE",
+"{. c #477DE1",
+"]. c #84A6E5",
+"^. c #B9CDF2",
+"/. c #E4EDFE",
+"(. c #A6C6FE",
+"_. c #699DFD",
+":. c #4F8BF8",
+"<. c #739FEF",
+"[. c #D0DEF6",
+"}. c #BBCEF1",
+"|. c #88A8E5",
+"1. c #658DD8",
+"2. c #4973C2",
+"3. c #3F75DA",
+"4. c #4E82E3",
+"5. c #5F90EA",
+"6. c #669BFB",
+"7. c #5C95FC",
+"8. c #518CF7",
+"9. c #779FE8",
+"0. c #7298DD",
+"a. c #5880CB",
+"b. c #3C74DC",
+"c. c #3875E7",
+"d. c #4482F6",
+"e. c #4D89F5",
+"f. c #83A4E4",
+"g. c #5881CC",
+"h. c #356ED7",
+"i. c #477DE0",
+"j. c #5685DC",
+"k. c #5D88DA",
+"l. c #5E89D8",
+"m. c #4676CF",
+"n. c #4774C7",
+" . . ",
+" + @ # $ % & * ",
+" = - ; > , ' ) ! ~ { ",
+" ] ^ / ( / _ : < [ } | 1 ",
+" 2 3 4 5 6 7 8 9 0 a b c d ",
+" e f g h i j k l m n o p q r ",
+" s t u v w x y l l i z A B C ",
+" D E _ : F G H l l l I J K L M ",
+" N O : P G Q l R S T U K V W X ",
+" s Y Z G Q l ` ...+.@.#.$.%. ",
+" &.*.=.-.l ` ;.>.,.k '.).!.~. ",
+" {.].^./.(._.:.<.[.}.|.1.2. ",
+" 3.4.5.6.7.8.K 9.).|.0.a. ",
+" b.c.d.e.K V $.f.1.g. ",
+" h.i.j.k.l.m.n. ",
+" "};
+
+
+static const char * sortDescendingXpm[] = {
+"16 16 145 2",
+" c None",
+". c #3D73D6",
+"+ c #467DE3",
+"@ c #608EE4",
+"# c #6290E5",
+"$ c #4075DA",
+"% c #3F75DA",
+"& c #477DE1",
+"* c #87A9E8",
+"= c #9DBAEC",
+"- c #C3D3F1",
+"; c #CFDCF3",
+"> c #B6CCF3",
+", c #A9C2F2",
+"' c #4E83E7",
+") c #4378DA",
+"! c #3C74DC",
+"~ c #4E82E3",
+"{ c #84A6E5",
+"] c #9CB7EA",
+"^ c #A8C1EC",
+"/ c #BED0EF",
+"( c #CDDAF4",
+"_ c #DBE5F6",
+": c #E0E8F7",
+"< c #D5E0F6",
+"[ c #6B94E1",
+"} c #487AD7",
+"| c #3875E7",
+"1 c #5F90EA",
+"2 c #B9CDF2",
+"3 c #D1DEF7",
+"4 c #8FB0ED",
+"5 c #A4BEED",
+"6 c #D1DDF5",
+"7 c #C5D6F6",
+"8 c #CADAF7",
+"9 c #D7E2F6",
+"0 c #4F84E6",
+"a c #356ED7",
+"b c #4482F6",
+"c c #669BFB",
+"d c #E4EDFE",
+"e c #FEFEFE",
+"f c #E5EDFB",
+"g c #A7C0ED",
+"h c #E7EDF9",
+"i c #FBFCFE",
+"j c #C3D5F6",
+"k c #E3EAF8",
+"l c #B4C9EF",
+"m c #4276D5",
+"n c #477DE0",
+"o c #4D89F5",
+"p c #5C95FC",
+"q c #A6C6FE",
+"r c #EBF2FE",
+"s c #DAE5F8",
+"t c #F8FAFE",
+"u c #AEC7F5",
+"v c #BFD1F2",
+"w c #5284E0",
+"x c #5685DC",
+"y c #6696ED",
+"z c #518CF7",
+"A c #699DFD",
+"B c #A8C7FE",
+"C c #EEF3FC",
+"D c #E2EBFB",
+"E c #FDFEFE",
+"F c #C1D4F5",
+"G c #D5E1F5",
+"H c #6C95E0",
+"I c #3368C9",
+"J c #5D88DA",
+"K c #779FE7",
+"L c #4F8BF8",
+"M c #669CFE",
+"N c #A6C5FE",
+"O c #EFF5FE",
+"P c #BBCFF4",
+"Q c #C9D7F2",
+"R c #6A93DF",
+"S c #5E89D8",
+"T c #7EA2E4",
+"U c #779FE8",
+"V c #739FEF",
+"W c #8CB4FD",
+"X c #B6CFFE",
+"Y c #DBE8FE",
+"Z c #F7F9FD",
+"` c #9BB8F0",
+" . c #94B5F0",
+".. c #A3BCEA",
+"+. c #5585DF",
+"@. c #4676CF",
+"#. c #83A4E4",
+"$. c #89AAE7",
+"%. c #D0DEF6",
+"&. c #FCFDFE",
+"*. c #FDFDFE",
+"=. c #FAFCFE",
+"-. c #86B0FD",
+";. c #4485FB",
+">. c #6A97EB",
+",. c #3F72D2",
+"'. c #4774C7",
+"). c #658DD8",
+"!. c #88A8E5",
+"~. c #BBCEF1",
+"{. c #D6E2F7",
+"]. c #DAE5F9",
+"^. c #C8DAFA",
+"/. c #BFD6FD",
+"(. c #CDDFFE",
+"_. c #A5C5FE",
+":. c #639AFE",
+"<. c #3A7EFB",
+"[. c #3573E7",
+"}. c #356ACD",
+"|. c #5881CC",
+"1. c #7298DD",
+"2. c #83A7E9",
+"3. c #4F8BF7",
+"4. c #508EFD",
+"5. c #4285FE",
+"6. c #3B7FFB",
+"7. c #3777ED",
+"8. c #376FD5",
+"9. c #5880CB",
+"0. c #83A4E3",
+"a. c #4C88F5",
+"b. c #4281F7",
+"c. c #3574E8",
+"d. c #386FD4",
+"e. c #4973C2",
+"f. c #4675CE",
+"g. c #5E88D7",
+"h. c #5C88D9",
+"i. c #5584DC",
+"j. c #477CDF",
+"k. c #366DD3",
+"l. c #376AC8",
+"m. c #3B67BA",
+"n. c #3A67BB",
+" ",
+" . + @ # + $ ",
+" % & * = - ; > , ' ) ",
+" ! ~ { ] ^ / ( _ : < [ } ",
+" | 1 2 3 4 5 / 6 7 8 9 0 ",
+" a b c d e f 4 g h i j k l m ",
+" n o p q r e f 4 s t u 9 v w ",
+" x y z A B r e C D E F ( G H I ",
+" J K y L M N O e e e P / Q R I ",
+" S T U V W X Y e e Z ` ...+. ",
+" @.#.$.%.E &.*.e i =.-.;.>.,. ",
+" '.).!.~.{.].^./.(._.:.<.[.}. ",
+" |.1.!.$.2.y 3.4.5.6.7.8. ",
+" 9.).0.T K y a.b.c.d. ",
+" e.f.g.h.i.j.k.l. ",
+" m.n. "};
+
+class SortOptionListItem : public KListViewItem
+{
+public:
+ SortOptionListItem(QListView* parent, QListViewItem* after, const QString& txt, int direction);
+ int direction(void) const;
+
+public slots:
+ void toggleDirection(void);
+
+private:
+ void setPixmap(void);
+
+private:
+ int m_direction;
+};
+
+SortOptionListItem::SortOptionListItem(QListView* parent, QListViewItem* after, const QString& txt, int direction) :
+ KListViewItem(parent, after, txt)
+{
+ m_direction = (direction >= 0) ? 1 : -1;
+ setPixmap();
+}
+
+void SortOptionListItem::setPixmap(void)
+{
+ if(m_direction > 0)
+ KListViewItem::setPixmap(0, QPixmap(&sortAscendingXpm[0]));
+ else
+ KListViewItem::setPixmap(0, QPixmap(&sortDescendingXpm[0]));
+}
+
+void SortOptionListItem::toggleDirection(void)
+{
+ m_direction *= (-1);
+ setPixmap();
+}
+
+int SortOptionListItem::direction(void) const
+{
+ return m_direction;
+}
+
diff --git a/kmymoney2/widgets/stdtransactiondownloaded.cpp b/kmymoney2/widgets/stdtransactiondownloaded.cpp
new file mode 100644
index 0000000..1305252
--- /dev/null
+++ b/kmymoney2/widgets/stdtransactiondownloaded.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ stdtransactiondownloaded.cpp
+ -------------------
+ begin : Sun May 11 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <stdtransactiondownloaded.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/register.h>
+
+using namespace KMyMoneyRegister;
+using namespace KMyMoneyTransactionForm;
+
+StdTransactionDownloaded::StdTransactionDownloaded(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ StdTransaction(parent, transaction, split, uniqueId)
+{
+}
+
+bool StdTransactionDownloaded::paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush)
+
+{
+ bool rc = Transaction::paintRegisterCellSetup(painter, row, col, cellRect, textRect, cg, brush);
+ // if not selected paint in selected background color
+ if(!isSelected()) {
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::importedTransactionColor());
+ brush = QBrush(cg.base());
+ }
+ return rc;
+}
+
+InvestTransactionDownloaded::InvestTransactionDownloaded(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ InvestTransaction(parent, transaction, split, uniqueId)
+{
+}
+
+bool InvestTransactionDownloaded::paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush)
+
+{
+ bool rc = Transaction::paintRegisterCellSetup(painter, row, col, cellRect, textRect, cg, brush);
+ // if not selected paint in selected background color
+ if(!isSelected()) {
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::importedTransactionColor());
+ brush = QBrush(cg.base());
+ }
+ return rc;
+}
+
diff --git a/kmymoney2/widgets/stdtransactiondownloaded.h b/kmymoney2/widgets/stdtransactiondownloaded.h
new file mode 100644
index 0000000..705fb04
--- /dev/null
+++ b/kmymoney2/widgets/stdtransactiondownloaded.h
@@ -0,0 +1,130 @@
+/***************************************************************************
+ stdtransactiondownloaded.h
+ -------------------
+ begin : Sun May 11 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef STDTRANSACTIONDOWNLOADED_H
+#define STDTRANSACTIONDOWNLOADED_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transaction.h>
+
+namespace KMyMoneyTransactionForm {
+ class TransactionForm;
+}; // namespace
+
+namespace KMyMoneyRegister {
+
+class StdTransactionDownloaded : public StdTransaction
+{
+public:
+ StdTransactionDownloaded(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~StdTransactionDownloaded() {}
+
+ virtual const char* className(void) { return "StdTransactionDownloaded"; }
+
+ /**
+ * This method sets the general paramaters required for the painting of a cell
+ * in the register. These are:
+ *
+ * - background color (alternating)
+ * - background color (imported transaction)
+ * - background color (matched transaction)
+ * - background color (selected transaction)
+ * - cellRect (area covering the cell)
+ * - textRect (area covering the text)
+ * - color of the pen to do the painting of text and lines
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param cellRect ref to QRect object receiving the area information for the cell
+ * @param textRect ref to QRect object receiving the area information for the text
+ * @param cg ref to QColorGroup object receiving the color information to be used
+ * @param brush ref to QBrush object receiveing the brush information to be used
+ */
+ virtual bool paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush);
+
+#if 0
+ virtual void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+
+ bool formCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+ void registerCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+
+ int numColsForm(void) const { return 4; }
+
+ void arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets);
+ void arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets);
+ void tabOrderInForm(QWidgetList& tabOrderWidgets) const;
+ void tabOrderInRegister(QWidgetList& tabOrderWidgets) const;
+
+ int numRowsRegister(bool expanded) const;
+#endif
+
+ /**
+ * Provided for internal reasons. No API change. See RegisterItem::numRowsRegister()
+ */
+ int numRowsRegister(void) const { return StdTransaction::numRowsRegister(); }
+};
+
+class InvestTransactionDownloaded : public InvestTransaction
+{
+ public:
+ InvestTransactionDownloaded(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~InvestTransactionDownloaded() {}
+
+ virtual const char* className(void) { return "InvestTransactionDownloaded"; }
+
+ /**
+ * This method sets the general paramaters required for the painting of a cell
+ * in the register. These are:
+ *
+ * - background color (alternating)
+ * - background color (imported transaction)
+ * - background color (matched transaction)
+ * - background color (selected transaction)
+ * - cellRect (area covering the cell)
+ * - textRect (area covering the text)
+ * - color of the pen to do the painting of text and lines
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param cellRect ref to QRect object receiving the area information for the cell
+ * @param textRect ref to QRect object receiving the area information for the text
+ * @param cg ref to QColorGroup object receiving the color information to be used
+ * @param brush ref to QBrush object receiveing the brush information to be used
+ */
+ virtual bool paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush);
+ /**
+ * Provided for internal reasons. No API change. See RegisterItem::numRowsRegister()
+ */
+ int numRowsRegister(void) const { return InvestTransaction::numRowsRegister(); }
+};
+
+
+}; // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
+
diff --git a/kmymoney2/widgets/stdtransactionmatched.cpp b/kmymoney2/widgets/stdtransactionmatched.cpp
new file mode 100644
index 0000000..9bc191b
--- /dev/null
+++ b/kmymoney2/widgets/stdtransactionmatched.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+ stdtransactionmatched.cpp
+ -------------------
+ begin : Sat May 11 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qregion.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <stdtransactionmatched.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+#include <kmymoney/register.h>
+
+using namespace KMyMoneyRegister;
+using namespace KMyMoneyTransactionForm;
+
+StdTransactionMatched::StdTransactionMatched(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ StdTransaction(parent, transaction, split, uniqueId),
+ m_drawCounter(parent->drawCounter()-1)
+{
+ // setup initial size
+ setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed()));
+}
+
+bool StdTransactionMatched::paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush)
+{
+ QRect r(cellRect);
+
+ bool rc = Transaction::paintRegisterCellSetup(painter, row, col, cellRect, textRect, cg, brush);
+
+ // if not selected paint in matched background color
+ if(!isSelected()) {
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::matchedTransactionColor());
+ brush = QBrush(cg.base());
+ }
+
+ // the first line needs to be painted across all columns
+ if(row + m_additionalRows - m_rowsRegister == 0) {
+ // avoid painting the text over multiple columns twice for the same update round
+ unsigned int drawCounter = m_parent->drawCounter();
+ if(m_drawCounter == drawCounter) {
+ return false;
+ }
+
+
+ // the fixed text always uses all cols
+ col = m_parent->columnAt(1);
+ painter->translate(-r.x() + m_parent->columnPos(col), 0);
+#if 0
+ r.setX(m_parent->columnPos(col));
+ r.setWidth(m_parent->visibleWidth());
+ painter->translate(r.x(), r.y());
+#endif
+ cellRect.setX(0);
+ cellRect.setY(0);
+ cellRect.setWidth(m_parent->visibleWidth());
+ cellRect.setHeight(m_parent->rowHeight(row + m_startRow));
+
+ textRect = cellRect;
+ textRect.setX(2);
+ textRect.setWidth(textRect.width()-4);
+ }
+ return rc;
+}
+
+void StdTransactionMatched::registerCellText(QString& txt, int& align, int row, int col, QPainter* painter)
+{
+ // run through the standard
+ StdTransaction::registerCellText(txt, align, row, col, painter);
+
+ // we only cover the additional rows
+ if(row >= m_rowsRegister - m_additionalRows) {
+ // make row relative to the last three rows
+ row += m_additionalRows - m_rowsRegister;
+
+ // remove anything that had been added by the standard method
+ txt = "";
+
+ // and we draw this information in italics
+ if(painter) {
+ QFont font = painter->font();
+ font.setItalic(true);
+ painter->setFont(font);
+ }
+
+ MyMoneyTransaction matchedTransaction = m_split.matchedTransaction();
+ MyMoneySplit matchedSplit;
+ try {
+ matchedSplit = matchedTransaction.splitById(m_split.value("kmm-match-split"));
+ } catch(MyMoneyException *e) {
+ delete e;
+ }
+
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ const QValueList<MyMoneySplit>& list = matchedTransaction.splits();
+ MyMoneyMoney importedValue;
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ if((*it_s).accountId() == m_account.id()) {
+ importedValue += (*it_s).shares();
+ }
+ }
+
+ QDate postDate;
+ QString memo;
+ switch(row) {
+ case 0:
+ if(painter)
+ txt = QString(" ")+i18n("KMyMoney has matched a downloaded transaction with a manually entered one (result above)");
+ // return true for the first visible column only
+ break;
+
+ case 1:
+ switch(col) {
+ case DateColumn:
+ align |= Qt::AlignLeft;
+ txt = i18n("Bank entry:");
+ break;
+
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ txt = QString("%1 %2").arg(matchedTransaction.postDate().toString(Qt::ISODate)).arg(matchedTransaction.memo());
+ break;
+
+ case PaymentColumn:
+ align |= Qt::AlignRight;
+ if(importedValue.isNegative()) {
+ txt = (-importedValue).formatMoney(m_account.fraction());
+ }
+ break;
+
+ case DepositColumn:
+ align |= Qt::AlignRight;
+ if(!importedValue.isNegative()) {
+ txt = importedValue.formatMoney(m_account.fraction());
+ }
+ break;
+ }
+ break;
+
+ case 2:
+ switch(col) {
+ case DateColumn:
+ align |= Qt::AlignLeft;
+ txt = i18n("Your entry:");
+ break;
+
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ postDate = m_transaction.postDate();
+ if(!m_split.value("kmm-orig-postdate").isEmpty()) {
+ postDate = QDate::fromString(m_split.value("kmm-orig-postdate"), Qt::ISODate);
+ }
+ memo = m_split.memo();
+ if(!matchedSplit.memo().isEmpty() && memo != matchedSplit.memo()) {
+ int pos = memo.findRev(matchedSplit.memo());
+ if(pos != -1) {
+ memo = memo.left(pos);
+ if(memo.endsWith("\n"))
+ memo = memo.left(pos-1);
+ }
+ }
+ txt = QString("%1 %2").arg(postDate.toString(Qt::ISODate)).arg(memo);
+ break;
+
+ case PaymentColumn:
+ align |= Qt::AlignRight;
+ if(m_split.value().isNegative()) {
+ txt = (-m_split.value(m_transaction.commodity(), m_splitCurrencyId)).formatMoney(m_account.fraction());
+ }
+ break;
+
+ case DepositColumn:
+ align |= Qt::AlignRight;
+ if(!m_split.value().isNegative()) {
+ txt = m_split.value(m_transaction.commodity(), m_splitCurrencyId).formatMoney(m_account.fraction());
+ }
+ break;
+
+ }
+ break;
+ }
+ }
+}
+
+void StdTransactionMatched::paintRegisterGrid(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& _cg) const
+{
+ // the last 3 rows should not show a grid
+ if(row < m_rowsRegister - m_additionalRows) {
+ Transaction::paintRegisterGrid(painter, row, col, r, _cg);
+
+ } else if(row == m_rowsRegister-1) {
+ painter->setPen(KMyMoneyGlobalSettings::listGridColor());
+ painter->drawLine(r.x(), r.height()-1, r.width(), r.height()-1);
+ }
+}
diff --git a/kmymoney2/widgets/stdtransactionmatched.h b/kmymoney2/widgets/stdtransactionmatched.h
new file mode 100644
index 0000000..599e6e0
--- /dev/null
+++ b/kmymoney2/widgets/stdtransactionmatched.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ stdtransactionmatched.h
+ -------------------
+ begin : Sat May 31 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef STDTRANSACTIONMATCHED_H
+#define STDTRANSACTIONMATCHED_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+#include <qbrush.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transaction.h>
+
+namespace KMyMoneyTransactionForm {
+ class TransactionForm;
+}; // namespace
+
+namespace KMyMoneyRegister {
+
+class StdTransactionMatched : public StdTransaction
+{
+ static const int m_additionalRows = 3;
+
+public:
+ StdTransactionMatched(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~StdTransactionMatched() {}
+
+ virtual const char* className(void) { return "StdTransactionMatched"; }
+
+ /**
+ * This method sets the general paramaters required for the painting of a cell
+ * in the register. These are:
+ *
+ * - background color (alternating)
+ * - background color (imported transaction)
+ * - background color (matched transaction)
+ * - background color (selected transaction)
+ * - cellRect (area covering the cell)
+ * - textRect (area covering the text)
+ * - color of the pen to do the painting of text and lines
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param cellRect ref to QRect object receiving the area information for the cell
+ * @param textRect ref to QRect object receiving the area information for the text
+ * @param cg ref to QColorGroup object receiving the color information to be used
+ * @param brush ref to QBrush object receiveing the brush information to be used
+ */
+ virtual bool paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush);
+
+ virtual void paintRegisterGrid(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg) const;
+
+#if 0
+ virtual void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+
+ bool formCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+
+ int numColsForm(void) const { return 4; }
+
+ void arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets);
+ void arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets);
+ void tabOrderInForm(QWidgetList& tabOrderWidgets) const;
+ void tabOrderInRegister(QWidgetList& tabOrderWidgets) const;
+
+ int numRowsRegister(bool expanded) const;
+#endif
+
+ void registerCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+
+ /**
+ * Provided for internal reasons. No API change. See RegisterItem::numRowsRegister(bool)
+ */
+ int numRowsRegister(bool expanded) const { return StdTransaction::numRowsRegister(expanded) + m_additionalRows; }
+
+private:
+ unsigned int m_drawCounter;
+};
+
+}; // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
+
diff --git a/kmymoney2/widgets/transaction.cpp b/kmymoney2/widgets/transaction.cpp
new file mode 100644
index 0000000..4c8a23b
--- /dev/null
+++ b/kmymoney2/widgets/transaction.cpp
@@ -0,0 +1,2189 @@
+/***************************************************************************
+ transaction.cpp - description
+ -------------------
+ begin : Tue Jun 13 2006
+ copyright : (C) 2000-2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qpainter.h>
+#include <qwidgetlist.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transaction.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/register.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/transactionform.h>
+#include <kmymoney/kmymoneylineedit.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/transactioneditor.h>
+#include <kmymoney/investtransactioneditor.h>
+#include <kmymoney/kmymoneyutils.h>
+
+#include "../kmymoneyglobalsettings.h"
+
+using namespace KMyMoneyRegister;
+using namespace KMyMoneyTransactionForm;
+
+static unsigned char attentionSign[] = {
+ 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,
+ 0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,
+ 0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x14,
+ 0x08,0x06,0x00,0x00,0x00,0x8D,0x89,0x1D,
+ 0x0D,0x00,0x00,0x00,0x04,0x73,0x42,0x49,
+ 0x54,0x08,0x08,0x08,0x08,0x7C,0x08,0x64,
+ 0x88,0x00,0x00,0x00,0x19,0x74,0x45,0x58,
+ 0x74,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,
+ 0x65,0x00,0x77,0x77,0x77,0x2E,0x69,0x6E,
+ 0x6B,0x73,0x63,0x61,0x70,0x65,0x2E,0x6F,
+ 0x72,0x67,0x9B,0xEE,0x3C,0x1A,0x00,0x00,
+ 0x02,0x05,0x49,0x44,0x41,0x54,0x38,0x8D,
+ 0xAD,0x95,0xBF,0x4B,0x5B,0x51,0x14,0xC7,
+ 0x3F,0x2F,0xBC,0x97,0x97,0x97,0x97,0x77,
+ 0xF3,0xF2,0x1C,0xA4,0x54,0x6B,0x70,0x10,
+ 0x44,0x70,0x2A,0x91,0x2E,0x52,0x02,0x55,
+ 0x8A,0xB5,0xA3,0xAB,0x38,0x08,0x66,0xCC,
+ 0xEE,0xE0,0xE2,0x20,0xB8,0x38,0xB8,0xB8,
+ 0xF8,0x1F,0x38,0x29,0xA5,0x29,0x74,0x90,
+ 0x0E,0x0D,0x0E,0x22,0x1D,0x44,0xA8,0xD0,
+ 0xD4,0xB4,0x58,0x4B,0x09,0xF9,0xF1,0x4A,
+ 0x3B,0xD4,0xD3,0xE1,0x55,0xD3,0x34,0xAF,
+ 0x49,0x6C,0x3D,0xF0,0x85,0x7B,0xCF,0xFD,
+ 0x9E,0xEF,0x3D,0xE7,0xFE,0xD4,0x44,0x84,
+ 0xDB,0xB4,0x48,0x2F,0xA4,0x94,0xAB,0xE5,
+ 0x52,0xAE,0x96,0xEB,0x49,0x51,0x44,0x3A,
+ 0x02,0x18,0x88,0xC7,0xF1,0xE3,0x71,0x7C,
+ 0x60,0xA0,0x1B,0xBF,0x6B,0x86,0x49,0xC5,
+ 0x46,0x3E,0x47,0x34,0x9F,0x23,0x9A,0x54,
+ 0x6C,0xFC,0x57,0x86,0x40,0xC6,0x4B,0xE1,
+ 0x37,0xCA,0x48,0xA3,0x8C,0x78,0x29,0x7C,
+ 0x20,0xD3,0x31,0xA6,0xD3,0xA0,0x52,0x1C,
+ 0x6D,0x6F,0x72,0xD9,0x28,0x23,0xFE,0x07,
+ 0x64,0x7B,0x93,0x4B,0xA5,0x38,0xFA,0x27,
+ 0x41,0x60,0x6E,0x74,0x84,0x7A,0xE5,0x1D,
+ 0x92,0x54,0x88,0xE7,0x22,0xD5,0x12,0x32,
+ 0x3A,0x42,0x1D,0x98,0xBB,0x91,0x20,0x60,
+ 0xDA,0x36,0x17,0xFB,0x7B,0xC8,0xC1,0x4B,
+ 0x04,0x02,0xBC,0x7E,0x81,0xEC,0xEF,0x21,
+ 0xB6,0xCD,0x05,0x60,0xF6,0x2C,0x68,0x9A,
+ 0x2C,0xCF,0x4C,0xE1,0x4B,0x05,0x39,0x3F,
+ 0x69,0x0A,0xBE,0x7F,0x83,0x48,0x05,0x99,
+ 0x99,0xC2,0x37,0x4D,0x96,0x7B,0x12,0x04,
+ 0xFA,0x2D,0x8B,0xC6,0xE9,0x61,0x10,0x2C,
+ 0x15,0xC4,0x8A,0x21,0x86,0x8E,0xFC,0xF8,
+ 0x12,0xF4,0x4F,0x0F,0x11,0xCB,0xA2,0x01,
+ 0xF4,0x77,0x3D,0x36,0x4E,0x82,0xF5,0xA5,
+ 0x05,0x8C,0xE1,0x74,0xD3,0x37,0x34,0x18,
+ 0x20,0xF2,0x8B,0x3D,0x9C,0x86,0xA5,0x05,
+ 0x0C,0x27,0xC1,0x7A,0xC7,0x63,0x03,0x8C,
+ 0x2B,0x07,0xBF,0x5A,0x6A,0x66,0x27,0x15,
+ 0x64,0x3A,0x8B,0x3C,0x7A,0xD8,0xEA,0xAB,
+ 0x96,0x10,0xE5,0xE0,0x03,0xE3,0x7F,0xCD,
+ 0x50,0x39,0x6C,0xAD,0xAD,0x10,0x53,0xAA,
+ 0x75,0xD2,0xF4,0xBD,0x00,0x2D,0x5C,0x05,
+ 0x6B,0x2B,0xC4,0x94,0xC3,0xD6,0xEF,0xFE,
+ 0x6B,0x41,0x4D,0xD3,0x66,0xFB,0x3C,0xC6,
+ 0x16,0xE7,0xDB,0x97,0x61,0xE2,0x3E,0x3C,
+ 0xC8,0xB4,0x15,0xC7,0xE2,0x3C,0x91,0x3E,
+ 0x8F,0x31,0x4D,0xD3,0x66,0x5B,0x4A,0x06,
+ 0x8C,0x84,0xCD,0x59,0x61,0xA7,0xB5,0xAC,
+ 0x2B,0x9C,0x1C,0x04,0x08,0x1B,0x2B,0xEC,
+ 0x20,0x09,0x9B,0x33,0xC0,0xB8,0xDE,0x65,
+ 0x43,0x27,0x9F,0x9D,0xA4,0x1E,0x16,0xF0,
+ 0xF9,0x6D,0xB0,0xC3,0x86,0x1E,0xB4,0xC3,
+ 0x38,0xD9,0x49,0xEA,0x86,0x4E,0xFE,0xEA,
+ 0x29,0xF4,0x2C,0x8B,0xDA,0x71,0x31,0x9C,
+ 0xFC,0xF5,0x23,0x32,0x34,0x88,0xDC,0xBD,
+ 0x13,0x5C,0xBF,0x30,0xCE,0x71,0x11,0xB1,
+ 0x2C,0x6A,0x80,0xA7,0xDB,0x36,0xAB,0x4F,
+ 0xA6,0x89,0xBA,0x49,0x38,0xFF,0xD4,0xBE,
+ 0x4E,0x00,0xAF,0x9E,0x81,0x08,0xD4,0xEA,
+ 0x01,0xFE,0x34,0x37,0x09,0x4F,0x1F,0x13,
+ 0xDD,0x7D,0xCE,0xAA,0x96,0x72,0x29,0x7C,
+ 0xFB,0xCE,0x44,0xB8,0xD4,0xCD,0x2C,0x66,
+ 0x52,0xD4,0x6E,0xFB,0x0B,0xF8,0x09,0x63,
+ 0x63,0x31,0xE4,0x85,0x76,0x2E,0x0E,0x00,
+ 0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,
+ 0x42,0x60,0x82
+};
+
+Transaction::Transaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ RegisterItem(parent),
+ m_transaction(transaction),
+ m_split(split),
+ m_form(0),
+ m_uniqueId(m_transaction.id()),
+ m_formRowHeight(-1),
+ m_selected(false),
+ m_focus(false),
+ m_erronous(false),
+ m_inEdit(false),
+ m_inRegisterEdit(false),
+ m_showBalance(true),
+ m_reducedIntensity(false)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ // load the account
+ if(!m_split.accountId().isEmpty())
+ m_account = file->account(m_split.accountId());
+
+ // load the payee
+ if(!m_split.payeeId().isEmpty()) {
+ m_payee = file->payee(m_split.payeeId()).name();
+ }
+ if(parent->account().isIncomeExpense()) {
+ m_payeeHeader = m_split.shares().isNegative() ? i18n("From") : i18n("Pay to");
+ } else {
+ m_payeeHeader = m_split.shares().isNegative() ? i18n("Pay to") : i18n("From");
+ }
+
+ // load the currency
+ if(!m_transaction.id().isEmpty())
+ m_splitCurrencyId = m_account.currencyId();
+
+ // check if transaction is errnous or not
+ m_erronous = !m_transaction.splitSum().isZero();
+
+ if(!m_uniqueId.isEmpty()) {
+ m_uniqueId += "-";
+ QString id;
+ id.setNum(uniqueId);
+ m_uniqueId += id.rightJustify(3, '0');
+ }
+}
+
+void Transaction::setFocus(bool focus, bool updateLens)
+{
+ if(focus != m_focus) {
+ m_focus = focus;
+ }
+ if(updateLens) {
+ if(KMyMoneyGlobalSettings::ledgerLens()
+ || !KMyMoneyGlobalSettings::transactionForm()
+ || KMyMoneyGlobalSettings::showRegisterDetailed()
+ || m_parent->m_ledgerLensForced) {
+ if(focus)
+ setNumRowsRegister(numRowsRegister(true));
+ else
+ setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed()));
+ }
+ }
+}
+
+void Transaction::markAttachment(QPainter* painter, int /* row */, int /* col */, const QRect& r)
+{
+ static QPixmap clip;
+
+ const int m = 2; // margin
+ int h = m_parent->rowHeightHint() - (2*m);
+ int lx = r.topRight().x() - h;
+ if(isErronous())
+ lx -= h;
+ QRect cr(QPoint(lx - m, m), QSize(h, h));
+
+ painter->save();
+ if(clip.isNull()) {
+ clip = KGlobal::iconLoader()->loadIcon("attach", KIcon::Small, KIcon::SizeSmall, KIcon::DefaultState);
+ if(clip.height() > h) {
+ clip.resize(h, h);
+ }
+ }
+
+ painter->drawPixmap(QPoint(lx - m, m + (h - clip.height())/2 ), clip);
+ painter->restore();
+}
+
+void Transaction::markAsErronous(QPainter* painter, int /* row */, int /* col */, const QRect& r)
+{
+ const int m = 2; // margin
+ int h = m_parent->rowHeightHint() - (2*m);
+ QRect cr(QPoint(r.topRight().x() - h - m, m), QSize(h, h));
+
+ painter->save();
+ QPixmap attention;
+ attention.loadFromData(attentionSign, sizeof(attentionSign), 0, 0);
+
+ if(attention.height() > h) {
+ attention.resize(h, h);
+ }
+ painter->drawPixmap(QPoint(r.topRight().x() - h - m, m + (h - attention.height())/2 ), attention);
+ painter->restore();
+
+}
+
+bool Transaction::paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush)
+{
+ if(m_reducedIntensity)
+ cg = m_parent->palette().disabled();
+
+ if(m_alternate)
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listColor());
+ else
+ cg.setColor(QColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
+
+ cellRect.setX(0);
+ cellRect.setY(0);
+ cellRect.setWidth(m_parent->columnWidth(col));
+ cellRect.setHeight(m_parent->rowHeight(m_startRow + row));
+
+ textRect = cellRect;
+ textRect.setX(2);
+ textRect.setWidth(textRect.width()-4);
+
+ if(m_selected) {
+ brush = QBrush(cg.highlight());
+ painter->setPen(cg.highlightedText());
+ } else {
+ brush = QBrush(cg.base());
+ painter->setPen(cg.text());
+ }
+
+ // do we need to switch to the error color?
+ if(m_erronous && m_parent->markErronousTransactions()) {
+ painter->setPen(KMyMoneyGlobalSettings::listErronousTransactionColor());
+ }
+
+ // do we need to switch to the negative balance color?
+ if(col == BalanceColumn) {
+ bool showNegative = m_balance.isNegative();
+ if(m_account.accountGroup() == MyMoneyAccount::Liability && !m_balance.isZero() )
+ showNegative = !showNegative;
+ if(showNegative)
+ painter->setPen(KMyMoneyGlobalSettings::listNegativeValueColor());
+ }
+ return true;
+}
+
+void Transaction::paintRegisterCellFocus(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg)
+{
+
+ if(m_focus) {
+ QPen oldPen = painter->pen();
+ QPen newPen = oldPen;
+ newPen.setWidth(0);
+
+ painter->setFont(KMyMoneyGlobalSettings::listCellFont());
+ painter->setPen(newPen);
+ painter->setPen(cg.foreground());
+ painter->setPen(Qt::DotLine);
+ // for the first Row, we need to paint the top
+ QPoint start, end;
+#if 0
+ if(row == 0) {
+ start = QPoint(r.x(), r.y() + 1);
+ end = QPoint(r.x() + r.width(), r.y() + 1);
+ if(col == 0) {
+ start.rx()++;
+ } else if(col == m_parent->lastCol()) {
+ end.rx()--;
+ }
+ // painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ // for the last Row, we need to paint the bottom
+ if(row == numRows() - 1) {
+ start = QPoint(r.x(), r.y() + r.height() - 1);
+ end = QPoint(r.x() + r.width(), r.y() + r.height() - 1);
+ if(col == 0) {
+ start.rx()++;
+ } else if(col == m_parent->lastCol()) {
+ end.rx()--;
+ }
+ // painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ // for the first col, we need to paint the left
+ if(col == 0) {
+ start = QPoint(r.x() + 1, r.y());
+ end = QPoint(r.x() + 1, r.y() + r.height());
+ if(row == 0) {
+ start.ry()++;
+ } else if(row == numRows()-1) {
+ end.ry()--;
+ }
+ //painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ // for the last col, we need to paint the left
+ if(col == m_parent->lastCol()) {
+ start = QPoint(r.x() + r.width() - 1, r.y());
+ end = QPoint(r.x() + r.width() - 1, r.y() + r.height());
+ if(row == 0) {
+ start.ry()++;
+ } else if(row == numRows()-1) {
+ end.ry()--;
+ }
+ //painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+#endif
+ if(row == 0) {
+ start = QPoint(r.x(), r.y());
+ end = QPoint(r.x() + r.width(), r.y() + 1);
+ if(col == 0) {
+ start.rx()++;
+ } else if(col == m_parent->lastCol()) {
+ end.rx()--;
+ }
+ // painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ // for the last Row, we need to paint the bottom
+ if(row == numRowsRegister() - 1) {
+ start = QPoint(r.x(), r.y() + r.height() - 2);
+ end = QPoint(r.x() + r.width(), r.y() + r.height() - 2);
+ if(col == 0) {
+ start.rx()++;
+ } else if(col == m_parent->lastCol()) {
+ end.rx()--;
+ }
+ // painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ // for the first col, we need to paint the left
+ if(col == 0) {
+ start = QPoint(r.x() + 1, r.y());
+ end = QPoint(r.x() + 1, r.y() + r.height());
+ if(row == 0) {
+ start.ry()++;
+ } else if(row == numRowsRegister()-1) {
+ end.ry()--;
+ }
+ //painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ // for the last col, we need to paint the left
+ if(col == m_parent->lastCol()) {
+ start = QPoint(r.x() + r.width() - 1, r.y());
+ end = QPoint(r.x() + r.width() - 1, r.y() + r.height());
+ if(row == 0) {
+ start.ry()++;
+ } else if(row == numRowsRegister()-1) {
+ end.ry()--;
+ }
+ //painter->drawLine(start, end);
+ painter->drawWinFocusRect(QRect(start, end));
+ }
+ painter->setPen(oldPen);
+ }
+}
+
+void Transaction::registerCellText(QString& txt, int row, int col)
+{
+ int align = 0;
+ registerCellText(txt, align, row, col, 0);
+}
+
+void Transaction::paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool /* selected */, const QColorGroup& _cg)
+{
+ QColorGroup cg(_cg);
+ QRect cellRect(r);
+ QRect textRect;
+ QBrush backgroundBrush;
+
+ painter->save();
+
+ if(paintRegisterCellSetup(painter, row, col, cellRect, textRect, cg, backgroundBrush)) {
+ // construct the text for the cell
+ int align = Qt::AlignVCenter;
+ QString txt;
+ if(m_transaction != MyMoneyTransaction() && !m_inRegisterEdit) {
+ registerCellText(txt, align, row, col, painter);
+ }
+
+ paintRegisterCellBackground(painter, row, col, cellRect, backgroundBrush);
+
+ // and paint it
+ paintRegisterCellText(painter, row, col, textRect, cg, align, txt);
+
+ // paint the grid
+ paintRegisterGrid(painter, row, col, cellRect, cg);
+
+ // possible icons
+ paintRegisterIcons(painter, row, col, cellRect, cg);
+
+ // and the focus
+ paintRegisterCellFocus(painter, row, col, cellRect, cg);
+ }
+
+ painter->restore();
+}
+
+void Transaction::paintRegisterIcons(QPainter* painter, int row, int col, const QRect& /*r*/, const QColorGroup& /*cg*/)
+{
+ if(row == 0 && col == DetailColumn && painter) {
+ if(m_erronous || !m_transaction.value("kmm-attachment").isEmpty()) {
+ QRect cellRect;
+ cellRect.setX(0);
+ cellRect.setY(0);
+ cellRect.setWidth(m_parent->columnWidth(col));
+ cellRect.setHeight(m_parent->rowHeight(m_startRow + row));
+ if(m_erronous) {
+ markAsErronous(painter, row, col, cellRect);
+ }
+ if(!m_transaction.value("kmm-attachment").isEmpty()) {
+ markAttachment(painter, row, col, cellRect);
+ }
+ }
+ }
+}
+void Transaction::paintRegisterCellBackground(QPainter* painter, int row, int col, const QRect& r, const QBrush& backgroundBrush)
+{
+ Q_UNUSED(row);
+ Q_UNUSED(col);
+
+ // fill the background
+ painter->fillRect(r, backgroundBrush);
+}
+
+void Transaction::paintRegisterGrid(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& _cg) const
+{
+ Q_UNUSED(_cg);
+
+ // if a grid is selected, we paint it right away
+ if (KMyMoneyGlobalSettings::showGrid()) {
+ painter->setPen(KMyMoneyGlobalSettings::listGridColor());
+ if(col != 0)
+ painter->drawLine(r.x(), 0, r.x(), r.height()-1);
+ if(row == numRowsRegister()-1)
+ painter->drawLine(r.x(), r.height()-1, r.width(), r.height()-1);
+ }
+}
+
+void Transaction::paintRegisterCellText(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& _cg, int align, const QString& txt)
+{
+ Q_UNUSED(row);
+ Q_UNUSED(col);
+ Q_UNUSED(r);
+ Q_UNUSED(_cg);
+
+ // make sure, we clear the cell
+ if(txt.isEmpty())
+ painter->drawText(r, align, " ");
+ else
+ painter->drawText(r, align, txt);
+}
+
+int Transaction::formRowHeight(int /*row*/)
+{
+ if(m_formRowHeight < 0) {
+ m_formRowHeight = formRowHeight();
+ }
+ return m_formRowHeight;
+}
+
+int Transaction::formRowHeight(void) const
+{
+ if(m_formRowHeight < 0) {
+ // determine the height of the objects in the table
+ kMyMoneyDateInput dateInput;
+ KMyMoneyCategory category(0,0,true);
+
+ return QMAX(dateInput.sizeHint().height(), category.sizeHint().height());
+ }
+ return m_formRowHeight;
+}
+
+void Transaction::setupForm(TransactionForm* form)
+{
+ m_form = form;
+ form->verticalHeader()->setUpdatesEnabled(false);
+ form->horizontalHeader()->setUpdatesEnabled(false);
+
+ form->setNumRows(numRowsForm());
+ form->setNumCols(numColsForm());
+
+ // Force all cells to have some text (so that paintCell is called for each cell)
+ for(int r = 0; r < numRowsForm(); ++r) {
+ for(int c = 0; c < numColsForm(); ++c) {
+ form->setText(r, c, "x");
+ if(r == 0 && form->columnWidth(c) == 0) {
+ form->setColumnWidth(c, 10);
+ }
+ }
+ }
+ form->horizontalHeader()->setUpdatesEnabled(true);
+ form->verticalHeader()->setUpdatesEnabled(true);
+
+ loadTab(form);
+}
+
+void Transaction::paintFormCell(QPainter* painter, int row, int col, const QRect& /*r*/, bool /*selected*/, const QColorGroup& _cg)
+{
+ if(!m_form)
+ return;
+
+ QRect cellRect = m_form->cellRect(row, col);
+
+ QRect textRect(cellRect);
+ textRect.setX(1);
+ textRect.setY(1);
+ textRect.setWidth(textRect.width()-2);
+ textRect.setHeight(textRect.height()-2);
+
+ painter->fillRect(cellRect, _cg.background());
+ painter->setPen(_cg.text());
+
+ QString txt;
+ int align = Qt::AlignVCenter;
+ bool editField = formCellText(txt, align, row, col, painter);
+
+ // if we have an editable field and don't currently edit the transaction
+ // show the background in a different color
+ if(editField && !m_inEdit) {
+ painter->fillRect(textRect, _cg.base());
+ }
+
+ // make sure, we clear the cell
+ // in case of an editable field and edit mode, we just clear the field
+ if(txt.isEmpty() || (editField && m_inEdit))
+ painter->drawText(textRect, align, " ");
+ else
+ painter->drawText(textRect, align, txt);
+
+}
+
+void Transaction::setupPalette(const QPalette& palette, QMap<QString, QWidget*>& editWidgets)
+{
+ QMap<QString, QWidget*>::iterator it_w;
+ for(it_w = editWidgets.begin(); it_w != editWidgets.end(); ++it_w) {
+ if(*it_w) {
+ (*it_w)->setPalette(palette);
+ }
+ }
+}
+
+void Transaction::setupFormPalette(QMap<QString, QWidget*>& editWidgets)
+{
+ setupPalette(m_parent->palette(), editWidgets);
+}
+
+void Transaction::setupRegisterPalette(QMap<QString, QWidget*>& editWidgets)
+{
+ // make sure, we're using the right palette
+ QPalette palette = m_parent->palette();
+
+ // use the highlight color as background
+ palette.setColor(QPalette::Active, QColorGroup::Background, palette.color(QPalette::Active, QColorGroup::Highlight));
+
+ setupPalette(palette, editWidgets);
+}
+
+QWidget* Transaction::focusWidget(QWidget* w) const
+{
+ if(w) {
+ while(w->focusProxy())
+ w = w->focusProxy();
+ }
+ return w;
+}
+
+void Transaction::arrangeWidget(QTable* tbl, int row, int col, QWidget* w) const
+{
+ if(w) {
+ tbl->setCellWidget(row, col, w);
+ // remove the widget from the QTable's eventFilter so that all
+ // events will be directed to the edit widget
+ w->removeEventFilter(tbl);
+ } else
+ qDebug("No widget for %d,%d", row, col);
+}
+
+bool Transaction::haveNumberField(void) const
+{
+ bool rc = true;
+ switch(m_account.accountType()) {
+ case MyMoneyAccount::Savings:
+ case MyMoneyAccount::Cash:
+ case MyMoneyAccount::Loan:
+ case MyMoneyAccount::AssetLoan:
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Equity:
+ rc = KMyMoneyGlobalSettings::alwaysShowNrField();
+ break;
+
+ case MyMoneyAccount::Checkings:
+ case MyMoneyAccount::CreditCard:
+ // the next case is used for the editor when the account
+ // is unknown (eg. when creating new schedules)
+ case MyMoneyAccount::UnknownAccountType:
+ break;
+
+ default:
+ rc = false;
+ break;
+ }
+ return rc;
+}
+
+bool Transaction::maybeTip(const QPoint& cpos, int row, int col, QRect& r, QString& msg)
+{
+ if(col != DetailColumn)
+ return false;
+
+ if(!m_erronous && m_transaction.splitCount() < 3)
+ return false;
+
+ int h = m_parent->rowHeightHint();
+
+ // check for detail column in row 0 of the transaction for a possible exclamation mark
+ r = m_parent->cellGeometry(m_startRow + 0, col);
+ // qDebug("r is %d,%d,%d,%d", r.x(), r.y(), r.width(), r.height());
+ r.setBottomLeft(QPoint(r.x() + (r.width() - h), r.y() + h));
+ // qDebug("r is %d,%d,%d,%d", r.x(), r.y(), r.width(), r.height());
+ // qDebug("p is in r = %d", r.contains(cpos));
+ if(r.contains(cpos) && m_erronous) {
+ if(m_transaction.splits().count() < 2) {
+ msg = QString("<qt>%1</qt>").arg(i18n("Transaction is missing a category assignment."));
+ } else {
+ const MyMoneySecurity& sec = MyMoneyFile::instance()->security(m_account.currencyId());
+ msg = QString("<qt>%1</qt>").arg(i18n("The transaction has a missing assignment of <b>%1</b>.").arg(m_transaction.splitSum().abs().formatMoney(m_account, sec)));
+ }
+ return true;
+ }
+
+ // check for detail column in row 1 of the transaction for a possible exclamation mark
+ r = m_parent->cellGeometry(m_startRow + 1, col);
+ if(row == 1 && r.contains(cpos) && m_transaction.splitCount() > 2) {
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ QString txt;
+ const MyMoneySecurity& sec = file->security(m_transaction.commodity());
+ MyMoneyMoney factor(1, 1);
+ if(!m_split.value().isNegative())
+ factor = -factor;
+
+ for(it_s = m_transaction.splits().begin(); it_s != m_transaction.splits().end(); ++it_s) {
+ if(*it_s == m_split)
+ continue;
+ const MyMoneyAccount& acc = file->account((*it_s).accountId());
+ QString category = file->accountToCategory(acc.id());
+ QString amount = ((*it_s).value() * factor).formatMoney(acc, sec);
+
+ txt += QString("<tr><td><nobr>%1</nobr></td><td align=right><nobr>%2</nobr></td></tr>").arg(category, amount);
+ }
+ msg = QString("<table>%1</table>").arg(txt);
+ return true;
+ }
+
+ return false;
+}
+
+QString Transaction::reconcileState(bool text) const
+{
+ QString txt = KMyMoneyUtils::reconcileStateToString(m_split.reconcileFlag(), text);
+
+ if((text == true)
+ && (txt == i18n("Unknown"))
+ && (m_transaction == MyMoneyTransaction()))
+ txt = QString();
+ return txt;
+}
+
+void Transaction::startEditMode(void)
+{
+ m_inEdit = true;
+ // only update the number of lines displayed if we edit inside the register
+ if(m_inRegisterEdit)
+ setNumRowsRegister(numRowsRegister(true));
+}
+
+void Transaction::leaveEditMode(void)
+{
+ m_inEdit = false;
+ m_inRegisterEdit = false;
+ setFocus(hasFocus(), true);
+}
+
+void Transaction::singleLineMemo(QString& txt, const MyMoneySplit& split) const
+{
+ txt = split.memo();
+ // remove empty lines
+ txt.replace("\n\n", "\n");
+ // replace '\n' with ", "
+ txt.replace('\n', ", ");
+}
+
+int Transaction::rowHeightHint(void) const
+{
+ return m_inEdit ? formRowHeight()-4 : RegisterItem::rowHeightHint();
+}
+
+
+bool Transaction::matches(const QString& txt) const
+{
+ if(txt.isEmpty() || m_transaction.splitCount() == 0)
+ return true;
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString s(txt);
+ s.replace(MyMoneyMoney::thousandSeparator(), QString());
+
+ const QValueList<MyMoneySplit>&list = m_transaction.splits();
+ QValueList<MyMoneySplit>::const_iterator it_s;
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ // check if the text is contained in one of the fields
+ // memo, number, payee, account
+ if((*it_s).memo().contains(txt, false)
+ || (*it_s).number().contains(txt, false))
+ return true;
+
+ if(!(*it_s).payeeId().isEmpty()) {
+ const MyMoneyPayee& payee = file->payee((*it_s).payeeId());
+ if(payee.name().contains(txt, false))
+ return true;
+ }
+ const MyMoneyAccount& acc = file->account((*it_s).accountId());
+ if(acc.name().contains(txt, false))
+ return true;
+
+ if(!s.isEmpty()) {
+ // check if any of the value field matches if a value has been entered
+ QString r = (*it_s).value().formatMoney(m_account.fraction(), false);
+ if(r.contains(s, false))
+ return true;
+ const MyMoneyAccount& acc = file->account((*it_s).accountId());
+ r = (*it_s).shares().formatMoney(acc.fraction(), false);
+ if(r.contains(s, false))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Transaction::setShowBalance(bool showBalance)
+{
+ m_showBalance = showBalance;
+}
+
+void Transaction::setVisible(bool visible)
+{
+ if(visible != isVisible()) {
+ RegisterItem::setVisible(visible);
+ RegisterItem* p;
+ Transaction* t;
+ if(!visible) {
+ // if we are hidden, we need to inform all previous transactions
+ // about it so that they don't show the balance
+ p = prevItem();
+ while(p) {
+ t = dynamic_cast<Transaction*>(p);
+ if(t) {
+ if(!t->m_showBalance)
+ break;
+ t->m_showBalance = false;
+ }
+ p = p->prevItem();
+ }
+ } else {
+ // if we are shown, we need to check if the next transaction
+ // is visible and change the display of the balance
+ p = this;
+ do {
+ p = p->nextItem();
+ t = dynamic_cast<Transaction*>(p);
+ } while(!t && p);
+
+ // if the next transaction is visible or I am the last one
+ if((t && t->m_showBalance) || !t) {
+ m_showBalance = true;
+ p = prevItem();
+ while(p && p->isVisible()) {
+ t = dynamic_cast<Transaction*>(p);
+ if(t) {
+ if(t->m_showBalance)
+ break;
+ t->m_showBalance = true;
+ }
+ p = p->prevItem();
+ }
+ }
+ }
+ }
+}
+
+void Transaction::setSelected(bool selected)
+{
+ if(!selected || (selected && isVisible()))
+ m_selected = selected;
+}
+
+StdTransaction::StdTransaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ Transaction(parent, transaction, split, uniqueId),
+ m_showAccountRow(false)
+{
+ try {
+ m_categoryHeader = i18n("Category");
+ switch(transaction.splitCount()) {
+ default:
+ m_category = i18n("Split transaction (category replacement)", "Split transaction");
+ break;
+
+ case 0: // the empty transaction
+ case 1:
+ break;
+
+ case 2:
+ setupFormHeader(m_transaction.splitByAccount(m_split.accountId(), false).accountId());
+ break;
+ }
+ } catch(MyMoneyException *e) {
+ kdDebug(2) << "Problem determining the category for transaction '" << m_transaction.id() << "'. Reason: " << e->what() << "\n";
+ delete e;
+ }
+ m_rowsForm = 6;
+
+ if(KMyMoneyUtils::transactionType(m_transaction) == KMyMoneyUtils::InvestmentTransaction) {
+ MyMoneySplit split = KMyMoneyUtils::stockSplit(m_transaction);
+ m_payee = MyMoneyFile::instance()->account(split.accountId()).name();
+ QString addon;
+ if(split.action() == MyMoneySplit::ActionBuyShares) {
+ if(split.value().isNegative()) {
+ addon = i18n("Sell");
+ } else {
+ addon = i18n("Buy");
+ }
+ } else if(split.action() == MyMoneySplit::ActionDividend) {
+ addon = i18n("Dividend");
+ } else if(split.action() == MyMoneySplit::ActionYield) {
+ addon = i18n("Yield");
+ }
+ if(!addon.isEmpty()) {
+ m_payee += QString(" (%1)").arg(addon);
+ }
+ m_payeeHeader = i18n("Activity");
+ m_category = i18n("Investment transaction");
+ }
+
+ // setup initial size
+ setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed()));
+
+ emit parent->itemAdded(this);
+}
+
+void StdTransaction::setupFormHeader(const QString& id)
+{
+ m_category = MyMoneyFile::instance()->accountToCategory(id);
+ switch(MyMoneyFile::instance()->account(id).accountGroup()) {
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::Liability:
+ m_categoryHeader = m_split.shares().isNegative() ? i18n("Transfer to") : i18n("Transfer from");
+ break;
+
+ default:
+ m_categoryHeader = i18n("Category");
+ break;
+ }
+}
+
+KMyMoneyRegister::Action StdTransaction::actionType(void) const
+{
+ KMyMoneyRegister::Action action=ActionNone;
+
+ // if at least one split is referencing an income or
+ // expense account, we will not call it a transfer
+ QValueList<MyMoneySplit>::const_iterator it_s;
+
+ for(it_s = m_transaction.splits().begin(); it_s != m_transaction.splits().end(); ++it_s) {
+ if((*it_s).accountId() == m_split.accountId())
+ continue;
+ MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
+ if(acc.accountGroup() == MyMoneyAccount::Income
+ || acc.accountGroup() == MyMoneyAccount::Expense) {
+ // otherwise, we have to determine between deposit and withdrawal
+ action = m_split.shares().isNegative() ? ActionWithdrawal : ActionDeposit;
+ break;
+ }
+ }
+ // otherwise, it's a transfer
+ if(it_s == m_transaction.splits().end())
+ action = ActionTransfer;
+
+ return action;
+}
+
+void StdTransaction::loadTab(TransactionForm* form)
+{
+ TabBar* bar = form->tabBar();
+ bar->setSignalEmission(TabBar::SignalNever);
+ for(int i = 0; i < bar->count(); ++i) {
+ bar->setTabEnabled(bar->tabAt(i)->identifier(), true);
+ }
+
+ if(m_transaction.splitCount() > 0) {
+ bar->setCurrentTab(actionType());
+ }
+ bar->setSignalEmission(TabBar::SignalAlways);
+}
+
+void StdTransaction::setupForm(TransactionForm* form)
+{
+ Transaction::setupForm(form);
+
+ QTableItem* memo = form->item(3, ValueColumn1);
+ memo->setSpan(3, 1);
+}
+
+bool StdTransaction::showRowInForm(int row) const
+{
+ return row == 0 ? m_showAccountRow : true;
+}
+
+void StdTransaction::setShowRowInForm(int row, bool show)
+{
+ if(row == 0)
+ m_showAccountRow = show;
+}
+
+bool StdTransaction::formCellText(QString& txt, int& align, int row, int col, QPainter* /* painter */)
+{
+ // if(m_transaction != MyMoneyTransaction()) {
+ switch(row) {
+ case 0:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = i18n("Account");
+ break;
+ }
+ break;
+
+ case 1:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = m_payeeHeader;
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ txt = m_payee;
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ if(haveNumberField())
+ txt = i18n("Number");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if(haveNumberField())
+ txt = m_split.number();
+ break;
+ }
+ break;
+
+ case 2:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = m_categoryHeader;
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ txt = m_category;
+ if(m_transaction != MyMoneyTransaction()) {
+ if(txt.isEmpty() && !m_split.value().isZero())
+ txt = i18n("*** UNASSIGNED ***");
+ }
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ txt = i18n("Date");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if(m_transaction != MyMoneyTransaction())
+ txt = KGlobal::locale()->formatDate(m_transaction.postDate(), true);
+ break;
+ }
+ break;
+
+ case 3:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = i18n("Memo");
+ break;
+
+ case ValueColumn1:
+ align &= ~Qt::AlignVCenter;
+ align |= Qt::AlignTop;
+ align |= Qt::AlignLeft;
+ if(m_transaction != MyMoneyTransaction())
+ txt = m_split.memo().section('\n', 0, 2);
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ txt = i18n("Amount");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if(m_transaction != MyMoneyTransaction()) {
+ txt = (m_split.value(m_transaction.commodity(), m_splitCurrencyId).abs()).formatMoney(m_account.fraction());
+ }
+ break;
+ }
+ break;
+
+ case 5:
+ switch(col) {
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ txt = i18n("Status");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ txt = reconcileState();
+ break;
+ }
+ }
+ // }
+ if(col == ValueColumn2 && row == 1) {
+ return haveNumberField();
+ }
+ return (col == ValueColumn1 && row < 4) || (col == ValueColumn2 && row > 0 && row != 4);
+}
+
+void StdTransaction::registerCellText(QString& txt, int& align, int row, int col, QPainter* painter)
+{
+ switch(row) {
+ case 0:
+ switch(col) {
+ case NumberColumn:
+ align |= Qt::AlignLeft;
+ if(haveNumberField())
+ txt = m_split.number();
+ break;
+
+ case DateColumn:
+ align |= Qt::AlignLeft;
+ txt = KGlobal::locale()->formatDate(m_transaction.postDate(), true);
+ break;
+
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ txt = m_payee;
+ if(txt.isEmpty() && m_rowsRegister < 3) {
+ singleLineMemo(txt, m_split);
+ }
+ if(txt.isEmpty() && m_rowsRegister < 2) {
+ if(m_account.accountType() != MyMoneyAccount::Income
+ && m_account.accountType() != MyMoneyAccount::Expense) {
+ txt = m_category;
+ if(txt.isEmpty() && !m_split.value().isZero()) {
+ txt = i18n("*** UNASSIGNED ***");
+ if(painter)
+ painter->setPen(KMyMoneyGlobalSettings::listErronousTransactionColor());
+ }
+ }
+ }
+ break;
+
+ case ReconcileFlagColumn:
+ align |= Qt::AlignHCenter;
+ txt = reconcileState(false);
+ break;
+
+ case PaymentColumn:
+ align |= Qt::AlignRight;
+ if(m_split.value().isNegative()) {
+ txt = (-m_split.value(m_transaction.commodity(), m_splitCurrencyId)).formatMoney(m_account.fraction());
+ }
+ break;
+
+ case DepositColumn:
+ align |= Qt::AlignRight;
+ if(!m_split.value().isNegative()) {
+ txt = m_split.value(m_transaction.commodity(), m_splitCurrencyId).formatMoney(m_account.fraction());
+ }
+ break;
+
+ case BalanceColumn:
+ align |= Qt::AlignRight;
+ if(m_showBalance)
+ txt = m_balance.formatMoney(m_account.fraction());
+ else
+ txt = "----";
+ break;
+
+ case AccountColumn:
+ // txt = m_objects->account(m_transaction.splits()[0].accountId()).name();
+ txt = MyMoneyFile::instance()->account(m_split.accountId()).name();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 1:
+ switch(col) {
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ txt = m_category;
+ if(txt.isEmpty() && !m_split.value().isZero()) {
+ txt = i18n("*** UNASSIGNED ***");
+ if(painter)
+ painter->setPen(KMyMoneyGlobalSettings::listErronousTransactionColor());
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2:
+ switch(col) {
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ singleLineMemo(txt, m_split);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+int StdTransaction::registerColWidth(int col, const QFontMetrics& cellFontMetrics)
+{
+ QString txt;
+ int firstRow = 0, lastRow = 0;
+
+ int nw = 0;
+ for(int i = firstRow; i <= lastRow; ++i) {
+ int align;
+ registerCellText(txt, align, i, col, 0);
+ int w = cellFontMetrics.width(txt+" ");
+ if(w > nw)
+ nw = w;
+ }
+ return nw;
+}
+
+void StdTransaction::arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets)
+{
+ if(!m_form || !m_parent)
+ return;
+
+ setupFormPalette(editWidgets);
+
+ arrangeWidget(m_form, 0, ValueColumn1, editWidgets["account"]);
+ arrangeWidget(m_form, 1, LabelColumn1, editWidgets["cashflow"]);
+ arrangeWidget(m_form, 1, ValueColumn1, editWidgets["payee"]);
+ arrangeWidget(m_form, 2, ValueColumn1, editWidgets["category"]->parentWidget());
+ arrangeWidget(m_form, 3, ValueColumn1, editWidgets["memo"]);
+ if(haveNumberField()) {
+ arrangeWidget(m_form, 1, LabelColumn2, editWidgets["number-label"]);
+ arrangeWidget(m_form, 1, ValueColumn2, editWidgets["number"]);
+ }
+ arrangeWidget(m_form, 2, LabelColumn2, editWidgets["date-label"]);
+ arrangeWidget(m_form, 2, ValueColumn2, editWidgets["postdate"]);
+ arrangeWidget(m_form, 3, ValueColumn2, editWidgets["amount"]);
+ arrangeWidget(m_form, 5, ValueColumn2, editWidgets["status"]);
+ arrangeWidget(m_form, 2, LabelColumn1, editWidgets["category-label"]);
+
+ // get rid of the hints. we don't need them for the form
+ QMap<QString, QWidget*>::iterator it;
+ for(it = editWidgets.begin(); it != editWidgets.end(); ++it) {
+ KMyMoneyCombo* combo = dynamic_cast<KMyMoneyCombo*>(*it);
+ kMyMoneyLineEdit* edit = dynamic_cast<kMyMoneyLineEdit*>(*it);
+ KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(*it);
+ if(combo)
+ combo->setHint(QString());
+ if(edit)
+ edit->setHint(QString());
+ if(payee)
+ payee->setHint(QString());
+ }
+
+ // drop the tabbar on top of the original
+ KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast<KMyMoneyTransactionForm::TransactionForm*>(m_form);
+ TabBar* w = dynamic_cast<TabBar*>(editWidgets["tabbar"]);
+ if(w) {
+ w->reparent(form->tabBar(), QPoint(0, 0), true);
+ }
+}
+
+void StdTransaction::tabOrderInForm(QWidgetList& tabOrderWidgets) const
+{
+ QStringList taborder = QStringList::split(",", KMyMoneyGlobalSettings::stdTransactionFormTabOrder());
+ QStringList::const_iterator it_s = taborder.constBegin();
+ QWidget* w;
+ while(it_s != taborder.constEnd()) {
+ if(*it_s == "account") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(0, ValueColumn1)));
+ } else if(*it_s == "cashflow") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, LabelColumn1)));
+ } else if(*it_s == "payee") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, ValueColumn1)));
+ } else if(*it_s == "category") {
+ // make sure to have the category field and the split button as seperate tab order widgets
+ // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
+ // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
+ // go haywire when someone changes the KMyMoneyCategory object ...
+ w = m_form->cellWidget(2, ValueColumn1);
+ tabOrderWidgets.append(focusWidget(w));
+ w = dynamic_cast<QWidget*>(w->child("splitButton"));
+ if(w)
+ tabOrderWidgets.append(w);
+ } else if(*it_s == "memo") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(3, ValueColumn1)));
+ } else if(*it_s == "number") {
+ if(haveNumberField()) {
+ if((w = focusWidget(m_form->cellWidget(1, ValueColumn2))))
+ tabOrderWidgets.append(w);
+ }
+ } else if(*it_s == "date") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(2, ValueColumn2)));
+ } else if(*it_s == "amount") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(3, ValueColumn2)));
+ } else if(*it_s == "state") {
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(5, ValueColumn2)));
+ }
+ ++it_s;
+ }
+}
+
+void StdTransaction::arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets)
+{
+ if(!m_parent)
+ return;
+
+ setupRegisterPalette(editWidgets);
+
+ if(haveNumberField())
+ arrangeWidget(m_parent, m_startRow+0, NumberColumn, editWidgets["number"]);
+ arrangeWidget(m_parent, m_startRow + 0, DateColumn, editWidgets["postdate"]);
+ arrangeWidget(m_parent, m_startRow + 1, DateColumn, editWidgets["status"]);
+ arrangeWidget(m_parent, m_startRow + 0, DetailColumn, editWidgets["payee"]);
+ arrangeWidget(m_parent, m_startRow + 1, DetailColumn, editWidgets["category"]->parentWidget());
+ arrangeWidget(m_parent, m_startRow + 2, DetailColumn, editWidgets["memo"]);
+ arrangeWidget(m_parent, m_startRow + 0, PaymentColumn, editWidgets["payment"]);
+ arrangeWidget(m_parent, m_startRow + 0, DepositColumn, editWidgets["deposit"]);
+
+ // increase the height of the row containing the memo widget
+ m_parent->setRowHeight(m_startRow+2, m_parent->rowHeightHint() * 3);
+}
+
+void StdTransaction::tabOrderInRegister(QWidgetList& tabOrderWidgets) const
+{
+ QStringList taborder = QStringList::split(",", KMyMoneyGlobalSettings::stdTransactionRegisterTabOrder());
+ QStringList::const_iterator it_s = taborder.constBegin();
+ QWidget* w;
+ while(it_s != taborder.constEnd()) {
+ if(*it_s == "number") {
+ if(haveNumberField()) {
+ if((w = focusWidget(m_parent->cellWidget(m_startRow + 0, NumberColumn))))
+ tabOrderWidgets.append(w);
+ }
+ } else if(*it_s == "date") {
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DateColumn)));
+ } else if(*it_s == "payee") {
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DetailColumn)));
+ } else if(*it_s == "category") {
+ // make sure to have the category field and the split button as seperate tab order widgets
+ // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
+ // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
+ // go haywire when someone changes the KMyMoneyCategory object ...
+ w = m_parent->cellWidget(m_startRow + 1, DetailColumn);
+ tabOrderWidgets.append(focusWidget(w));
+ w = dynamic_cast<QWidget*>(w->child("splitButton"));
+ if(w)
+ tabOrderWidgets.append(w);
+ } else if(*it_s == "memo") {
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 2, DetailColumn)));
+ } else if(*it_s == "payment") {
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, PaymentColumn)));
+ } else if(*it_s == "deposit") {
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DepositColumn)));
+ } else if(*it_s == "state") {
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 1, DateColumn)));
+ }
+ ++it_s;
+ }
+}
+
+int StdTransaction::numRowsRegister(bool expanded) const
+{
+ int numRows = 1;
+ if(expanded) {
+ numRows = 3;
+ if(!m_inEdit) {
+ if(m_payee.isEmpty()) {
+ numRows--;
+ }
+ if(m_split.memo().isEmpty()) {
+ numRows--;
+ }
+ // For income and expense accounts that only have
+ // two splits we only show one line, because the
+ // account name is already contained in the account column.
+ if(m_account.accountType() == MyMoneyAccount::Income
+ || m_account.accountType() == MyMoneyAccount::Expense) {
+ if(numRows > 2 && m_transaction.splitCount() == 2)
+ numRows = 1;
+ }
+ }
+ }
+ return numRows;
+}
+
+TransactionEditor* StdTransaction::createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate)
+{
+ m_inRegisterEdit = regForm == m_parent;
+ return new StdTransactionEditor(regForm, this, list, lastPostDate);
+}
+
+InvestTransaction::InvestTransaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
+ Transaction(parent, transaction, split, uniqueId)
+{
+ // dissect the transaction into its type, splits, currency, security etc.
+ InvestTransactionEditor::dissectTransaction(m_transaction, m_split,
+ m_assetAccountSplit,
+ m_feeSplits,
+ m_interestSplits,
+ m_security,
+ m_currency,
+ m_transactionType);
+
+ QValueList<MyMoneySplit>::ConstIterator it_s;
+ for(it_s = m_feeSplits.begin(); it_s != m_feeSplits.end(); ++it_s) {
+ m_feeAmount += (*it_s).value();
+ }
+ for(it_s = m_interestSplits.begin(); it_s != m_interestSplits.end(); ++it_s) {
+ m_interestAmount += (*it_s).value();
+ }
+
+ // check the count of the fee splits and setup the text
+ switch(m_feeSplits.count()) {
+ case 0:
+ break;
+
+ case 1:
+ m_feeCategory = MyMoneyFile::instance()->accountToCategory(m_feeSplits[0].accountId());
+ break;
+
+ default:
+ m_feeCategory = i18n("Split transaction (category replacement)", "Split transaction");
+ break;
+ }
+
+ // check the count of the interest splits and setup the text
+ switch(m_interestSplits.count()) {
+ case 0:
+ break;
+
+ case 1:
+ m_interestCategory = MyMoneyFile::instance()->accountToCategory(m_interestSplits[0].accountId());
+ break;
+
+ default:
+ m_interestCategory = i18n("Split transaction (category replacement)", "Split transaction");
+ break;
+ }
+
+ m_rowsForm = 7;
+
+ // setup initial size
+ setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed()));
+
+ emit parent->itemAdded(this);
+}
+
+void InvestTransaction::setupForm(TransactionForm* form)
+{
+ Transaction::setupForm(form);
+
+ QTableItem* memo = form->item(5, 1);
+ memo->setSpan(2, 1);
+}
+
+void InvestTransaction::activity(QString& txt, MyMoneySplit::investTransactionTypeE type) const
+{
+ switch(type) {
+ case MyMoneySplit::AddShares:
+ txt = i18n("Add shares");
+ break;
+ case MyMoneySplit::RemoveShares:
+ txt = i18n("Remove shares");
+ break;
+ case MyMoneySplit::BuyShares:
+ txt = i18n("Buy shares");
+ break;
+ case MyMoneySplit::SellShares:
+ txt = i18n("Sell shares");
+ break;
+ case MyMoneySplit::Dividend:
+ txt = i18n("Dividend");
+ break;
+ case MyMoneySplit::ReinvestDividend:
+ txt = i18n("Reinvest Dividend");
+ break;
+ case MyMoneySplit::Yield:
+ txt = i18n("Yield");
+ break;
+ case MyMoneySplit::SplitShares:
+ txt = i18n("Split shares");
+ break;
+ default:
+ txt = i18n("Unknown");
+ break;
+ }
+}
+
+bool InvestTransaction::formCellText(QString& txt, int& align, int row, int col, QPainter* /* painter */)
+{
+ bool fieldEditable = false;
+
+ switch(row) {
+ case 0:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = i18n("Activity");
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ fieldEditable = true;
+ activity(txt, m_transactionType);
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ txt = i18n("Date");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ fieldEditable = true;
+ if(m_transaction != MyMoneyTransaction())
+ txt = KGlobal::locale()->formatDate(m_transaction.postDate(), true);
+ break;
+ }
+ break;
+
+ case 1:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = i18n("Security");
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ fieldEditable = true;
+ if(m_account.isInvest())
+ txt = m_security.name();
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ if(haveShares()) {
+ txt = i18n("Shares");
+ } else if(haveSplitRatio()) {
+ txt = i18n("Ratio");
+ }
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if((fieldEditable = haveShares()) == true) {
+ txt = m_split.shares().abs().formatMoney("", MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
+ } else if(haveSplitRatio()) {
+ txt = QString("1 / %1").arg(m_split.shares().abs().formatMoney("", -1));
+ }
+ break;
+ }
+ break;
+
+ case 2:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ if(haveAssetAccount())
+ txt = i18n("Account");
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ if((fieldEditable = haveAssetAccount()) == true) {
+ txt = MyMoneyFile::instance()->accountToCategory(m_assetAccountSplit.accountId());
+ }
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ if(havePrice())
+ txt = i18n("Price/share");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if((fieldEditable = havePrice()) == true && !m_split.shares().isZero()) {
+ txt = m_split.price().formatMoney("", KMyMoneyGlobalSettings::pricePrecision());
+ }
+ break;
+ }
+ break;
+
+ case 3:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ if(haveFees())
+ txt = i18n("Fees");
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ if((fieldEditable = haveFees()) == true) {
+ txt = m_feeCategory;
+ }
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ if(haveFees() && !m_feeCategory.isEmpty())
+ txt = i18n("Amount");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if(haveFees()) {
+ if((fieldEditable = !m_feeCategory.isEmpty()) == true) {
+ txt = m_feeAmount.formatMoney(m_currency);
+ }
+ }
+ break;
+ }
+ break;
+
+ case 4:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ if(haveInterest())
+ txt = i18n("Interest");
+ break;
+
+ case ValueColumn1:
+ align |= Qt::AlignLeft;
+ if((fieldEditable = haveInterest()) == true) {
+ txt = m_interestCategory;
+ }
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ if(haveInterest() && !m_interestCategory.isEmpty())
+ txt = i18n("Amount");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if(haveInterest()) {
+ if((fieldEditable = !m_interestCategory.isEmpty()) == true) {
+ txt = (-m_interestAmount).formatMoney(m_currency);
+ }
+ }
+ break;
+ }
+ break;
+
+ case 5:
+ switch(col) {
+ case LabelColumn1:
+ align |= Qt::AlignLeft;
+ txt = i18n("Memo");
+ break;
+
+ case ValueColumn1:
+ align &= ~Qt::AlignVCenter;
+ align |= Qt::AlignTop;
+ align |= Qt::AlignLeft;
+ fieldEditable = true;
+ if(m_transaction != MyMoneyTransaction())
+ txt = m_split.memo().section('\n', 0, 2);
+ break;
+
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ if(haveAmount())
+ txt = i18n("Total");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ if((fieldEditable = haveAmount()) == true) {
+ txt = m_assetAccountSplit.value().abs().formatMoney(m_currency);
+ }
+ }
+ break;
+
+ case 6:
+ switch(col) {
+ case LabelColumn2:
+ align |= Qt::AlignLeft;
+ txt = i18n("Status");
+ break;
+
+ case ValueColumn2:
+ align |= Qt::AlignRight;
+ fieldEditable = true;
+ txt = reconcileState();
+ break;
+ }
+ }
+
+ return fieldEditable;
+}
+
+void InvestTransaction::registerCellText(QString& txt, int& align, int row, int col, QPainter* /* painter */)
+{
+ switch(row) {
+ case 0:
+ switch(col) {
+ case DateColumn:
+ align |= Qt::AlignLeft;
+ txt = KGlobal::locale()->formatDate(m_transaction.postDate(), true);
+ break;
+
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ activity(txt, m_transactionType);
+ break;
+
+ case SecurityColumn:
+ align |= Qt::AlignLeft;
+ if(m_account.isInvest())
+ txt = m_security.name();
+ break;
+
+ case ReconcileFlagColumn:
+ align |= Qt::AlignHCenter;
+ txt = reconcileState(false);
+ break;
+
+ case QuantityColumn:
+ align |= Qt::AlignRight;
+ if(haveShares())
+ txt = m_split.shares().abs().formatMoney("", MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
+ else if(haveSplitRatio()) {
+ txt = QString("1 / %1").arg(m_split.shares().abs().formatMoney("", -1));
+ }
+ break;
+
+ case PriceColumn:
+ align |= Qt::AlignRight;
+ if(havePrice() && !m_split.shares().isZero()) {
+ txt = m_split.price().formatMoney(m_currency.tradingSymbol(), KMyMoneyGlobalSettings::pricePrecision());
+ }
+ break;
+
+ case ValueColumn:
+ align |= Qt::AlignRight;
+ if(haveAmount()) {
+ txt = m_assetAccountSplit.value().abs().formatMoney(m_currency);
+
+ } else if(haveInterest()) {
+ txt = (-m_interestAmount).formatMoney(m_currency);
+ }
+ break;
+
+ case BalanceColumn:
+ align |= Qt::AlignRight;
+ if(m_showBalance)
+ txt = m_balance.formatMoney("", MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
+ else
+ txt = "----";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 1:
+ switch(col) {
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()) {
+ txt = MyMoneyFile::instance()->accountToCategory(m_assetAccountSplit.accountId());
+ } else if(haveInterest() && m_interestSplits.count()) {
+ txt = m_interestCategory;
+ } else if(haveFees() && m_feeSplits.count()) {
+ txt = m_feeCategory;
+ } else
+ singleLineMemo(txt, m_split);
+ break;
+
+ case QuantityColumn:
+ align |= Qt::AlignRight;
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()) {
+ // txt = m_interestAmount.abs().formatMoney(m_currency);
+ } else if(haveInterest() && m_interestSplits.count()) {
+ txt = (-m_interestAmount).formatMoney(m_currency);
+ } else if(haveFees() && m_feeSplits.count()) {
+ txt = m_feeAmount.formatMoney(m_currency);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2:
+ switch(col) {
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()
+ && haveInterest() && m_interestSplits.count()) {
+ txt = m_interestCategory;
+ } else if(haveFees() && m_feeSplits.count()) {
+ txt = m_feeCategory;
+ } else
+ singleLineMemo(txt, m_split);
+ break;
+
+ case QuantityColumn:
+ align |= Qt::AlignRight;
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()
+ && haveInterest() && m_interestSplits.count()) {
+ txt = (-m_interestAmount).formatMoney(m_currency);
+ } else if(haveFees() && m_feeSplits.count()) {
+ txt = m_feeAmount.formatMoney(m_currency);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3:
+ switch(col) {
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()
+ && haveInterest() && m_interestSplits.count()
+ && haveFees() && m_feeSplits.count()) {
+ txt = m_feeCategory;
+ } else
+ singleLineMemo(txt, m_split);
+ break;
+
+ case QuantityColumn:
+ align |= Qt::AlignRight;
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()
+ && haveInterest() && m_interestSplits.count()
+ && haveFees() && m_feeSplits.count()) {
+ txt = m_feeAmount.formatMoney(m_currency);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4:
+ switch(col) {
+ case DetailColumn:
+ align |= Qt::AlignLeft;
+ singleLineMemo(txt, m_split);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+int InvestTransaction::registerColWidth(int col, const QFontMetrics& cellFontMetrics)
+{
+ QString txt;
+ MyMoneyMoney amount;
+ int nw = 0;
+
+ // for now just check all rows in that column
+ for(int row = 0; row < m_rowsRegister; ++row) {
+ int w;
+ Transaction::registerCellText(txt, row, col);
+ w = cellFontMetrics.width(txt+" ");
+ nw = QMAX(nw, w);
+ }
+
+ // TODO the optimized way would be to base the size on the contents of a single row
+ // as we do it in StdTransaction::registerColWidth()
+#if 0
+ switch(col) {
+ default:
+ break;
+
+ case PriceColumn:
+ if(havePrice()) {
+ txt = (m_split.value() / m_split.shares()).formatMoney("", KMyMoneyGlobalSettings::pricePrecision());
+ nw = cellFontMetrics.width(txt+" ");
+ }
+ break;
+ }
+#endif
+ return nw;
+}
+
+void InvestTransaction::arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets)
+{
+ if(!m_form || !m_parent)
+ return;
+
+ setupFormPalette(editWidgets);
+
+ // arrange the edit widgets
+ arrangeWidget(m_form, 0, ValueColumn1, editWidgets["activity"]);
+ arrangeWidget(m_form, 0, ValueColumn2, editWidgets["postdate"]);
+ arrangeWidget(m_form, 1, ValueColumn1, editWidgets["security"]);
+ arrangeWidget(m_form, 1, ValueColumn2, editWidgets["shares"]);
+ arrangeWidget(m_form, 2, ValueColumn1, editWidgets["asset-account"]);
+ arrangeWidget(m_form, 2, ValueColumn2, editWidgets["price"]);
+ arrangeWidget(m_form, 3, ValueColumn1, editWidgets["fee-account"]->parentWidget());
+ arrangeWidget(m_form, 3, ValueColumn2, editWidgets["fee-amount"]);
+ arrangeWidget(m_form, 4, ValueColumn1, editWidgets["interest-account"]->parentWidget());
+ arrangeWidget(m_form, 4, ValueColumn2, editWidgets["interest-amount"]);
+ arrangeWidget(m_form, 5, ValueColumn1, editWidgets["memo"]);
+ arrangeWidget(m_form, 5, ValueColumn2, editWidgets["total"]);
+ arrangeWidget(m_form, 6, ValueColumn2, editWidgets["status"]);
+
+ // arrange dynamic labels
+ arrangeWidget(m_form, 1, LabelColumn2, editWidgets["shares-label"]);
+ arrangeWidget(m_form, 2, LabelColumn1, editWidgets["asset-label"]);
+ arrangeWidget(m_form, 2, LabelColumn2, editWidgets["price-label"]);
+ arrangeWidget(m_form, 3, LabelColumn1, editWidgets["fee-label"]);
+ arrangeWidget(m_form, 3, LabelColumn2, editWidgets["fee-amount-label"]);
+ arrangeWidget(m_form, 4, LabelColumn1, editWidgets["interest-label"]);
+ arrangeWidget(m_form, 4, LabelColumn2, editWidgets["interest-amount-label"]);
+ arrangeWidget(m_form, 5, LabelColumn2, editWidgets["total-label"]);
+
+ // get rid of the hints. we don't need them for the form
+ QMap<QString, QWidget*>::iterator it;
+ for(it = editWidgets.begin(); it != editWidgets.end(); ++it) {
+ KMyMoneyCombo* combo = dynamic_cast<KMyMoneyCombo*>(*it);
+ kMyMoneyLineEdit* lineedit = dynamic_cast<kMyMoneyLineEdit*>(*it);
+ kMyMoneyEdit* edit = dynamic_cast<kMyMoneyEdit*>(*it);
+ KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(*it);
+ if(combo)
+ combo->setHint(QString());
+ if(edit)
+ edit->setHint(QString());
+ if(lineedit)
+ lineedit->setHint(QString());
+ if(payee)
+ payee->setHint(QString());
+ }
+}
+
+void InvestTransaction::tabOrderInForm(QWidgetList& tabOrderWidgets) const
+{
+ // activity
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(0, ValueColumn1)));
+
+ // date
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(0, ValueColumn2)));
+
+ // security
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, ValueColumn1)));
+
+ // shares
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, ValueColumn2)));
+
+ // account
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(2, ValueColumn1)));
+
+ // price
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(2, ValueColumn2)));
+
+ // make sure to have the fee category field and the split button as seperate tab order widgets
+ // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
+ // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
+ // go haywire when someone changes the KMyMoneyCategory object ...
+ QWidget* w = m_form->cellWidget(3, ValueColumn1);
+ tabOrderWidgets.append(focusWidget(w));
+ w = dynamic_cast<QWidget*>(w->child("splitButton"));
+ if(w)
+ tabOrderWidgets.append(w);
+
+ // fee amount
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(3, ValueColumn2)));
+
+ // the same applies for the interest categories
+ w = m_form->cellWidget(4, ValueColumn1);
+ tabOrderWidgets.append(focusWidget(w));
+ w = dynamic_cast<QWidget*>(w->child("splitButton"));
+ if(w)
+ tabOrderWidgets.append(w);
+
+ // interest amount
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(4, ValueColumn2)));
+
+ // memo
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(5, ValueColumn1)));
+
+ // total
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(5, ValueColumn2)));
+
+ // state
+ tabOrderWidgets.append(focusWidget(m_form->cellWidget(6, ValueColumn2)));
+}
+
+void InvestTransaction::arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets)
+{
+ if(!m_parent)
+ return;
+
+ setupRegisterPalette(editWidgets);
+
+ arrangeWidget(m_parent, m_startRow + 0, DateColumn, editWidgets["postdate"]);
+ arrangeWidget(m_parent, m_startRow + 0, SecurityColumn, editWidgets["security"]);
+ arrangeWidget(m_parent, m_startRow + 0, DetailColumn, editWidgets["activity"]);
+ arrangeWidget(m_parent, m_startRow + 1, DetailColumn, editWidgets["asset-account"]);
+ arrangeWidget(m_parent, m_startRow + 2, DetailColumn, editWidgets["interest-account"]->parentWidget());
+ arrangeWidget(m_parent, m_startRow + 3, DetailColumn, editWidgets["fee-account"]->parentWidget());
+ arrangeWidget(m_parent, m_startRow + 4, DetailColumn, editWidgets["memo"]);
+ arrangeWidget(m_parent, m_startRow + 0, QuantityColumn, editWidgets["shares"]);
+ arrangeWidget(m_parent, m_startRow + 0, PriceColumn, editWidgets["price"]);
+ arrangeWidget(m_parent, m_startRow + 2, QuantityColumn, editWidgets["interest-amount"]);
+ arrangeWidget(m_parent, m_startRow + 3, QuantityColumn, editWidgets["fee-amount"]);
+ arrangeWidget(m_parent, m_startRow + 0, ValueColumn, editWidgets["total"]);
+ arrangeWidget(m_parent, m_startRow + 1, DateColumn, editWidgets["status"]);
+
+ // increase the height of the row containing the memo widget
+ m_parent->setRowHeight(m_startRow+4, m_parent->rowHeightHint() * 3);
+}
+
+void InvestTransaction::tabOrderInRegister(QWidgetList& tabOrderWidgets) const
+{
+ QWidget* w;
+
+ // date
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DateColumn)));
+ // security
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, SecurityColumn)));
+ // activity
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DetailColumn)));
+ // shares
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, QuantityColumn)));
+ // price
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, PriceColumn)));
+ // asset account
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 1, DetailColumn)));
+
+ // make sure to have the category fields and the split button as seperate tab order widgets
+ // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
+ // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
+ // go haywire when someone changes the KMyMoneyCategory object ...
+ w = m_parent->cellWidget(m_startRow + 2, DetailColumn); // interest account
+ tabOrderWidgets.append(focusWidget(w));
+ w = dynamic_cast<QWidget*>(w->child("splitButton"));
+ if(w)
+ tabOrderWidgets.append(w);
+
+ // interest amount
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 2, QuantityColumn)));
+
+ w = m_parent->cellWidget(m_startRow + 3, DetailColumn); // fee account
+ tabOrderWidgets.append(focusWidget(w));
+ w = dynamic_cast<QWidget*>(w->child("splitButton"));
+ if(w)
+ tabOrderWidgets.append(w);
+
+ // fee amount
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 3, QuantityColumn)));
+
+ // memo
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 4, DetailColumn)));
+
+ // status
+ tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 1, DateColumn)));
+}
+
+int InvestTransaction::numRowsRegister(bool expanded) const
+{
+ int numRows = 1;
+ if(expanded) {
+ if(!m_inEdit) {
+ if(haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty())
+ ++numRows;
+ if(haveInterest() && m_interestSplits.count())
+ ++numRows;
+ if(haveFees() && m_feeSplits.count())
+ ++numRows;
+ if(!m_split.memo().isEmpty())
+ ++numRows;
+ } else
+ numRows = 5;
+ }
+ return numRows;
+}
+
+bool InvestTransaction::haveShares(void) const
+{
+ bool rc = true;
+ switch(m_transactionType) {
+ case MyMoneySplit::Dividend:
+ case MyMoneySplit::Yield:
+ case MyMoneySplit::SplitShares:
+ rc = false;
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+bool InvestTransaction::haveFees(void) const
+{
+ bool rc = true;
+ switch(m_transactionType) {
+ case MyMoneySplit::AddShares:
+ case MyMoneySplit::RemoveShares:
+ case MyMoneySplit::SplitShares:
+ rc = false;
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+bool InvestTransaction::haveInterest(void) const
+{
+ bool rc = false;
+ switch(m_transactionType) {
+ case MyMoneySplit::BuyShares:
+ case MyMoneySplit::SellShares:
+ case MyMoneySplit::Dividend:
+ case MyMoneySplit::ReinvestDividend:
+ case MyMoneySplit::Yield:
+ rc = true;
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+bool InvestTransaction::havePrice(void) const
+{
+ bool rc = false;
+ switch(m_transactionType) {
+ case MyMoneySplit::BuyShares:
+ case MyMoneySplit::SellShares:
+ case MyMoneySplit::ReinvestDividend:
+ rc = true;
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+bool InvestTransaction::haveAmount(void) const
+{
+ bool rc = false;
+ switch(m_transactionType) {
+ case MyMoneySplit::BuyShares:
+ case MyMoneySplit::SellShares:
+ case MyMoneySplit::Dividend:
+ case MyMoneySplit::Yield:
+ rc = true;
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+bool InvestTransaction::haveAssetAccount(void) const
+{
+ bool rc = true;
+ switch(m_transactionType) {
+ case MyMoneySplit::AddShares:
+ case MyMoneySplit::RemoveShares:
+ case MyMoneySplit::SplitShares:
+ case MyMoneySplit::ReinvestDividend:
+ rc = false;
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+bool InvestTransaction::haveSplitRatio(void) const
+{
+ return m_transactionType == MyMoneySplit::SplitShares;
+}
+
+void InvestTransaction::splits(MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& feeSplits) const
+{
+ assetAccountSplit = m_assetAccountSplit;
+ interestSplits = m_interestSplits;
+ feeSplits = m_feeSplits;
+}
+
+TransactionEditor* InvestTransaction::createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate)
+{
+ m_inRegisterEdit = regForm == m_parent;
+ return new InvestTransactionEditor(regForm, this, list, lastPostDate);
+}
+
diff --git a/kmymoney2/widgets/transaction.h b/kmymoney2/widgets/transaction.h
new file mode 100644
index 0000000..060d025
--- /dev/null
+++ b/kmymoney2/widgets/transaction.h
@@ -0,0 +1,420 @@
+/***************************************************************************
+ transaction.h - description
+ -------------------
+ begin : Tue Jun 13 2006
+ copyright : (C) 2000-2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TRANSACTION_H
+#define TRANSACTION_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpalette.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/registeritem.h>
+#include <kmymoney/mymoneytransaction.h>
+#include <kmymoney/mymoneysplit.h>
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/selectedtransaction.h>
+#include <kmymoney/mymoneyaccount.h>
+
+class QTable;
+class TransactionEditor;
+class TransactionEditorContainer;
+
+namespace KMyMoneyTransactionForm {
+ class TransactionForm;
+}; // namespace
+
+namespace KMyMoneyRegister {
+
+// keep the following list in sync with code in the constructor
+// of KMyMoneyRegister::Register in register.cpp
+typedef enum {
+ NumberColumn = 0,
+ DateColumn,
+ AccountColumn,
+ SecurityColumn,
+ DetailColumn,
+ ReconcileFlagColumn,
+ PaymentColumn,
+ DepositColumn,
+ QuantityColumn,
+ PriceColumn,
+ ValueColumn,
+ BalanceColumn,
+ // insert new values above this line
+ MaxColumns
+} Column;
+
+class Transaction : public RegisterItem
+{
+public:
+ Transaction(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~Transaction() {}
+
+ virtual const char* className(void) { return "Transaction"; }
+
+ bool isSelectable(void) const { return true; }
+ bool isSelected(void) const { return m_selected; }
+ void setSelected(bool selected);
+
+ bool canHaveFocus(void) const { return true; }
+ bool hasFocus(void) const { return m_focus; }
+ bool hasEditorOpen(void) const { return m_inEdit; }
+
+ virtual bool isScheduled(void) const { return false; }
+
+ void setFocus(bool focus, bool updateLens = true);
+
+ bool isErronous(void) const { return m_erronous; }
+
+ virtual const QDate& sortPostDate(void) const { return m_transaction.postDate(); }
+ virtual int sortSamePostDate(void) const { return 2; }
+ virtual const QDate& sortEntryDate(void) const { return m_transaction.entryDate(); }
+ virtual const QString& sortPayee(void) const { return m_payee; }
+ virtual const MyMoneyMoney& sortValue(void) const { return m_split.shares(); }
+ virtual const QString& sortNumber(void) const { return m_split.number(); }
+ virtual const QString& sortEntryOrder(void) const { return m_uniqueId; }
+ virtual CashFlowDirection sortType(void) const { return m_split.shares().isNegative() ? Payment : Deposit; }
+ virtual const QString& sortCategory(void) const { return m_category; }
+ virtual MyMoneySplit::reconcileFlagE sortReconcileState(void) const { return m_split.reconcileFlag(); }
+
+ virtual const QString& id(void) const { return m_uniqueId; }
+ const MyMoneyTransaction& transaction(void) const { return m_transaction; }
+ const MyMoneySplit& split(void) const { return m_split; }
+
+ void setBalance(const MyMoneyMoney& balance) { m_balance = balance; }
+ const MyMoneyMoney& balance(void) const { return m_balance; }
+
+ virtual int rowHeightHint(void) const;
+
+ /**
+ * This method sets the general paramaters required for the painting of a cell
+ * in the register. These are:
+ *
+ * - background color (alternating)
+ * - background color (imported transaction)
+ * - background color (matched transaction)
+ * - background color (selected transaction)
+ * - cellRect (area covering the cell)
+ * - textRect (area covering the text)
+ * - color of the pen to do the painting of text and lines
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param cellRect ref to QRect object receiving the area information for the cell
+ * @param textRect ref to QRect object receiving the area information for the text
+ * @param cg ref to QColorGroup object receiving the color information to be used
+ */
+ virtual bool paintRegisterCellSetup(QPainter* painter, int& row, int& col, QRect& cellRect, QRect& textRect, QColorGroup& cg, QBrush& brush);
+
+ /**
+ * paints the focus if the current cell defined by (@a row, @a col) has the focus.
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param r area covering the cell
+ * @param cg the color definitions to be used
+ */
+ void paintRegisterCellFocus(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg);
+
+ /**
+ * paints a cell of the register for the transaction. Uses paintRegisterCellSetup(), paintRegisterCellText()
+ * paintRegisterGrid(), paintRegisterIcons() and paintRegisterCellFocus() to actually do the job.
+ *
+ * @param painter pointer to the QPainter object
+ * @param row vertical index of cell in register
+ * @param col horizontal index of cell in register
+ * @param r area covering the cell
+ * @param selected unused but kept for compatibility
+ * @param cg the color definitions to be used
+ *
+ */
+ virtual void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+ virtual void paintRegisterCellText(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg, int align, const QString& txt);
+ virtual void paintRegisterCellBackground(QPainter* painter, int row, int col, const QRect& r, const QBrush& backgroundBrush);
+ virtual void paintRegisterGrid(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg) const;
+ virtual void paintRegisterIcons(QPainter* painter, int row, int col, const QRect& r, const QColorGroup& cg);
+
+ virtual void paintFormCell(QPainter* /* painter */, int /* row */, int /* col */, const QRect& /* r */, bool /* selected */, const QColorGroup& /* cg */);
+
+ virtual bool formCellText(QString& /* txt */, int& /* align */, int /* row */, int /* col */, QPainter* /* painter */) { return false; }
+ virtual void registerCellText(QString& /* txt */, int& /* align */, int /* row */, int /* col */, QPainter* /* painter */) {}
+ virtual int registerColWidth(int /* col */, const QFontMetrics& /* cellFontMetrics */) { return 0; }
+
+ /**
+ * Helper method for the above method.
+ */
+ void registerCellText(QString& txt, int row, int col);
+
+ virtual int formRowHeight(int row);
+ virtual int formRowHeight(void) const;
+
+ virtual void setupForm(KMyMoneyTransactionForm::TransactionForm* form);
+ virtual void setupFormPalette(QMap<QString, QWidget*>& editWidgets);
+ virtual void setupRegisterPalette(QMap<QString, QWidget*>& editWidgets);
+ virtual void loadTab(KMyMoneyTransactionForm::TransactionForm* form) = 0;
+
+ virtual void arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets) = 0;
+ virtual void arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets) = 0;
+ virtual void tabOrderInForm(QWidgetList& tabOrderWidgets) const = 0;
+ virtual void tabOrderInRegister(QWidgetList& tabOrderWidgets) const = 0;
+
+ virtual KMyMoneyRegister::Action actionType(void) const = 0;
+
+ QWidget* focusWidget(QWidget*) const;
+ void arrangeWidget(QTable* tbl, int row, int col, QWidget* w) const;
+
+ bool haveNumberField(void) const;
+
+ bool matches(const QString&) const;
+
+ /**
+ * Checks if the mouse hovered over an area that has a tooltip associated with it.
+ * The mouse position is given in relative coordinates to the @a startRow and the
+ * @a row and @a col of the item are also passed as relative values.
+ *
+ * If a tooltip shall be shown, this method presets the rectangle @a r with the
+ * area in register coordinates and @a msg with the string that will be passed
+ * to QToolTip::tip. @a true is returned in this case.
+ *
+ * If no tooltip is available, @a false will be returned.
+ */
+ virtual bool maybeTip(const QPoint& relpos, int row, int col, QRect& r, QString& msg);
+
+ /**
+ * This method returns the number of register rows required for a certain
+ * item in expanded (@p expanded equals @a true) or collapsed (@p expanded
+ * is @a false) mode.
+ *
+ * @param expanded returns number of maximum rows required for this item to
+ * display all information (used for ledger lens and register
+ * edit mode) or the minimum number of rows required.
+ * @return number of rows required for mode selected by @p expanded
+ */
+ virtual int numRowsRegister(bool expanded) const = 0;
+
+ virtual int numRowsRegister(void) const = 0;
+
+ void leaveEditMode(void);
+ void startEditMode(void);
+
+ /**
+ * This method creates an editor for the transaction
+ */
+ virtual TransactionEditor* createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) = 0;
+
+ virtual void setVisible(bool visible);
+
+ virtual void setShowBalance(bool showBalance);
+
+ /**
+ * Return information if @a row should be shown (@a true )
+ * or hidden (@a false ) in the form. Default is true.
+ */
+ virtual bool showRowInForm(int row) const { Q_UNUSED(row) return true; }
+
+ /**
+ * Control visibility of @a row in the transaction form.
+ * Only row 0 has an effect, others return @a true.
+ */
+ virtual void setShowRowInForm(int row, bool show) { Q_UNUSED(row); Q_UNUSED(show) }
+
+ virtual void setReducedIntensity(bool reduced) { m_reducedIntensity = reduced; }
+
+protected:
+ virtual void markAsErronous(QPainter* p, int row, int col, const QRect& r);
+ virtual void markAttachment(QPainter* painter, int row, int col, const QRect& r);
+
+ /**
+ * This method converts m_split.reconcileFlag() into a readable string
+ *
+ * @param text Return textual representation e.g. "Cleared" (@a true) or just
+ * a flag e.g. "C" (@a false). Defaults to textual representation.
+ * @return Textual representation or flag as selected via @p text of the
+ * reconciliation state of the split
+ */
+ QString reconcileState(bool text = true) const;
+
+ /**
+ * Helper method to reduce a multi line memo text into a single line.
+ *
+ * @param txt QString that will receive the single line memo text
+ * @param split const reference to the split to take the memo from
+ */
+ void singleLineMemo(QString& txt, const MyMoneySplit& split) const;
+
+ virtual void setupPalette(const QPalette& palette, QMap<QString, QWidget*>& editWidgets);
+
+protected:
+ MyMoneyTransaction m_transaction;
+ MyMoneySplit m_split;
+ MyMoneyAccount m_account;
+ MyMoneyMoney m_balance;
+ QTable* m_form;
+ QString m_category;
+ QString m_payee;
+ QString m_payeeHeader;
+ QString m_categoryHeader;
+ QString m_splitCurrencyId;
+ QString m_uniqueId;
+ int m_formRowHeight;
+ bool m_selected;
+ bool m_focus;
+ bool m_erronous;
+ bool m_inEdit;
+ bool m_inRegisterEdit;
+ bool m_showBalance;
+ bool m_reducedIntensity;
+};
+
+class StdTransaction : public Transaction
+{
+public:
+ StdTransaction(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~StdTransaction() {}
+
+ virtual const char* className(void) { return "StdTransaction"; }
+
+ bool formCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+ void registerCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+
+ int registerColWidth(int col, const QFontMetrics& cellFontMetrics);
+ void setupForm(KMyMoneyTransactionForm::TransactionForm* form);
+ void loadTab(KMyMoneyTransactionForm::TransactionForm* form);
+
+ int numColsForm(void) const { return 4; }
+
+ void arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets);
+ void arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets);
+ void tabOrderInForm(QWidgetList& tabOrderWidgets) const;
+ void tabOrderInRegister(QWidgetList& tabOrderWidgets) const;
+ KMyMoneyRegister::Action actionType(void) const;
+
+ int numRowsRegister(bool expanded) const;
+
+ /**
+ * Provided for internal reasons. No API change. See RegisterItem::numRowsRegister()
+ */
+ int numRowsRegister(void) const { return RegisterItem::numRowsRegister(); }
+
+ TransactionEditor* createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate);
+
+ /**
+ * Return information if @a row should be shown (@a true )
+ * or hidden (@a false ) in the form. Default is true.
+ */
+ virtual bool showRowInForm(int row) const;
+
+ /**
+ * Control visibility of @a row in the transaction form.
+ * Only row 0 has an effect, others return @a true.
+ */
+ virtual void setShowRowInForm(int row, bool show);
+
+protected:
+ void setupFormHeader(const QString& id);
+
+private:
+ bool m_showAccountRow;
+};
+
+class InvestTransaction : public Transaction
+{
+public:
+ InvestTransaction(Register* parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId);
+ virtual ~InvestTransaction() {}
+
+ virtual const QString& sortSecurity(void) const { return m_security.name(); }
+ virtual const char* className(void) { return "InvestTransaction"; }
+
+ // virtual void paintRegisterCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+
+ bool formCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+ void registerCellText(QString& txt, int& align, int row, int col, QPainter* painter = 0);
+
+ int registerColWidth(int col, const QFontMetrics& cellFontMetrics);
+ void setupForm(KMyMoneyTransactionForm::TransactionForm* form);
+
+ /**
+ * provide NOP here as the investment transaction form does not supply a tab
+ */
+ void loadTab(KMyMoneyTransactionForm::TransactionForm* /* form */) {}
+
+ int numColsForm(void) const { return 4; }
+
+ void arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets);
+ void arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets);
+ void tabOrderInForm(QWidgetList& tabOrderWidgets) const;
+ void tabOrderInRegister(QWidgetList& tabOrderWidgets) const;
+ KMyMoneyRegister::Action actionType(void) const { return KMyMoneyRegister::ActionNone; }
+
+ int numRowsRegister(bool expanded) const;
+
+ /**
+ * Provided for internal reasons. No API change. See RegisterItem::numRowsRegister()
+ */
+ int numRowsRegister(void) const { return RegisterItem::numRowsRegister(); }
+
+ TransactionEditor* createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate);
+
+ void splits(MyMoneySplit& assetAccountSplit, QValueList<MyMoneySplit>& interestSplits, QValueList<MyMoneySplit>& feeSplits) const;
+
+protected:
+ bool haveShares(void) const;
+ bool haveFees(void) const;
+ bool haveInterest(void) const;
+ bool havePrice(void) const;
+ bool haveAmount(void) const;
+ bool haveAssetAccount(void) const;
+ bool haveSplitRatio(void) const;
+
+ /**
+ * Returns textual representation of the activity identified
+ * by @p type.
+ *
+ * @param txt reference to QString where to store the result
+ * @param type activity represented as investTransactionTypeE
+ */
+ void activity(QString& txt, MyMoneySplit::investTransactionTypeE type) const;
+
+private:
+ QValueList<MyMoneySplit> m_feeSplits;
+ QValueList<MyMoneySplit> m_interestSplits;
+ MyMoneySplit m_assetAccountSplit;
+ MyMoneySecurity m_security;
+ MyMoneySecurity m_currency;
+ MyMoneySplit::investTransactionTypeE m_transactionType;
+ QString m_feeCategory;
+ QString m_interestCategory;
+ MyMoneyMoney m_feeAmount;
+ MyMoneyMoney m_interestAmount;
+ MyMoneyMoney m_totalAmount;
+};
+
+}; // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
+
diff --git a/kmymoney2/widgets/transactioneditorcontainer.cpp b/kmymoney2/widgets/transactioneditorcontainer.cpp
new file mode 100644
index 0000000..4750025
--- /dev/null
+++ b/kmymoney2/widgets/transactioneditorcontainer.cpp
@@ -0,0 +1,29 @@
+/***************************************************************************
+ transactioneditorcontainer.cpp
+ ----------
+ begin : Wed Jun 07 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/transactioneditorcontainer.h>
+
+
diff --git a/kmymoney2/widgets/transactioneditorcontainer.h b/kmymoney2/widgets/transactioneditorcontainer.h
new file mode 100644
index 0000000..01474ee
--- /dev/null
+++ b/kmymoney2/widgets/transactioneditorcontainer.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ transactioneditorcontainer.h
+ ----------
+ begin : Wed Jun 07 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TRANSACTIONEDITORCONTAINER_H
+#define TRANSACTIONEDITORCONTAINER_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qmap.h>
+#include <qstring.h>
+#include <qtable.h>
+class QWidget;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+namespace KMyMoneyRegister { class Transaction; };
+
+typedef enum {
+ ProtectNone = 0,
+ ProtectTransfer,
+ ProtectNonTransfer,
+ ProtectAll
+} ProtectedAction;
+
+class TransactionEditorContainer : public QTable
+{
+public:
+ TransactionEditorContainer(QWidget* parent, const char* name) : QTable(parent, name) {}
+
+ virtual void arrangeEditWidgets(QMap<QString, QWidget*>& editWidgets, KMyMoneyRegister::Transaction* t) = 0;
+ virtual void removeEditWidgets(QMap<QString, QWidget*>& editWidgets) = 0;
+ virtual void tabOrder(QWidgetList& tabOrderWidgets, KMyMoneyRegister::Transaction* t) const = 0;
+ // FIXME remove tabbar
+ // virtual int action(QMap<QString, QWidget*>& editWidgets) const = 0;
+ // virtual void setProtectedAction(QMap<QString, QWidget*>& editWidgets, ProtectedAction action) = 0;
+};
+
+#endif
diff --git a/kmymoney2/widgets/transactionform.cpp b/kmymoney2/widgets/transactionform.cpp
new file mode 100644
index 0000000..7097b6d
--- /dev/null
+++ b/kmymoney2/widgets/transactionform.cpp
@@ -0,0 +1,467 @@
+/***************************************************************************
+ transactionform.cpp
+ -------------------
+ begin : Sun May 14 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qtabbar.h>
+#include <qpalette.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneycategory.h>
+
+#include "transactionform.h"
+#include "../kmymoneyutils.h"
+#include "../kmymoneyglobalsettings.h"
+
+using namespace KMyMoneyTransactionForm;
+
+TabBar::TabBar(QWidget* parent, const char* name) :
+ QTabBar(parent, name),
+ m_signalType(SignalNormal)
+{
+ connect(this, SIGNAL(selected(int)), this, SLOT(slotTabSelected(int)));
+}
+
+TabBar::SignalEmissionE TabBar::setSignalEmission(TabBar::SignalEmissionE type)
+{
+ TabBar::SignalEmissionE _type = m_signalType;
+ m_signalType = type;
+ return _type;
+}
+
+int TabBar::currentTab(void) const
+{
+ QMap<int, int>::const_iterator it;
+ it = m_idMap.find(QTabBar::currentTab());
+ if(it != m_idMap.end())
+ return *it;
+ return -1;
+}
+
+void TabBar::setCurrentTab(int id)
+{
+ if (tab(id)) // there are no tabs in an expense/income ledger
+ if (tab(id)->isEnabled())
+ setCurrentTab(tab(id));
+}
+
+QTab* TabBar::tab(int id) const
+{
+ /* if a QAccel calls setCurrentTab, id will be as set by qt.
+ * however if we call it programmatically, id will
+ * be our own id. We do tell QTab about our id but
+ * in qt3.3 I (woro) am not able to make sure that
+ * QAccel also gets it. See registeritem.h: We defined
+ * new values for our own ids which should lie way
+ * outside of the range that qt uses
+ */
+ QTab *result=QTabBar::tab(id);
+ QMap<int, int>::const_iterator it;
+ for(it = m_idMap.begin(); it != m_idMap.end(); ++it)
+ if(*it == id)
+ result=QTabBar::tab(it.key());
+ return result;
+}
+
+void TabBar::setCurrentTab(QTab* tab)
+{
+ if(m_signalType != SignalNormal)
+ blockSignals(true);
+
+ QTabBar::setCurrentTab(tab);
+
+ if(m_signalType != SignalNormal)
+ blockSignals(false);
+
+ if(m_signalType == SignalAlways)
+ emit selected(tab->identifier());
+}
+
+void TabBar::addTab(QTab* tab, int id)
+{
+ QTabBar::addTab(tab);
+ setIdentifier(tab, id);
+}
+
+void TabBar::setIdentifier(QTab* tab, int newId)
+{
+ m_idMap[tab->identifier()] = newId;
+}
+
+void TransactionForm::enableTabBar(bool b)
+{
+ m_tabBar->setEnabled(b);
+}
+
+void TabBar::slotTabSelected(int id)
+{
+ QMap<int, int>::const_iterator it;
+ it = m_idMap.find(id);
+ if(it != m_idMap.end())
+ emit tabSelected(*it);
+ else
+ emit tabSelected(id);
+}
+
+void TabBar::show(void)
+{
+ // make sure we don't emit a signal when simply showing the widget
+ if(m_signalType != SignalNormal)
+ blockSignals(true);
+
+ QTabBar::show();
+
+ if(m_signalType != SignalNormal)
+ blockSignals(false);
+}
+
+void TabBar::copyTabs(const TabBar* otabbar)
+{
+ // remove all existing tabs
+ while(count()) {
+ removeTab(tabAt(0));
+ }
+ // now create new ones. copy text, icon and identifier
+ for(int i=0; i < otabbar->count(); ++i) {
+ QTab* otab = otabbar->tabAt(i);
+ QTab* ntab = new QTab(otab->text());
+ int nid = QTabBar::addTab(ntab);
+ m_idMap[nid] = otabbar->m_idMap[otab->identifier()];
+ ntab->setEnabled(otab->isEnabled());
+ if(otab->identifier() == otabbar->currentTab())
+ setCurrentTab(ntab);
+ }
+}
+
+TransactionForm::TransactionForm(QWidget *parent, const char *name) :
+ TransactionEditorContainer(parent, name),
+ m_transaction(0),
+ m_tabBar(0)
+{
+ setBackgroundOrigin(QTable::WindowOrigin);
+ setFrameShape( QTable::NoFrame);
+ setShowGrid( false );
+ setSelectionMode( QTable::NoSelection );
+ verticalHeader()->hide();
+ horizontalHeader()->hide();
+ setLeftMargin(0);
+ setTopMargin(0);
+ setReadOnly(true); // display only
+
+ // make sure, that the table is 'invisible' by setting up the right background
+ // keep the original color group for painting the cells though
+ QPalette p = palette();
+ QColorGroup cg = p.active();
+ m_cellColorGroup = cg;
+ cg.setBrush(QColorGroup::Base, cg.brush(QColorGroup::Background));
+ p.setActive(cg);
+ p.setInactive(cg);
+ p.setDisabled(cg);
+ setPalette(p);
+
+ // never show vertical scroll bars
+ setVScrollBarMode(QScrollView::AlwaysOff);
+
+ slotSetTransaction(0);
+}
+
+void TransactionForm::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
+{
+ // the QTable::drawContents() method does not honor the block update flag
+ // so we take care of it here
+ if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
+ return;
+
+ QTable::drawContents(p, cx, cy, cw, ch);
+}
+
+bool TransactionForm::focusNextPrevChild(bool next)
+{
+ return QFrame::focusNextPrevChild(next);
+}
+
+void TransactionForm::clear(void)
+{
+ slotSetTransaction(0);
+}
+
+void TransactionForm::slotSetTransaction(KMyMoneyRegister::Transaction* transaction)
+{
+ m_transaction = transaction;
+
+ bool enabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ if(m_transaction) {
+ // the next call sets up a back pointer to the form and also sets up the col and row span
+ // as well as the tab of the form
+ m_transaction->setupForm(this);
+
+ } else {
+ setNumRows(5);
+ setNumCols(1);
+ }
+
+ kMyMoneyDateInput dateInput(0, "editDate");
+ KMyMoneyCategory category(0, "category", true);
+
+ // extract the maximal sizeHint height
+ int height = QMAX(dateInput.sizeHint().height(), category.sizeHint().height());
+
+ for(int row = 0; row < numRows(); ++row) {
+ if(!transaction || transaction->showRowInForm(row)) {
+ showRow(row);
+ QTable::setRowHeight(row, height);
+ } else
+ hideRow(row);
+ }
+
+ // adjust vertical size of form table
+ height *= numRows();
+ setMaximumHeight(height);
+ setMinimumHeight(height);
+
+ setUpdatesEnabled(enabled);
+
+ // force resizeing of the columns
+ QTimer::singleShot(0, this, SLOT(resize()));
+}
+
+void TransactionForm::paintCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& /* cg */)
+{
+ if(m_transaction) {
+ m_transaction->paintFormCell(painter, row, col, r, selected, m_cellColorGroup);
+ }
+}
+
+TabBar* TransactionForm::tabBar(QWidget* parent)
+{
+ if(!m_tabBar && parent) {
+ // determine the height of the objects in the table
+ // create the tab bar
+ m_tabBar = new TabBar( parent );
+ m_tabBar->setSignalEmission(TabBar::SignalAlways);
+ m_tabBar->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)0, 0, 0, m_tabBar->sizePolicy().hasHeightForWidth() ) );
+ connect(m_tabBar, SIGNAL(tabSelected(int)), this, SLOT(slotActionSelected(int)));
+ }
+ return m_tabBar;
+}
+
+void TransactionForm::slotActionSelected(int id)
+{
+ emit newTransaction(static_cast<KMyMoneyRegister::Action>(id));
+}
+
+void TransactionForm::setupForm(const MyMoneyAccount& acc)
+{
+ // remove all tabs from the tabbar
+ QTab* tab;
+ for(tab = m_tabBar->tabAt(0); tab; tab = m_tabBar->tabAt(0)) {
+ m_tabBar->removeTab(tab);
+ }
+
+ m_tabBar->show();
+
+ // important: one needs to add the new tabs first and then
+ // change the identifier. Otherwise, addTab() will assign
+ // a different value
+ switch(acc.accountType()) {
+ default:
+ tab = new QTab(i18n("&Deposit"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
+ tab = new QTab(i18n("&Transfer"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
+ tab = new QTab(i18n("&Withdrawal"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
+ break;
+
+ case MyMoneyAccount::CreditCard:
+ tab = new QTab(i18n("&Payment"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
+ tab = new QTab(i18n("&Transfer"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
+ tab = new QTab(i18n("&Charge"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
+ break;
+
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Loan:
+ tab = new QTab(i18n("&Decrease"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
+ tab = new QTab(i18n("&Transfer"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
+ tab = new QTab(i18n("&Increase"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
+ break;
+
+ case MyMoneyAccount::Asset:
+ case MyMoneyAccount::AssetLoan:
+ tab = new QTab(i18n("&Increase"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
+ tab = new QTab(i18n("&Transfer"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
+ tab = new QTab(i18n("&Decrease"));
+ m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
+ break;
+
+ case MyMoneyAccount::Income:
+ case MyMoneyAccount::Expense:
+ case MyMoneyAccount::Investment:
+ case MyMoneyAccount::Stock:
+ m_tabBar->hide();
+ break;
+ }
+}
+
+void TransactionForm::resize(void)
+{
+ resize(ValueColumn1);
+}
+
+void TransactionForm::resize(int col)
+{
+ bool enabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ // resize the register
+ int w = visibleWidth();
+ int nc = numCols();
+
+ // check which space we need
+ if(nc >= LabelColumn1 && columnWidth(LabelColumn1))
+ adjustColumn(LabelColumn1);
+ if(nc >= LabelColumn2 && columnWidth(LabelColumn2))
+ adjustColumn(LabelColumn2);
+ if(nc >= ValueColumn2 && columnWidth(ValueColumn2))
+ adjustColumn(ValueColumn2);
+
+ for(int i = 0; i < nc; ++i) {
+ if(i == col)
+ continue;
+
+ w -= columnWidth(i);
+ }
+ if(col < nc && w >= 0)
+ setColumnWidth(col, w);
+
+ setUpdatesEnabled(enabled);
+ updateContents();
+}
+
+// needed to duplicate this here, as the QTable::tableSize method is private :-(
+QSize TransactionForm::tableSize(void) const
+{
+ return QSize(columnPos(numCols()-1) + columnWidth(numCols()-1) + 10,
+ rowPos(numRows()-1) + rowHeight(numRows()-1) + 10);
+}
+
+QSize TransactionForm::sizeHint(void) const
+{
+ // I've taken this from qtable.cpp, QTable::sizeHint()
+ int vmargin = QApplication::reverseLayout() ? rightMargin() : leftMargin();
+ return QSize(tableSize().width() + vmargin + 5, tableSize().height() + topMargin() + 10);
+}
+
+void TransactionForm::adjustColumn(Column col)
+{
+ int w = 0;
+
+ // preset the width of the right value column with the width of
+ // the possible edit widgets so that they fit if they pop up
+ if(col == ValueColumn2) {
+ kMyMoneyDateInput dateInput;
+ kMyMoneyEdit valInput;
+ w = QMAX(dateInput.sizeHint().width(), valInput.sizeHint().width());
+ }
+
+ if(m_transaction) {
+ QString txt;
+ QFontMetrics fontMetrics(KMyMoneyGlobalSettings::listCellFont());
+
+ // scan through the rows
+ for ( int i = numRows()-1; i >= 0; --i ) {
+ int align;
+ m_transaction->formCellText(txt, align, i, static_cast<int>(col), 0);
+ QWidget* cw = cellWidget(i, col);
+ if(cw) {
+ w = QMAX(w, cw->sizeHint().width()+10);
+ }
+ w = QMAX(w, fontMetrics.width(txt)+10);
+ }
+ }
+
+ if(col < numCols())
+ setColumnWidth( col, w );
+}
+
+void TransactionForm::arrangeEditWidgets(QMap<QString, QWidget*>& editWidgets, KMyMoneyRegister::Transaction* t)
+{
+ t->arrangeWidgetsInForm(editWidgets);
+ resize(ValueColumn1);
+}
+
+void TransactionForm::tabOrder(QWidgetList& tabOrderWidgets, KMyMoneyRegister::Transaction* t) const
+{
+ t->tabOrderInForm(tabOrderWidgets);
+}
+
+void TransactionForm::removeEditWidgets(QMap<QString, QWidget*>& editWidgets)
+{
+ QMap<QString, QWidget*>::iterator it;
+ for(it = editWidgets.begin(); it != editWidgets.end(); ) {
+ if((*it)->parentWidget() == this) {
+ editWidgets.remove(it);
+ it = editWidgets.begin();
+ } else
+ ++it;
+ }
+
+ for(int row = 0; row < numRows(); ++row) {
+ for(int col = 0; col < numCols(); ++col) {
+ if(cellWidget(row, col))
+ clearCellWidget(row, col);
+ }
+ }
+ resize(ValueColumn1);
+
+ // delete all remaining edit widgets (e.g. tabbar)
+ for(it = editWidgets.begin(); it != editWidgets.end(); ) {
+ delete (*it); // ->deleteLater();
+ editWidgets.remove(it);
+ it = editWidgets.begin();
+ }
+}
+
+#include "transactionform.moc"
diff --git a/kmymoney2/widgets/transactionform.h b/kmymoney2/widgets/transactionform.h
new file mode 100644
index 0000000..13116da
--- /dev/null
+++ b/kmymoney2/widgets/transactionform.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+ transactionform.h
+ ----------
+ begin : Sun May 14 2006
+ copyright : (C) 2006 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TRANSACTIONFORM_H
+#define TRANSACTIONFORM_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtable.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qpalette.h>
+#include <qwidgetlist.h>
+#include <qtabbar.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyobject.h>
+#include <kmymoney/register.h>
+
+#include "../kmymoneysettings.h"
+
+class MyMoneyObjectContainer;
+
+namespace KMyMoneyTransactionForm {
+
+/**
+ * @author Thomas Baumgart
+ */
+class TabBar : public QTabBar
+{
+ Q_OBJECT
+public:
+ typedef enum {
+ SignalNormal = 0, // standard signal behaviour
+ SignalNever, // don't signal selection of a tab at all
+ SignalAlways // always signal selection of a tab
+ } SignalEmissionE;
+
+ TabBar(QWidget* parent = 0, const char* name = 0);
+ virtual ~TabBar() {}
+
+ SignalEmissionE setSignalEmission(SignalEmissionE type);
+
+ void copyTabs(const TabBar* otabbar);
+
+ void addTab(QTab* tab, int id);
+
+ void setIdentifier(QTab* tab, int newId);
+
+ QTab* tab(int id) const;
+
+ int currentTab(void) const;
+
+public slots:
+ /**
+ * overridden for internal reasons, API not changed
+ */
+ virtual void setCurrentTab( int );
+
+ /**
+ * overridden for internal reasons, API not changed
+ */
+ virtual void setCurrentTab( QTab * );
+
+ /**
+ * overridden for internal reasons, API not changed
+ */
+ virtual void show(void);
+
+protected slots:
+ void slotTabSelected(int id);
+
+signals:
+ void tabSelected(int id);
+
+private:
+ SignalEmissionE m_signalType;
+
+ /**
+ * maps our internal action ids to those used by
+ * qt3. Since it does not seem possible to tell
+ * qt3 to use our ids everywhere (in QAccel) we
+ * need to know which is which
+ */
+ QMap<int, int> m_idMap;
+
+
+};
+
+typedef enum {
+ LabelColumn1 = 0,
+ ValueColumn1,
+ LabelColumn2,
+ ValueColumn2,
+ // insert new values above this line
+ MaxColumns
+} Column;
+
+/**
+ * @author Thomas Baumgart
+ */
+class TransactionForm : public TransactionEditorContainer
+{
+ Q_OBJECT
+public:
+ TransactionForm(QWidget *parent = 0, const char *name = 0);
+ virtual ~TransactionForm() {}
+
+ /**
+ * Override the QTable member function to avoid display of focus
+ */
+ void paintFocus(QPainter* /*p*/, const QRect& /*cr*/ ) {}
+
+ QSize tableSize(void) const;
+ QSize sizeHint(void) const;
+ void adjustColumn(Column col);
+ void clear(void);
+
+ void paintCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& cg);
+
+ void resize(int col);
+
+ void arrangeEditWidgets(QMap<QString, QWidget*>& editWidgets, KMyMoneyRegister::Transaction* t);
+ void removeEditWidgets(QMap<QString, QWidget*>& editWidgets);
+ void tabOrder(QWidgetList& tabOrderWidgets, KMyMoneyRegister::Transaction* t) const;
+
+ /**
+ * reimplemented to prevent normal cell selection behavior
+ */
+ void setCurrentCell(int, int) {}
+
+ TabBar* tabBar(QWidget* parent = 0);
+
+ void setupForm(const MyMoneyAccount& acc);
+
+ void enableTabBar(bool b);
+
+ protected:
+ /**
+ * reimplemented to support QWidget::WState_BlockUpdates
+ */
+ void drawContents(QPainter *p, int cx, int cy, int cw, int ch);
+
+ /**
+ * reimplemented to prevent normal mouse press behavior
+ */
+ void contentsMousePressEvent(QMouseEvent* ev) { ev->ignore(); }
+
+ /**
+ * reimplemented to prevent normal mouse move behavior
+ */
+ void contentsMouseMoveEvent(QMouseEvent* ev) { ev->ignore(); }
+
+ /**
+ * reimplemented to prevent normal mouse release behavior
+ */
+ void contentsMouseReleaseEvent(QMouseEvent* ev) { ev->ignore(); }
+
+ /**
+ * reimplemented to prevent normal mouse double click behavior
+ */
+ void contentsMouseDoubleClickEvent(QMouseEvent* ev) { ev->ignore(); }
+
+ /**
+ * reimplemented to prevent normal keyboard behavior
+ */
+ void keyPressEvent(QKeyEvent* ev) { ev->ignore(); }
+
+ /**
+ * Override logic and use standard QFrame behaviour
+ */
+ bool focusNextPrevChild(bool next);
+
+public slots:
+ void slotSetTransaction(KMyMoneyRegister::Transaction* item);
+
+protected slots:
+ void resize(void);
+
+ /**
+ * Helper method to convert @a int into @a KMyMoneyRegister::Action
+ */
+ void slotActionSelected(int);
+
+signals:
+ /**
+ * This signal is emitted when a user selects a tab. @a id
+ * contains the tab's id (e.g. KMyMoneyRegister::ActionDeposit)
+ */
+ void newTransaction(KMyMoneyRegister::Action id);
+
+protected:
+ KMyMoneyRegister::Transaction* m_transaction;
+ QColorGroup m_cellColorGroup;
+ TabBar* m_tabBar;
+};
+
+
+} // namespace
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/widgets/transactionsortoption.ui b/kmymoney2/widgets/transactionsortoption.ui
new file mode 100644
index 0000000..23de01b
--- /dev/null
+++ b/kmymoney2/widgets/transactionsortoption.ui
@@ -0,0 +1,287 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>TransactionSortOption</class>
+<author>Thomas Baumgart &lt;ipwizard@users.sourceforge.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TransactionSortOption</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>486</width>
+ <height>228</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>TransactionSortOptionDecl</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Sort options</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_availableList</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ <property name="itemsMovable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>67</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_addButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_removeButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>67</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Sort order</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_selectedList</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ <property name="itemsMovable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>67</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_upButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_downButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>67</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_addButton</sender>
+ <signal>clicked()</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>slotAddItem()</slot>
+ </connection>
+ <connection>
+ <sender>m_availableList</sender>
+ <signal>selectionChanged(QListViewItem*)</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>slotAvailableSelected(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_downButton</sender>
+ <signal>clicked()</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>slotDownItem()</slot>
+ </connection>
+ <connection>
+ <sender>m_removeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>slotRemoveItem()</slot>
+ </connection>
+ <connection>
+ <sender>m_selectedList</sender>
+ <signal>selectionChanged(QListViewItem*)</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>slotSelectedSelected(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_upButton</sender>
+ <signal>clicked()</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>slotUpItem()</slot>
+ </connection>
+ <connection>
+ <sender>m_selectedList</sender>
+ <signal>doubleClicked(QListViewItem*)</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>toggleDirection(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_selectedList</sender>
+ <signal>spacePressed(QListViewItem*)</signal>
+ <receiver>TransactionSortOption</receiver>
+ <slot>toggleDirection(QListViewItem*)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">transactionsortoption.ui.h</include>
+</includes>
+<signals>
+ <signal>settingsChanged(const QString&amp;)</signal>
+</signals>
+<slots>
+ <slot>setSettings( const QString &amp; settings )</slot>
+ <slot>toggleDirection( QListViewItem * item )</slot>
+ <slot access="protected" specifier="non virtual">slotAvailableSelected( QListViewItem * item )</slot>
+ <slot access="protected" specifier="non virtual">slotSelectedSelected( QListViewItem * item )</slot>
+ <slot access="protected" specifier="non virtual">slotAddItem( void )</slot>
+ <slot access="protected" specifier="non virtual">slotRemoveItem( void )</slot>
+ <slot access="protected" specifier="non virtual">slotUpItem( void )</slot>
+ <slot access="protected" specifier="non virtual">slotDownItem( void )</slot>
+</slots>
+<functions>
+ <function specifier="non virtual">init()</function>
+ <function access="protected" specifier="non virtual" returnType="QListViewItem *">addEntry( KListView * p, QListViewItem * after, int idx )</function>
+ <function specifier="non virtual" returnType="QString">settings( void ) const</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/widgets/transactionsortoption.ui.h b/kmymoney2/widgets/transactionsortoption.ui.h
new file mode 100644
index 0000000..3784e0b
--- /dev/null
+++ b/kmymoney2/widgets/transactionsortoption.ui.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/register.h>
+#include "sortoptionlistitem.h"
+
+
+void TransactionSortOption::init()
+{
+ KIconLoader* il = KGlobal::iconLoader();
+ m_addButton->setIconSet(QIconSet(il->loadIcon("1rightarrow", KIcon::Small, KIcon::SizeSmall)));
+ m_removeButton->setIconSet(QIconSet(il->loadIcon("1leftarrow", KIcon::Small, KIcon::SizeSmall)));
+ m_upButton->setIconSet(QIconSet(il->loadIcon("1uparrow", KIcon::Small, KIcon::SizeSmall)));
+ m_downButton->setIconSet(QIconSet(il->loadIcon("1downarrow", KIcon::Small, KIcon::SizeSmall)));
+
+ // don't allow sorting of the selected entries
+ m_selectedList->setSortColumn(-1);
+
+ // defaults to "post date, value" sorting
+ // setSettings(QString("1,4"));
+ setSettings(QString());
+
+ QListViewItem* p;
+ if((p = m_availableList->firstChild()) != 0) {
+ m_availableList->setSelected(p, true);
+ }
+}
+
+/**
+ * Setup the two lists according to the elements found in @a list.
+ * If an item is negative, it will show up in the available list,
+ * if positive, it shows up in the selected list.
+ *
+ * Special care is taken about the two values @a EntryDateSort and
+ * @a EntryOrderSort. These two entries cannot (should not) exist
+ * alone. Inside this widget, only the @a EntryOrderSort is used.
+ *
+ * setSettings() takes care of hiding the @a EntryDateSort item and if
+ * it exists in @p settings without @a EntryOrderSort being present, it
+ * will add @a EntryOrderSort.
+ */
+void TransactionSortOption::setSettings(const QString& settings)
+{
+ m_availableList->clear();
+ m_selectedList->clear();
+
+ QStringList list = QStringList::split(',', settings);
+ QMap<int, bool> selectedMap;
+
+ // fill selected list
+ QStringList::const_iterator it_s;
+ QListViewItem* last = 0;
+ int dateSign = 1;
+ for(it_s = list.begin(); it_s != list.end(); ++it_s) {
+ int val = (*it_s).toInt();
+ selectedMap[abs(val)] = true;
+ // skip EntryDateSort but keep sign
+ if(abs(val) == static_cast<int>(KMyMoneyRegister::EntryDateSort)) {
+ dateSign = (val < 0) ? -1 : 1;
+ continue;
+ }
+ last = addEntry(m_selectedList, last, val);
+ }
+
+ // make sure to create EntryOrderSort if missing but required
+ if(selectedMap.find(static_cast<int>(KMyMoneyRegister::EntryDateSort)) != selectedMap.end()
+ && selectedMap.find(static_cast<int>(KMyMoneyRegister::EntryOrderSort)) == selectedMap.end()) {
+ int val = dateSign * static_cast<int>(KMyMoneyRegister::EntryOrderSort);
+ selectedMap[static_cast<int>(KMyMoneyRegister::EntryOrderSort)] = true;
+ last = addEntry(m_selectedList, last, val);
+ }
+
+ // fill available list
+ QMap<int, bool>::const_iterator it_m;
+ for(int i = static_cast<int>(KMyMoneyRegister::PostDateSort);
+ i < static_cast<int>(KMyMoneyRegister::MaxSortFields); ++i) {
+ // Never add EntryDateSort
+ if(i == static_cast<int>(KMyMoneyRegister::EntryDateSort))
+ continue;
+ // Only add those, that are not present in the list of selected items
+ if(selectedMap.find(i) == selectedMap.end()) {
+ int val = i;
+ if(i == static_cast<int>(KMyMoneyRegister::ValueSort))
+ val = -val;
+ addEntry(m_availableList, 0, val);
+ }
+ }
+}
+
+QListViewItem* TransactionSortOption::addEntry( KListView * p, QListViewItem* after, int idx )
+{
+ QString txt = KMyMoneyRegister::sortOrderToText(static_cast<KMyMoneyRegister::TransactionSortField>(abs(idx)));
+ if(txt.isEmpty())
+ txt = "Unknown"; // i18n should be handled in sortOptionToText()
+
+ return new SortOptionListItem(p, after, txt, idx);
+}
+
+void TransactionSortOption::toggleDirection(QListViewItem* item)
+{
+ SortOptionListItem* p = dynamic_cast<SortOptionListItem*>(item);
+ if(p) {
+ p->toggleDirection();
+ emit settingsChanged(settings());
+ }
+}
+
+QString TransactionSortOption::settings( void ) const
+{
+ QString rc;
+ SortOptionListItem* item = dynamic_cast<SortOptionListItem*>(m_selectedList->firstChild());
+ while(item) {
+ int option = KMyMoneyRegister::textToSortOrder(item->text(0));
+ // if we look at the EntryOrderSort option, we have to make
+ // sure, that the EntryDateSort is prepended
+ if(option == KMyMoneyRegister::EntryOrderSort) {
+ rc += QString::number(static_cast<int>(KMyMoneyRegister::EntryDateSort)*item->direction())+",";
+ }
+ rc += QString::number(KMyMoneyRegister::textToSortOrder(item->text(0))*item->direction());
+ item = dynamic_cast<SortOptionListItem*>(item->itemBelow());
+ if(item != 0)
+ rc += ",";
+ }
+ return rc;
+}
+
+void TransactionSortOption::slotAvailableSelected( QListViewItem * item )
+{
+ m_addButton->setEnabled(item != 0);
+ m_removeButton->setDisabled(true);
+ m_upButton->setDisabled(true);
+ m_downButton->setDisabled(true);
+
+ QListViewItem* p = m_selectedList->currentItem();
+ if(p) {
+ m_selectedList->setSelected(p, false);
+ }
+}
+
+void TransactionSortOption::slotSelectedSelected( QListViewItem * item )
+{
+ m_addButton->setDisabled(true);
+ m_removeButton->setEnabled(item != 0);
+ if(item) {
+ m_upButton->setEnabled(item->itemAbove() != 0);
+ m_downButton->setEnabled(item->itemBelow() != 0);
+ } else {
+ m_upButton->setEnabled(false);
+ m_downButton->setEnabled(false);
+ }
+
+ QListViewItem* p = m_availableList->currentItem();
+ if(p) {
+ m_availableList->setSelected(p, false);
+ }
+}
+
+void TransactionSortOption::slotAddItem( void )
+{
+ QListViewItem* item;
+ if((item = m_availableList->currentItem()) != 0) {
+ QListViewItem* next = item->itemBelow();
+ if(!next)
+ next = item->itemAbove();
+ m_availableList->takeItem(item);
+ m_selectedList->insertItem(item);
+ m_addButton->setEnabled(m_availableList->firstChild() != 0);
+ if(next) {
+ m_availableList->setCurrentItem(next);
+ m_availableList->setSelected(next, true);
+ }
+ emit settingsChanged(settings());
+ }
+}
+
+void TransactionSortOption::slotRemoveItem( void )
+{
+ QListViewItem* item;
+ if((item = m_selectedList->currentItem()) != 0) {
+ QListViewItem* next = item->itemBelow();
+ if(!next)
+ next = item->itemAbove();
+ m_selectedList->takeItem(item);
+ m_availableList->insertItem(item);
+ m_removeButton->setEnabled(m_selectedList->firstChild() != 0);
+ if(next) {
+ m_selectedList->setCurrentItem(next);
+ m_selectedList->setSelected(next, true);
+ }
+ emit settingsChanged(settings());
+ }
+}
+
+void TransactionSortOption::slotUpItem( void )
+{
+ QListViewItem* item;
+ if((item = m_selectedList->currentItem()) != 0) {
+ QListViewItem* prev = item->itemAbove();
+ if(prev) {
+ prev->moveItem(item);
+ m_selectedList->setCurrentItem(item);
+ m_selectedList->setSelected(item, true);
+ m_upButton->setEnabled(item->itemAbove() != 0);
+ m_downButton->setEnabled(item->itemBelow() != 0);
+ emit settingsChanged(settings());
+ }
+ }
+}
+
+void TransactionSortOption::slotDownItem( void )
+{
+ QListViewItem* item;
+ if((item = m_selectedList->currentItem()) != 0) {
+ QListViewItem* next = item->itemBelow();
+ if(next) {
+ item->moveItem(next);
+ m_selectedList->setCurrentItem(item);
+ m_selectedList->setSelected(item, true);
+ m_upButton->setEnabled(item->itemAbove() != 0);
+ m_downButton->setEnabled(item->itemBelow() != 0);
+ emit settingsChanged(settings());
+ }
+ }
+}
diff --git a/kmymoney2/wizards/Makefile.am b/kmymoney2/wizards/Makefile.am
new file mode 100644
index 0000000..96afbe6
--- /dev/null
+++ b/kmymoney2/wizards/Makefile.am
@@ -0,0 +1,5 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+
+SUBDIRS = wizardpages newuserwizard newaccountwizard
diff --git a/kmymoney2/wizards/newaccountwizard/Makefile.am b/kmymoney2/wizards/newaccountwizard/Makefile.am
new file mode 100644
index 0000000..42afe78
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LIBRARIES = libnewaccountwizard.a
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I../wizardpages -I.. -I$(top_srcdir) -I.
+
+libnewaccountwizard_a_METASOURCES = AUTO
+
+UI_FILES =
+
+libnewaccountwizard_a_SOURCES = knewaccountwizard.cpp kinstitutionpagedecl.ui kaccounttypepagedecl.ui kbrokeragepagedecl.ui kschedulepagedecl.ui kgeneralloaninfopagedecl.ui kloandetailspagedecl.ui kloanpaymentpagedecl.ui kloanschedulepagedecl.ui kloanpayoutpagedecl.ui khierarchypagedecl.ui kaccountsummarypagedecl.ui
+
+EXTRA_DIST = kinstitutionpagedecl.ui kaccounttypepagedecl.ui kbrokeragepagedecl.ui kschedulepagedecl.ui kgeneralloaninfopagedecl.ui kloandetailspagedecl.ui kloanpaymentpagedecl.ui kloanschedulepagedecl.ui kloanpayoutpagedecl.ui khierarchypagedecl.ui kaccountsummarypagedecl.ui
+
+DISTCLEANFILES= kinstitutionpagedecl.cpp kinstitutionpagedecl.h kaccounttypepagedecl.cpp kaccounttypepagedecl.h kbrokeragepagedecl.cpp kbrokeragepagedecl.h kschedulepagedecl.cpp kschedulepagedecl.h kgeneralloaninfopagedecl.cpp kgeneralloaninfopagedecl.h kloandetailspagedecl.cpp kloandetailspagedecl.h kloanpaymentpagedecl.cpp kloanpaymentpagedecl.h kloanschedulepagedecl.cpp kloanschedulepagedecl.h kloanpayoutpagedecl.cpp kloanpayoutpagedecl.h kaccountsummarypagedecl.cpp khierarchypagedecl.h kaccountsummarypagedecl.h
+
+noinst_HEADERS = knewaccountwizard.h knewaccountwizard_p.h
+
+SUBDIRS =
+
+messages: rc.cpp
diff --git a/kmymoney2/wizards/newaccountwizard/kaccountsummarypagedecl.ui b/kmymoney2/wizards/newaccountwizard/kaccountsummarypagedecl.ui
new file mode 100644
index 0000000..d68bc4b
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kaccountsummarypagedecl.ui
@@ -0,0 +1,80 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAccountSummaryPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAccountSummaryPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>This page summarizes the data you have entered. Press &lt;b&gt;Finish&lt;/b&gt; to create the account, schedules, etc. or use &lt;b&gt;Back&lt;/b&gt; to modify your entries.</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Item</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_dataList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>2</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="hScrollBarMode">
+ <enum>AlwaysOff</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>LastColumn</enum>
+ </property>
+ <property name="fullWidth">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kaccounttypepagedecl.ui b/kmymoney2/wizards/newaccountwizard/kaccounttypepagedecl.ui
new file mode 100644
index 0000000..bb6c5b7
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kaccounttypepagedecl.ui
@@ -0,0 +1,289 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAccountTypePageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAccountTypePageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>555</width>
+ <height>404</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel4</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Enter the name of the account under which it is known within KMyMoney.
+Select the type for the new account. Use the &lt;b&gt;What's this?&lt;/b&gt; feature to see more details about the various account types.
+Enter the date the account was opened and its currency.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KMyMoneySecuritySelector" row="2" column="1">
+ <property name="name">
+ <cstring>m_currencyComboBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select the currency in which this account is denominated.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Opening date</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_openingBalance</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The opening balance is the balance of the account when you start using it with KMyMoney. For new accounts this is usually 0 but for existing accounts this may well differ. Please consult the account statements to figure out this value. The opening balance is to be provided in the currency of the account as selected with the currency button.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>m_conversionLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Conversion rate</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="3" column="1">
+ <property name="name">
+ <cstring>m_openingDate</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The opening date would be the date of the last statement. In case you want to keep track of transactions prior to this date, enter the ending balance and statement date of a prior statement and add all following transactions into KMyMoney.
+&lt;br&gt;
+&lt;i&gt;Note&lt;/i&gt;: If you do not know the exact amount of the opening balance, enter an estimate. You can change this value later before you reconcile this account for the first time.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>m_conversionExample</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Account type</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="5" column="1">
+ <property name="name">
+ <cstring>m_conversionRate</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>For foreign currencies an initial conversion rate needs to be provided. This should be the price of the foreign currency in the base currency on the opening date of the account.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Account name</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Opening balance</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo" row="1" column="1">
+ <property name="name">
+ <cstring>m_typeSelection</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;&lt;b&gt;Checking&lt;/b&gt;
+Use the checking account type to manage activities on your checking account e.g. payments, checks and cash card purchases.&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Savings&lt;/b&gt;
+Use the savings account type to manage activities on your savings account.&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Credit Card&lt;/b&gt;
+Use the credit card account type to manage activities on your credit card.&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Cash&lt;/b&gt;
+
+Use the cash account type to manage activities in your wallet.&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Loan&lt;/b&gt;
+Use the loan account type to manage amortization loans (e.g. mortgages, car loan, money you lend, private loans etc.).&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Investment&lt;/b&gt;
+Use the investment account to manage your stock, mutual fund and other investments.&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Asset&lt;/b&gt;
+Use the asset account type to manage assets (e.g. your house, car or art collection).&lt;/p&gt;
+
+&lt;p&gt;&lt;b&gt;Liability&lt;/b&gt;
+Use the liability account type to manage any type of liability except amortization loans. Use it for taxes you owe or money you borrowed from friends. For amortization loans like mortgages you should create a loan account.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="7" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_preferredAccount</cstring>
+ </property>
+ <property name="text">
+ <string>Preferred account</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Mark this checkbox if the account should be maintained as preferred account</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Selecting the &lt;b&gt;Preferred Account&lt;/b&gt; checkbox will allow preferred access in some dialogs and views of KMyMoney.</string>
+ </property>
+ </widget>
+ <spacer row="2" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>231</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_accountName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter a name under which this account is known within KMyMoney.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="5" column="2">
+ <property name="name">
+ <cstring>m_onlineQuote</cstring>
+ </property>
+ <property name="text">
+ <string>Online quote</string>
+ </property>
+ </widget>
+ <spacer row="5" column="3">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer18</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kbrokeragepagedecl.ui b/kmymoney2/wizards/newaccountwizard/kbrokeragepagedecl.ui
new file mode 100644
index 0000000..bc388a8
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kbrokeragepagedecl.ui
@@ -0,0 +1,172 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KBrokeragePageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KBrokeragePageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>594</width>
+ <height>398</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel14</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Does this investment account have a brokerage account?&lt;p&gt;
+
+&lt;b&gt;Check&lt;/b&gt; the mark if this investment account has an associated account for money that is not invested.&lt;br&gt;
+
+&lt;b&gt;Uncheck&lt;/b&gt; it if you don't use this account for active stock brokerage. You should also uncheck it if this account is not maintained by a bank or broker.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_createBrokerageButton</cstring>
+ </property>
+ <property name="text">
+ <string>Create brokerage account</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_currencyFrame</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Currency</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCurrencySelector" row="0" column="1">
+ <property name="name">
+ <cstring>m_brokerageCurrency</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_accountNumberLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Account number</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_accountNumber</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>m_ibanLabel</cstring>
+ </property>
+ <property name="text">
+ <string>IBAN</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_iban</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer20</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_createBrokerageButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_currencyFrame</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>m_createBrokerageButton</tabstop>
+ <tabstop>m_brokerageCurrency</tabstop>
+ <tabstop>m_accountNumber</tabstop>
+ <tabstop>m_iban</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kgeneralloaninfopagedecl.ui b/kmymoney2/wizards/newaccountwizard/kgeneralloaninfopagedecl.ui
new file mode 100644
index 0000000..db13917
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kgeneralloaninfopagedecl.ui
@@ -0,0 +1,358 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KGeneralLoanInfoPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KGeneralLoanInfoPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>675</width>
+ <height>494</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Please select the required options. Please use the &lt;b&gt;What's this?&lt;/b&gt; feature to see more information about the items.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>What is the type of the loan?</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>I am borrowing money</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>I am lending money</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_loanDirection</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Who is the payee/payer of the loan?</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyPayeeCombo" row="1" column="1">
+ <property name="name">
+ <cstring>m_payee</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the name of the person or bank you owe money or who owes you money.
+
+If the name does not exist within KMyMoney's database, you are asked if you want to create it.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Did you make/receive any payments yet?</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>No</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Yes</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_anyPayments</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Were there any payments for this loan whether they are entered into KMyMoney or not?
+
+Note: Payments made to obtain the loan (e.g. Disagio) are not considered as payments in this context.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Which payments do you want to record?</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>All payments</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Start with this year's payments</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_recordings</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which transactions should be recorded.
+
+&lt;b&gt;All payments&lt;/b&gt; allows you to enter all payments made for this loan.
+
+The option to &lt;b&gt;start from the beginning of the current year&lt;/b&gt; is meant for loans that are active for a longer period of time already and you don't want to enter all transactions of the past.
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Balance before start of recording</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the ending balance found on the statement that is the last one before you want to start recording this loan in KMyMoney.</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_openingBalance</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>You have selected to record only payments from the beginning of this year. Since prior transactions will not be recorded, you need to supply the balance of the loan on January 1st of this year.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Payment frequency</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyFrequencyCombo" row="5" column="1">
+ <property name="name">
+ <cstring>m_paymentFrequency</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Interest Compounding frequency</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyFrequencyCombo" row="6" column="1">
+ <property name="name">
+ <cstring>m_compoundFrequency</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select the frequency with which the interest is compounded. If uncertain, select the same as the payment frequency. Consult your loan contract for details.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Due date of first payment to be recorded</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="7" column="1">
+ <property name="name">
+ <cstring>m_firstPaymentDate</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Depending on the answer to &lt;b&gt;What do you want to record?&lt;/b&gt; this field means the following:&lt;p&gt;
+
+&lt;b&gt;All payments&lt;/b&gt;&lt;br&gt;
+Enter the due date of the very first payment&lt;p&gt;
+
+&lt;b&gt;Start with this year's payments&lt;/b&gt;&lt;br&gt;
+Enter the due date of the first payment in the current year</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="8" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Type of interest rate</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="8" column="1">
+ <item>
+ <property name="text">
+ <string>Fixed</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Variable</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_interestType</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="9" column="0">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Time between interest changes</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="9" column="1">
+ <property name="name">
+ <cstring>layout48</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_interestFrequencyAmountEdit</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>Days</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Weeks</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Months</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Years</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_interestFrequencyUnitEdit</cstring>
+ </property>
+ <property name="currentItem">
+ <number>3</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="10" column="0">
+ <property name="name">
+ <cstring>textLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Next interest change is due</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="10" column="1">
+ <property name="name">
+ <cstring>m_interestChangeDateEdit</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>29</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/khierarchypagedecl.ui b/kmymoney2/wizards/newaccountwizard/khierarchypagedecl.ui
new file mode 100644
index 0000000..00602e4
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/khierarchypagedecl.ui
@@ -0,0 +1,82 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KHierarchyPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KHierarchyPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>674</width>
+ <height>419</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>This page allows you to select the parent account.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_subAccountLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Subaccount of</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyAccountTreeBase">
+ <header location="global">kmymoney/kmymoneyaccounttreebase.h</header>
+ <property name="name">
+ <cstring>m_qlistviewParentAccounts</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer18</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kinstitutionpagedecl.ui b/kmymoney2/wizards/newaccountwizard/kinstitutionpagedecl.ui
new file mode 100644
index 0000000..ee38d48
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kinstitutionpagedecl.ui
@@ -0,0 +1,156 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KInstitutionPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KInstitutionPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>586</width>
+ <height>322</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>If this account is managed by an institution please select the institution from the list. If the institution does not exist yet, please choose the &lt;b&gt;New Institution&lt;/b&gt; button to create it. Otherwise, leave this field empty.
+Enter the account number used by the institution to identify the account.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Institution</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_institutionComboBox</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Select the institution which manages this account or leave empty</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_newInstitutionButton</cstring>
+ </property>
+ <property name="text">
+ <string>New Institution</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Account number</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_accountNumber</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Accounts managed by an institution are usually referenced by a unique number the so called account number. Enter that number here.
+
+KMyMoney currently uses this number only for some online banking functions.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>IBAN</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1" colspan="2">
+ <property name="name">
+ <cstring>m_iban</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the International Bank Account Number into this field</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>You can enter the IBAN (International Bank Account Number) into this field if you know it. Usually, people at your institution can tell you the number or it is printed on your statements.
+
+See also http://en.wikipedia.org/wiki/International_Bank_Account_Number for more information.
+
+KMyMoney keeps this field only for documentation purposes and does not use it otherwise.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>132</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer17</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kloandetailspagedecl.ui b/kmymoney2/wizards/newaccountwizard/kloandetailspagedecl.ui
new file mode 100644
index 0000000..eebb158
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kloandetailspagedecl.ui
@@ -0,0 +1,288 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KLoanDetailsPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KLoanDetailsPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>592</width>
+ <height>434</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Now enter the details for your loan. You can leave one of the fields empty and KMyMoney will calculate it when you press the &lt;b&gt;Calculate&lt;/b&gt; button. Before you can continue with the next page you also need to press &lt;b&gt;Calculate&lt;/b&gt; so that KMyMoney can check the logical correctness of the values you have supplied.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer89</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>70</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>The interest rate gets calculated</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1" rowspan="1" colspan="3">
+ <item>
+ <property name="text">
+ <string>when the payment is received</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>when the payment is due</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_paymentDue</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Loan amount</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="1" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_loanAmount</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the amount of the loan in this field. If you want to calculate this field out of the other parameters, please leave it empty. If the field is marked as required (colored background) you have informed KMyMoney about the fact that there were already some payments towards the loan. In this case, please enter the ending balance of your last statement.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel9</cstring>
+ </property>
+ <property name="text">
+ <string>Interest rate</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_interestRate</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Please enter the interest rate in percent or leave the field empty to calculate it.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel10</cstring>
+ </property>
+ <property name="text">
+ <string>Term</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_termAmount</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Please enter the term of this loan or enter 0 to calculate it. The term is the time that is required to fully repay the loan. This time might be different from the time your loan contract is signed for.</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyFrequencyCombo">
+ <property name="name">
+ <cstring>m_termUnit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel11</cstring>
+ </property>
+ <property name="text">
+ <string>Payment (principal and interest)</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="4" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_paymentAmount</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Please enter the amount you pay for principal and interest or leave the field empty to calculate it.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel12</cstring>
+ </property>
+ <property name="text">
+ <string>Balloon payment</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="5" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_balloonAmount</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Please enter the amount of a final amortization payment or leave the field empty to calculate it.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="6" column="1">
+ <property name="name">
+ <cstring>layout53</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer86</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_calculateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Calculate</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Press this button to calculate/verify your loan details.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Pressing this button calculates a possibly missing parameter for your loan or verifies that the values entered match. If something is not correct you will receive information about it.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer row="6" column="2">
+ <property name="name">
+ <cstring>spacer88_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer87</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>27</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer88</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kloanpaymentpagedecl.ui b/kmymoney2/wizards/newaccountwizard/kloanpaymentpagedecl.ui
new file mode 100644
index 0000000..51ac286
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kloanpaymentpagedecl.ui
@@ -0,0 +1,184 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KLoanPaymentPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KLoanPaymentPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>525</width>
+ <height>373</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Now enter the information required for the periodic loan payments. If your regular payments contains any additional fees, click on the &lt;b&gt;Additional fees&lt;/b&gt; button to enter them.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>63</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Principal + Interest</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>m_basePayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>+</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>m_additionalFeesButton</cstring>
+ </property>
+ <property name="text">
+ <string>Additional fees</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>m_additionalFees</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>= periodical payments</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>m_totalPayment</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>62</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kloanpayoutpagedecl.ui b/kmymoney2/wizards/newaccountwizard/kloanpayoutpagedecl.ui
new file mode 100644
index 0000000..1270efe
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kloanpayoutpagedecl.ui
@@ -0,0 +1,198 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KLoanPayoutPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KLoanPayoutPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>384</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>If this loan is for an asset, such as a car or a house, you can create the asset account now. An asset account represents the total value of an asset. The money from this loan will be transfered into the asset account you create or select.
+If this loan is a 'consumer loan' (money to use however you want), you can use a checking account instead.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_noPayoutTransaction</cstring>
+ </property>
+ <property name="text">
+ <string>Don't create payout transaction</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_payoutDetailFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>m_refinanceLoan</cstring>
+ </property>
+ <property name="text">
+ <string>Refinance existing loan</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this if you are refinancing a loan that already exists in KMyMoney</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Asset Account</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_assetAccount</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="3">
+ <property name="name">
+ <cstring>m_createAssetButton</cstring>
+ </property>
+ <property name="text">
+ <string>Create</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Loan account</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_loanAccount</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Date of payment</string>
+ </property>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer88</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="kMyMoneyDateInput" row="3" column="2">
+ <property name="name">
+ <cstring>m_payoutDate</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer89</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_noPayoutTransaction</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_payoutDetailFrame</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_refinanceLoan</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_assetAccount</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_refinanceLoan</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_loanAccount</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_refinanceLoan</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_createAssetButton</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/kloanschedulepagedecl.ui b/kmymoney2/wizards/newaccountwizard/kloanschedulepagedecl.ui
new file mode 100644
index 0000000..bead410
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kloanschedulepagedecl.ui
@@ -0,0 +1,160 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KLoanSchedulePageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KLoanSchedulePageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>545</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>KMyMoney creates a schedule for this payment and reminds you whenever a payment must be made. Please select the account to/from which payments will be made and the category the interest will be assigned to.&lt;p&gt;
+If you selected to record all payments this date has already been supplied. If you selected to record only this years payments, then the &lt;b&gt;First payment due date&lt;/b&gt; is the date of the first payment made in this year.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout54</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout53</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Interest category</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory" row="0" column="1">
+ <property name="name">
+ <cstring>m_interestCategory</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The category the interest part of the payment will be assigned to. If you borrow money you usually have to pay interest, so this should be an expense category. If you lend the money, you receive the interest. In this case, select an income category here.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Payment account</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory" row="1" column="1">
+ <property name="name">
+ <cstring>m_paymentAccount</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select the account from which you make your periodical payments or where you receive regular payments in case you lend the money. In most cases, this is a checking account.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>First payment due on</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="1">
+ <property name="name">
+ <cstring>layout52</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer89</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_firstPaymentDueDate</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer88</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp b/kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp
new file mode 100644
index 0000000..1bfae86
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp
@@ -0,0 +1,1691 @@
+/***************************************************************************
+ knewaccountwizard.cpp
+ -------------------
+ begin : Tue Sep 25 2006
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <locale.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+#include <qfocusdata.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <klistbox.h>
+#include <klineedit.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneycombo.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kmymoneycurrencyselector.h>
+#include <kmymoney/kmymoneyaccountselector.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/mymoneyfinancialcalculator.h>
+#include <kmymoney/kmymoneychecklistitem.h>
+#include <kmymoney/kmymoneylistviewitem.h>
+#include <kmymoney/kcurrencycalculator.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyglobalsettings.h>
+
+#include "knewaccountwizard.h"
+#include "knewaccountwizard_p.h"
+#include <kmymoney/kguiutils.h>
+
+#include "../../dialogs/ksplittransactiondlg.h"
+#include "../../dialogs/kequitypriceupdatedlg.h"
+#include "../../kmymoney2.h"
+
+using namespace NewAccountWizard;
+
+namespace NewAccountWizard {
+ enum steps {
+ StepInstitution = 1,
+ StepAccount,
+ StepBroker,
+ StepDetails,
+ StepPayments,
+ StepFees,
+ StepSchedule,
+ StepPayout,
+ StepParentAccount,
+ StepFinish
+ };
+};
+NewAccountWizard::Wizard::Wizard(QWidget *parent, const char *name, bool modal, WFlags flags)
+ : KMyMoneyWizard(parent, name, modal, flags)
+{
+ setTitle(i18n("KMyMoney New Account Setup"));
+ addStep(i18n("Institution"));
+ addStep(i18n("Account"));
+ addStep(i18n("Broker"));
+ addStep(i18n("Details"));
+ addStep(i18n("Payments"));
+ addStep(i18n("Fees"));
+ addStep(i18n("Schedule"));
+ addStep(i18n("Payout"));
+ addStep(i18n("Parent Account"));
+ addStep(i18n("Finish"));
+ setStepHidden(StepBroker);
+ setStepHidden(StepSchedule);
+ setStepHidden(StepPayout);
+ setStepHidden(StepDetails);
+ setStepHidden(StepPayments);
+ setStepHidden(StepFees);
+
+ m_institutionPage = new InstitutionPage(this);
+ m_accountTypePage = new AccountTypePage(this);
+ // Investment Pages
+ m_brokeragepage = new BrokeragePage(this);
+ // Credit Card Pages
+ m_schedulePage = new CreditCardSchedulePage(this);
+ // Loan Pages
+ m_generalLoanInfoPage = new GeneralLoanInfoPage(this);
+ m_loanDetailsPage = new LoanDetailsPage(this);
+ m_loanPaymentPage = new LoanPaymentPage(this);
+ m_loanSchedulePage = new LoanSchedulePage(this);
+ m_loanPayoutPage = new LoanPayoutPage(this);
+ // Not a loan page
+ m_hierarchyPage = new HierarchyPage(this);
+ // Finish
+ m_accountSummaryPage = new AccountSummaryPage(this);
+
+ setFirstPage(m_institutionPage);
+}
+
+void NewAccountWizard::Wizard::setAccount(const MyMoneyAccount& acc)
+{
+ m_account = acc;
+ m_accountTypePage->setAccount(m_account);
+}
+
+const MyMoneySecurity& NewAccountWizard::Wizard::currency(void) const
+{
+ return m_accountTypePage->currency();
+}
+
+MyMoneyMoney NewAccountWizard::Wizard::interestRate(void) const
+{
+ return m_loanDetailsPage->m_interestRate->value() / MyMoneyMoney(100,1);
+}
+
+int NewAccountWizard::Wizard::precision(void) const
+{
+ return MyMoneyMoney::denomToPrec(currency().smallestAccountFraction());
+}
+
+const MyMoneyAccount& NewAccountWizard::Wizard::account(void)
+{
+ m_account = MyMoneyAccountLoan();
+ m_account.setName(m_accountTypePage->m_accountName->text());
+ m_account.setOpeningDate(m_accountTypePage->m_openingDate->date());
+ m_account.setAccountType(m_accountTypePage->accountType());
+ m_account.setInstitutionId(m_institutionPage->institution().id());
+ m_account.setNumber(m_institutionPage->m_accountNumber->text());
+ m_account.setValue("IBAN", m_institutionPage->m_iban->text());
+ if(m_accountTypePage->m_preferredAccount->isChecked())
+ m_account.setValue("PreferredAccount", "Yes");
+ else
+ m_account.deletePair("PreferredAccount");
+
+ m_account.setCurrencyId(currency().id());
+ if(m_account.isLoan()) {
+ // in case we lend the money we adjust the account type
+ if(!moneyBorrowed())
+ m_account.setAccountType(MyMoneyAccount::AssetLoan);
+ m_account.setLoanAmount(m_loanDetailsPage->m_loanAmount->value());
+ m_account.setInterestRate(m_account.openingDate(), m_loanDetailsPage->m_interestRate->value());
+ m_account.setInterestCalculation(m_loanDetailsPage->m_paymentDue->currentItem() == 0 ? MyMoneyAccountLoan::paymentReceived : MyMoneyAccountLoan::paymentDue);
+ m_account.setFixedInterestRate(m_generalLoanInfoPage->m_interestType->currentItem() == 0);
+ m_account.setFinalPayment(m_loanDetailsPage->m_balloonAmount->value());
+ m_account.setTerm(m_loanDetailsPage->term());
+ m_account.setPeriodicPayment(m_loanDetailsPage->m_paymentAmount->value());
+ m_account.setPayee(m_generalLoanInfoPage->m_payee->selectedItem());
+ m_account.setInterestCompounding(m_generalLoanInfoPage->m_compoundFrequency->currentItem());
+
+ if(!m_account.fixedInterestRate()) {
+ m_account.setNextInterestChange(m_generalLoanInfoPage->m_interestChangeDateEdit->date());
+ m_account.setInterestChangeFrequency(m_generalLoanInfoPage->m_interestFrequencyAmountEdit->value(), m_generalLoanInfoPage->m_interestFrequencyUnitEdit->currentItem());
+ }
+ }
+ return m_account;
+}
+
+MyMoneyTransaction NewAccountWizard::Wizard::payoutTransaction(void)
+{
+ MyMoneyTransaction t;
+ if(m_account.isLoan() // we're creating a loan
+ && openingBalance().isZero() // and don't have an opening balance
+ && !m_loanPayoutPage->m_noPayoutTransaction->isChecked()) { // and the user wants to have a payout transaction
+ t.setPostDate(m_loanPayoutPage->m_payoutDate->date());
+ t.setCommodity(m_account.currencyId());
+ MyMoneySplit s;
+ s.setAccountId(m_account.id());
+ s.setShares(m_loanDetailsPage->m_loanAmount->value());
+ if(moneyBorrowed())
+ s.setShares(-s.shares());
+ s.setValue(s.shares());
+ t.addSplit(s);
+
+ s.clearId();
+ s.setValue(-s.value());
+ s.setAccountId(m_loanPayoutPage->payoutAccountId());
+ MyMoneyMoney shares;
+ KCurrencyCalculator::setupSplitPrice(shares, t, s, QMap<QString, MyMoneyMoney>(), this);
+ s.setShares(shares);
+ t.addSplit(s);
+ }
+ return t;
+}
+
+const MyMoneyAccount& NewAccountWizard::Wizard::parentAccount(void)
+{
+ return m_accountTypePage->allowsParentAccount()
+ ? m_hierarchyPage->parentAccount()
+ : ( m_accountTypePage->accountType() == MyMoneyAccount::Loan
+ ? m_generalLoanInfoPage->parentAccount()
+ : m_accountTypePage->parentAccount() );
+}
+
+MyMoneyAccount NewAccountWizard::Wizard::brokerageAccount(void) const
+{
+ MyMoneyAccount account;
+ if(m_account.accountType() == MyMoneyAccount::Investment
+ && m_brokeragepage->m_createBrokerageButton->isChecked()) {
+ account.setName(m_account.brokerageName());
+ account.setAccountType(MyMoneyAccount::Checkings);
+ account.setInstitutionId(m_account.institutionId());
+ account.setOpeningDate(m_account.openingDate());
+ account.setCurrencyId(m_brokeragepage->m_brokerageCurrency->security().id());
+ if(m_brokeragepage->m_accountNumber->isEnabled() && !m_brokeragepage->m_accountNumber->text().isEmpty())
+ account.setNumber(m_brokeragepage->m_accountNumber->text());
+ if(m_brokeragepage->m_iban->isEnabled() && !m_brokeragepage->m_iban->text().isEmpty())
+ account.setValue("IBAN", m_brokeragepage->m_iban->text());
+ }
+ return account;
+}
+
+const MyMoneySchedule& NewAccountWizard::Wizard::schedule(void)
+{
+ m_schedule = MyMoneySchedule();
+
+ if(!m_account.id().isEmpty()) {
+ if(m_schedulePage->m_reminderCheckBox->isChecked() && (m_account.accountType() == MyMoneyAccount::CreditCard)) {
+ m_schedule.setName(m_schedulePage->m_name->text());
+ m_schedule.setType(MyMoneySchedule::TYPE_TRANSFER);
+ m_schedule.setPaymentType(static_cast<MyMoneySchedule::paymentTypeE>(m_schedulePage->m_method->currentItem()));
+ m_schedule.setFixed(false);
+ m_schedule.setOccurencePeriod(MyMoneySchedule::OCCUR_MONTHLY);
+ m_schedule.setOccurenceMultiplier(1);
+ MyMoneyTransaction t;
+ MyMoneySplit s;
+ s.setPayeeId(m_schedulePage->m_payee->selectedItem());
+ s.setAccountId(m_schedulePage->m_paymentAccount->selectedItem());
+ s.setMemo(i18n("Credit card payment"));
+ s.setShares(-m_schedulePage->m_amount->value());
+ s.setValue(s.shares());
+ t.addSplit(s);
+
+ s.clearId();
+ s.setAccountId(m_account.id());
+ s.setShares(m_schedulePage->m_amount->value());
+ s.setValue(s.shares());
+ t.addSplit(s);
+
+ // setup the next due date
+ t.setPostDate(m_schedulePage->m_date->date());
+ m_schedule.setTransaction(t);
+
+ } else if(m_account.isLoan()) {
+ m_schedule.setName(i18n("Loan payment for %1").arg(m_accountTypePage->m_accountName->text()));
+ m_schedule.setType(MyMoneySchedule::TYPE_LOANPAYMENT);
+ if(moneyBorrowed())
+ m_schedule.setPaymentType(MyMoneySchedule::STYPE_DIRECTDEBIT);
+ else
+ m_schedule.setPaymentType(MyMoneySchedule::STYPE_DIRECTDEPOSIT);
+
+ m_schedule.setFixed(true);
+ m_schedule.setOccurence(m_generalLoanInfoPage->m_paymentFrequency->currentItem());
+
+ MyMoneyTransaction t;
+ MyMoneySplit s;
+ // payment split
+ s.setPayeeId(m_generalLoanInfoPage->m_payee->selectedItem());
+ s.setAccountId(m_loanSchedulePage->m_paymentAccount->selectedItem());
+ s.setMemo(i18n("Loan payment"));
+ if(moneyBorrowed()) {
+ s.setShares(-(m_loanPaymentPage->basePayment() + m_loanPaymentPage->additionalFees()));
+ } else {
+ s.setShares(m_loanPaymentPage->basePayment() + m_loanPaymentPage->additionalFees());
+ }
+ s.setValue(s.shares());
+ t.addSplit(s);
+
+ // principal split
+ s.clearId();
+ s.setAccountId(m_account.id());
+ s.setShares(MyMoneyMoney::autoCalc);
+ s.setValue(MyMoneyMoney::autoCalc);
+ s.setMemo(i18n("Amortization"));
+ s.setAction(MyMoneySplit::ActionAmortization);
+ t.addSplit(s);
+
+ // interest split
+ s.clearId();
+ s.setAccountId(m_loanSchedulePage->m_interestCategory->selectedItem());
+ s.setShares(MyMoneyMoney::autoCalc);
+ s.setValue(MyMoneyMoney::autoCalc);
+ s.setMemo(i18n("Interest"));
+ s.setAction(MyMoneySplit::ActionInterest);
+ t.addSplit(s);
+
+ // additional fee splits
+ QValueList<MyMoneySplit> additionalSplits;
+ m_loanPaymentPage->additionalFeesSplits(additionalSplits);
+ QValueList<MyMoneySplit>::const_iterator it;
+ MyMoneyMoney factor(moneyBorrowed() ? 1 : -1, 1);
+
+ for(it = additionalSplits.begin(); it != additionalSplits.end(); ++it) {
+ s = (*it);
+ s.clearId();
+ s.setShares(s.shares() * factor);
+ s.setValue(s.value() * factor);
+ t.addSplit(s);
+ }
+
+ // setup the next due date
+ t.setPostDate(m_loanSchedulePage->firstPaymentDueDate());
+ m_schedule.setTransaction(t);
+ }
+ }
+ return m_schedule;
+}
+
+MyMoneyMoney NewAccountWizard::Wizard::openingBalance(void) const
+{
+ // equity accounts don't have an opening balance
+ if(m_accountTypePage->accountType() == MyMoneyAccount::Equity)
+ return MyMoneyMoney();
+
+ if(m_accountTypePage->accountType() == MyMoneyAccount::Loan) {
+ if(m_generalLoanInfoPage->recordAllPayments())
+ return MyMoneyMoney(0, 1);
+ if(moneyBorrowed())
+ return -(m_generalLoanInfoPage->m_openingBalance->value());
+ return m_generalLoanInfoPage->m_openingBalance->value();
+ }
+ return m_accountTypePage->m_openingBalance->value();
+}
+
+MyMoneyPrice NewAccountWizard::Wizard::conversionRate(void) const
+{
+ if(MyMoneyFile::instance()->baseCurrency().id() == m_accountTypePage->m_currencyComboBox->security().id())
+ return MyMoneyPrice(MyMoneyFile::instance()->baseCurrency().id(),
+ m_accountTypePage->m_currencyComboBox->security().id(),
+ m_accountTypePage->m_openingDate->date(),
+ MyMoneyMoney(1,1),
+ i18n("User"));
+ return MyMoneyPrice(MyMoneyFile::instance()->baseCurrency().id(),
+ m_accountTypePage->m_currencyComboBox->security().id(),
+ m_accountTypePage->m_openingDate->date(),
+ m_accountTypePage->m_conversionRate->value(),
+ i18n("User"));
+}
+
+bool NewAccountWizard::Wizard::moneyBorrowed(void) const
+{
+ return m_generalLoanInfoPage->m_loanDirection->currentItem() == 0;
+}
+
+class NewAccountWizard::InstitutionPage::Private
+{
+public:
+ QValueList<MyMoneyInstitution> m_list;
+};
+
+InstitutionPage::InstitutionPage(Wizard* wizard, const char* name) :
+ KInstitutionPageDecl(wizard),
+ WizardPage<Wizard>(StepInstitution, this, wizard, name),
+ d(new Private())
+{
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+ connect(m_newInstitutionButton, SIGNAL(clicked()), this, SLOT(slotNewInstitution()));
+ connect(m_institutionComboBox, SIGNAL(activated(int)), this, SLOT(slotSelectInstitution(int)));
+
+ slotLoadWidgets();
+ m_institutionComboBox->setCurrentItem(0);
+ slotSelectInstitution(0);
+}
+
+InstitutionPage::~InstitutionPage()
+{
+ delete d;
+}
+
+void InstitutionPage::slotLoadWidgets(void)
+{
+ m_institutionComboBox->clear();
+
+ d->m_list.clear();
+ MyMoneyFile::instance()->institutionList(d->m_list);
+ qHeapSort(d->m_list);
+
+ QValueList<MyMoneyInstitution>::const_iterator it_l;
+ m_institutionComboBox->insertItem("");
+ for(it_l = d->m_list.begin(); it_l != d->m_list.end(); ++it_l) {
+ m_institutionComboBox->insertItem((*it_l).name());
+ }
+}
+
+void InstitutionPage::slotNewInstitution(void)
+{
+ MyMoneyInstitution institution;
+
+ emit m_wizard->createInstitution(institution);
+
+ if(!institution.id().isEmpty()) {
+ QValueList<MyMoneyInstitution>::const_iterator it_l;
+ int i = 0;
+ for(it_l = d->m_list.begin(); it_l != d->m_list.end(); ++it_l) {
+ if((*it_l).id() == institution.id()) {
+ // select the item and remember that the very first one is the empty item
+ m_institutionComboBox->setCurrentItem(i+1);
+ slotSelectInstitution(i+1);
+ m_accountNumber->setFocus();
+ break;
+ }
+ ++i;
+ }
+ }
+}
+
+void InstitutionPage::slotSelectInstitution(int id)
+{
+ m_accountNumber->setEnabled(id != 0);
+ m_iban->setEnabled(id != 0);
+}
+
+const MyMoneyInstitution& InstitutionPage::institution(void) const
+{
+ static MyMoneyInstitution emptyInstitution;
+ if(m_institutionComboBox->currentItem() == 0)
+ return emptyInstitution;
+
+ return d->m_list[m_institutionComboBox->currentItem()-1];
+}
+
+KMyMoneyWizardPage* InstitutionPage::nextPage(void) const
+{
+ return m_wizard->m_accountTypePage;
+}
+
+AccountTypePage::AccountTypePage(Wizard* wizard, const char* name) :
+ KAccountTypePageDecl(wizard),
+ WizardPage<Wizard>(StepAccount, this, wizard, name),
+ m_showPriceWarning(true)
+{
+ m_typeSelection->insertItem(i18n("Checking"), MyMoneyAccount::Checkings);
+ m_typeSelection->insertItem(i18n("Savings"), MyMoneyAccount::Savings);
+ m_typeSelection->insertItem(i18n("Credit Card"), MyMoneyAccount::CreditCard);
+ m_typeSelection->insertItem(i18n("Cash"), MyMoneyAccount::Cash);
+ m_typeSelection->insertItem(i18n("Loan"), MyMoneyAccount::Loan);
+ m_typeSelection->insertItem(i18n("Investment"), MyMoneyAccount::Investment);
+ m_typeSelection->insertItem(i18n("Asset"), MyMoneyAccount::Asset);
+ m_typeSelection->insertItem(i18n("Liability"), MyMoneyAccount::Liability);
+ if(KMyMoneyGlobalSettings::expertMode()) {
+ m_typeSelection->insertItem(i18n("Equity"), MyMoneyAccount::Equity);
+ }
+
+ m_typeSelection->setCurrentItem(MyMoneyAccount::Checkings);
+
+ m_currencyComboBox->setSecurity(MyMoneyFile::instance()->baseCurrency());
+
+ m_mandatoryGroup->add(m_accountName);
+ m_mandatoryGroup->add(m_conversionRate->lineedit());
+
+ m_conversionRate->setPrecision(KMyMoneyGlobalSettings::pricePrecision());
+ m_conversionRate->setValue(MyMoneyMoney(1,1));
+ slotUpdateCurrency();
+
+ connect(m_typeSelection, SIGNAL(itemSelected(int)), this, SLOT(slotUpdateType(int)));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+ connect(m_currencyComboBox, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrency()));
+ connect(m_conversionRate, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateConversionRate(const QString&)));
+ connect(m_conversionRate, SIGNAL(valueChanged(const QString&)), this, SLOT(slotPriceWarning()));
+ connect(m_onlineQuote, SIGNAL(clicked()), this, SLOT(slotGetOnlineQuote()));
+}
+
+void AccountTypePage::slotUpdateType(int i)
+{
+ hideShowPages(static_cast<MyMoneyAccount::accountTypeE> (i));
+ m_openingBalance->setDisabled(static_cast<MyMoneyAccount::accountTypeE> (i) == MyMoneyAccount::Equity);
+}
+
+void AccountTypePage::hideShowPages(MyMoneyAccount::accountTypeE accountType) const
+{
+ bool hideSchedulePage = (accountType != MyMoneyAccount::CreditCard)
+ && (accountType != MyMoneyAccount::Loan);
+ bool hideLoanPage = (accountType != MyMoneyAccount::Loan);
+ m_wizard->setStepHidden(StepDetails, hideLoanPage);
+ m_wizard->setStepHidden(StepPayments, hideLoanPage);
+ m_wizard->setStepHidden(StepFees, hideLoanPage);
+ m_wizard->setStepHidden(StepSchedule, hideSchedulePage);
+ m_wizard->setStepHidden(StepPayout, (accountType != MyMoneyAccount::Loan));
+ m_wizard->setStepHidden(StepBroker, accountType != MyMoneyAccount::Investment);
+ m_wizard->setStepHidden(StepParentAccount, accountType == MyMoneyAccount::Loan);
+ // Force an update of the steps in case the list has changed
+ m_wizard->reselectStep();
+};
+
+KMyMoneyWizardPage* AccountTypePage::nextPage(void) const
+{
+ if(accountType() == MyMoneyAccount::Loan)
+ return m_wizard->m_generalLoanInfoPage;
+ if(accountType() == MyMoneyAccount::CreditCard)
+ return m_wizard->m_schedulePage;
+ if(accountType() == MyMoneyAccount::Investment)
+ return m_wizard->m_brokeragepage;
+ return m_wizard->m_hierarchyPage;
+}
+
+void AccountTypePage::slotUpdateCurrency(void)
+{
+ MyMoneyAccount acc;
+ acc.setAccountType(accountType());
+
+ m_openingBalance->setPrecision(MyMoneyMoney::denomToPrec(acc.fraction(currency())));
+
+ bool show = m_currencyComboBox->security().id() != MyMoneyFile::instance()->baseCurrency().id();
+ m_conversionLabel->setShown(show);
+ m_conversionRate->setShown(show);
+ m_conversionExample->setShown(show);
+ m_onlineQuote->setShown(show);
+ m_conversionRate->setEnabled(show); // make sure to include/exclude in mandatoryGroup
+ m_mandatoryGroup->changed();
+ slotUpdateConversionRate(m_conversionRate->lineedit()->text());
+}
+
+void AccountTypePage::slotGetOnlineQuote(void)
+{
+ QString id = MyMoneyFile::instance()->baseCurrency().id()+" "+m_currencyComboBox->security().id();
+ KEquityPriceUpdateDlg dlg(this, id);
+ if(dlg.exec() == QDialog::Accepted) {
+ MyMoneyPrice price = dlg.price(id);
+ if(price.isValid()) {
+ m_conversionRate->setValue(price.rate(m_currencyComboBox->security().id()));
+ if(price.date() != m_openingDate->date()) {
+ priceWarning(true);
+ }
+ }
+ }
+}
+
+void AccountTypePage::slotPriceWarning(void)
+{
+ priceWarning(false);
+}
+
+void AccountTypePage::priceWarning(bool always)
+{
+ if(m_showPriceWarning || always) {
+ KMessageBox::information(this, i18n("Please make sure to enter the correct conversion for the selected opening date. If you requested an online quote it might be provided for a different date."), i18n("Check date"));
+ }
+ m_showPriceWarning = false;
+}
+
+void AccountTypePage::slotUpdateConversionRate(const QString& txt)
+{
+ m_conversionExample->setText(i18n("1 %1 equals %2").
+ arg(MyMoneyFile::instance()->baseCurrency().tradingSymbol()).
+ arg(MyMoneyMoney(txt).formatMoney(m_currencyComboBox->security().tradingSymbol(), KMyMoneyGlobalSettings::pricePrecision())));
+}
+
+void AccountTypePage::slotLoadWidgets(void)
+{
+ m_currencyComboBox->update(QString("x"));
+}
+
+bool AccountTypePage::isComplete(void) const
+{
+ // check that the conversion rate is positive if enabled
+ bool rc = !m_conversionRate->isVisible() || (!m_conversionRate->value().isZero() && !m_conversionRate->value().isNegative());
+ if(!rc) {
+ QToolTip::add(m_wizard->m_nextButton, i18n("Conversion rate is not positive"));
+
+ } else {
+ rc = KMyMoneyWizardPage::isComplete();
+
+ if(!rc) {
+ QToolTip::add(m_wizard->m_nextButton, i18n("No account name supplied"));
+ }
+ }
+ hideShowPages(accountType());
+ return rc;
+}
+
+MyMoneyAccount::accountTypeE AccountTypePage::accountType(void) const
+{
+ return static_cast<MyMoneyAccount::accountTypeE>(m_typeSelection->currentItem());
+}
+
+const MyMoneySecurity& AccountTypePage::currency(void) const
+{
+ return m_currencyComboBox->security();
+}
+
+void AccountTypePage::setAccount(const MyMoneyAccount& acc)
+{
+ m_typeSelection->setCurrentItem(acc.accountType());
+ m_openingDate->setDate(acc.openingDate());
+ m_accountName->setText(acc.name());
+}
+
+const MyMoneyAccount& AccountTypePage::parentAccount(void)
+{
+ switch(accountType()) {
+ case MyMoneyAccount::CreditCard:
+ case MyMoneyAccount::Liability:
+ case MyMoneyAccount::Loan: // Can be either but we return liability here
+ return MyMoneyFile::instance()->liability();
+ break;
+ case MyMoneyAccount::Equity:
+ return MyMoneyFile::instance()->equity();
+ default:
+ break;
+ }
+ return MyMoneyFile::instance()->asset();
+}
+
+bool AccountTypePage::allowsParentAccount(void) const
+{
+ return accountType() != MyMoneyAccount::Loan;
+}
+
+BrokeragePage::BrokeragePage(Wizard* wizard, const char* name) :
+ KBrokeragePageDecl(wizard),
+ WizardPage<Wizard>(StepBroker, this, wizard, name)
+{
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+}
+
+void BrokeragePage::slotLoadWidgets(void)
+{
+ m_brokerageCurrency->update(QString("x"));
+}
+
+void BrokeragePage::enterPage(void)
+{
+ // assign the currency of the investment account to the
+ // brokerage account if nothing else has ever been selected
+ if(m_brokerageCurrency->security().id().isEmpty()) {
+ m_brokerageCurrency->setSecurity(m_wizard->m_accountTypePage->m_currencyComboBox->security());
+ }
+
+ // check if the institution relevant fields should be enabled or not
+ bool enabled = m_wizard->m_institutionPage->m_accountNumber->isEnabled();
+ m_accountNumberLabel->setEnabled(enabled);
+ m_accountNumber->setEnabled(enabled);
+ m_ibanLabel->setEnabled(enabled);
+ m_iban->setEnabled(enabled);
+}
+
+KMyMoneyWizardPage* BrokeragePage::nextPage(void) const
+{
+ return m_wizard->m_hierarchyPage;
+}
+
+CreditCardSchedulePage::CreditCardSchedulePage(Wizard* wizard, const char* name) :
+ KSchedulePageDecl(wizard),
+ WizardPage<Wizard>(StepSchedule, this, wizard, name)
+{
+ m_mandatoryGroup->add(m_name);
+ m_mandatoryGroup->add(m_payee);
+ m_mandatoryGroup->add(m_amount->lineedit());
+ m_mandatoryGroup->add(m_paymentAccount);
+ connect(m_paymentAccount, SIGNAL(itemSelected(const QString&)), object(), SIGNAL(completeStateChanged()));
+ connect(m_payee, SIGNAL(itemSelected(const QString&)), object(), SIGNAL(completeStateChanged()));
+ connect(m_date, SIGNAL(dateChanged(const QDate&)), object(), SIGNAL(completeStateChanged()));
+
+ connect(m_payee, SIGNAL(createItem(const QString&, QString&)), wizard, SIGNAL(createPayee(const QString&, QString&)));
+
+ m_reminderCheckBox->setChecked(true);
+ connect(m_reminderCheckBox, SIGNAL(toggled(bool)), object(), SIGNAL(completeStateChanged()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+
+ m_method->insertItem(i18n("Write check"), MyMoneySchedule::STYPE_WRITECHEQUE);
+#if 0
+ m_method->insertItem(i18n("Direct debit"), MyMoneySchedule::STYPE_DIRECTDEBIT);
+ m_method->insertItem(i18n("Bank transfer"), MyMoneySchedule::STYPE_BANKTRANSFER);
+#endif
+ m_method->insertItem(i18n("Standing order"), MyMoneySchedule::STYPE_STANDINGORDER);
+ m_method->insertItem(i18n("Manual deposit"), MyMoneySchedule::STYPE_MANUALDEPOSIT);
+ m_method->insertItem(i18n("Direct deposit"), MyMoneySchedule::STYPE_DIRECTDEPOSIT);
+ m_method->insertItem(i18n("Other"), MyMoneySchedule::STYPE_OTHER);
+ m_method->setCurrentItem(MyMoneySchedule::STYPE_DIRECTDEBIT);
+
+ slotLoadWidgets();
+}
+
+void CreditCardSchedulePage::enterPage(void)
+{
+ if(m_name->text().isEmpty())
+ m_name->setText(i18n("CreditCard %1 monthly payment").arg(m_wizard->m_accountTypePage->m_accountName->text()));
+}
+
+bool CreditCardSchedulePage::isComplete(void) const
+{
+ bool rc = true;
+ QString msg = i18n("Finish entry and create account");
+ if(m_reminderCheckBox->isChecked()) {
+ msg = i18n("Finish entry and create account and schedule");
+ if(m_date->date() < m_wizard->m_accountTypePage->m_openingDate->date()) {
+ rc = false;
+ msg = i18n("Next due date is prior to opening date");
+ }
+ if(m_paymentAccount->selectedItem().isEmpty()) {
+ rc = false;
+ msg = i18n("No account selected");
+ }
+ if(m_amount->lineedit()->text().isEmpty()) {
+ rc = false;
+ msg = i18n("No amount for payment selected");
+ }
+ if(m_payee->selectedItem().isEmpty()) {
+ rc = false;
+ msg = i18n("No payee for payment selected");
+ }
+ if(m_name->text().isEmpty()) {
+ rc = false;
+ msg = i18n("No name assigned for schedule");
+ }
+ }
+ QToolTip::add(m_wizard->m_finishButton, msg);
+
+ return rc;
+}
+
+void CreditCardSchedulePage::slotLoadWidgets(void)
+{
+ AccountSet set;
+ set.addAccountGroup(MyMoneyAccount::Asset);
+ set.load(m_paymentAccount->selector());
+
+ m_payee->loadPayees(MyMoneyFile::instance()->payeeList());
+}
+
+KMyMoneyWizardPage* CreditCardSchedulePage::nextPage(void) const
+{
+ return m_wizard->m_hierarchyPage;
+}
+
+GeneralLoanInfoPage::GeneralLoanInfoPage(Wizard* wizard, const char* name) :
+ KGeneralLoanInfoPageDecl(wizard),
+ WizardPage<Wizard>(StepDetails, this, wizard, name),
+ m_firstTime(true)
+{
+ m_mandatoryGroup->add(m_payee);
+
+ // remove the unsupported payment and compounding frequencies and setup default
+ m_paymentFrequency->removeItem(MyMoneySchedule::OCCUR_ONCE);
+ m_paymentFrequency->removeItem(MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+ m_paymentFrequency->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY);
+ m_compoundFrequency->removeItem(MyMoneySchedule::OCCUR_ONCE);
+ m_compoundFrequency->removeItem(MyMoneySchedule::OCCUR_EVERYOTHERYEAR);
+ m_compoundFrequency->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY);
+
+ slotLoadWidgets();
+
+ connect(m_payee, SIGNAL(createItem(const QString&, QString&)), wizard, SIGNAL(createPayee(const QString&, QString&)));
+ connect(m_anyPayments, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged()));
+ connect(m_recordings, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged()));
+
+ connect(m_interestType, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged()));
+ connect(m_interestChangeDateEdit, SIGNAL(dateChanged(const QDate&)), object(), SIGNAL(completeStateChanged()));
+ connect(m_openingBalance, SIGNAL(textChanged(const QString&)), object(), SIGNAL(completeStateChanged()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+}
+
+KMyMoneyWizardPage* GeneralLoanInfoPage::nextPage(void) const
+{
+ return m_wizard->m_loanDetailsPage;
+}
+
+bool GeneralLoanInfoPage::recordAllPayments(void) const
+{
+ bool rc = true; // all payments
+ if(m_recordings->isEnabled()) {
+ if(m_recordings->currentItem() != 0)
+ rc = false;
+ }
+ return rc;
+}
+
+void GeneralLoanInfoPage::enterPage(void)
+{
+ if(m_firstTime) {
+ // setup default dates to last of this month and one year on top
+ QDate firstDay(QDate::currentDate().year(), QDate::currentDate().month(), 1);
+ m_firstPaymentDate->setDate(firstDay.addMonths(1).addDays(-1));
+ m_interestChangeDateEdit->setDate(m_firstPaymentDate->date().addYears(1));;
+ m_firstTime = false;
+ }
+}
+
+bool GeneralLoanInfoPage::isComplete(void) const
+{
+ m_wizard->setStepHidden(StepPayout, !m_wizard->openingBalance().isZero());
+ bool rc = KMyMoneyWizardPage::isComplete();
+ if(!rc) {
+ QToolTip::add(m_wizard->m_nextButton, i18n("No payee supplied"));
+ }
+
+ // fixup availability of items on this page
+ m_recordings->setDisabled(m_anyPayments->currentItem() == 0);
+
+ m_interestFrequencyAmountEdit->setDisabled(m_interestType->currentItem() == 0);
+ m_interestFrequencyUnitEdit->setDisabled(m_interestType->currentItem() == 0);
+ m_interestChangeDateEdit->setDisabled(m_interestType->currentItem() == 0);
+
+ m_openingBalance->setDisabled(recordAllPayments());
+
+ if(m_openingBalance->isEnabled() && m_openingBalance->lineedit()->text().length() == 0) {
+ rc = false;
+ QToolTip::add(m_wizard->m_nextButton, i18n("No opening balance supplied"));
+ }
+
+ if(rc
+ && (m_interestType->currentItem() != 0)
+ && (m_interestChangeDateEdit->date() <= m_firstPaymentDate->date())) {
+ rc = false;
+ QToolTip::add(m_wizard->m_nextButton, i18n("An interest change can only happen after the first payment"));
+ }
+ return rc;
+}
+
+const MyMoneyAccount& GeneralLoanInfoPage::parentAccount(void)
+{
+ return ( m_loanDirection->currentItem() == 0 )
+ ? MyMoneyFile::instance()->liability()
+ : MyMoneyFile::instance()->asset();
+}
+
+void GeneralLoanInfoPage::slotLoadWidgets(void)
+{
+ m_payee->loadPayees(MyMoneyFile::instance()->payeeList());
+}
+
+LoanDetailsPage::LoanDetailsPage(Wizard* wizard, const char* name) :
+ KLoanDetailsPageDecl(wizard),
+ WizardPage<Wizard>(StepPayments, this, wizard, name),
+ m_needCalculate(true)
+{
+ // force the balloon payment to zero (default)
+ m_balloonAmount->setValue(MyMoneyMoney());
+ // allow any precision for the interest rate
+ m_interestRate->setPrecision(-1);
+
+ connect(m_paymentDue, SIGNAL(activated(int)), this, SLOT(slotValuesChanged()));
+
+ connect(m_termAmount, SIGNAL(valueChanged(int)), this, SLOT(slotValuesChanged()));
+ connect(m_termUnit, SIGNAL(highlighted(int)), this, SLOT(slotValuesChanged()));
+ connect(m_loanAmount, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged()));
+ connect(m_interestRate, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged()));
+ connect(m_paymentAmount, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged()));
+ connect(m_balloonAmount, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged()));
+
+ connect(m_calculateButton, SIGNAL(clicked()), this, SLOT(slotCalculate()));
+}
+
+void LoanDetailsPage::enterPage(void)
+{
+ // we need to remove a bunch of entries of the payment frequencies
+ m_termUnit->clear();
+
+ m_mandatoryGroup->clear();
+ if(!m_wizard->openingBalance().isZero()) {
+ m_mandatoryGroup->add(m_loanAmount->lineedit());
+ if(m_loanAmount->lineedit()->text().length() == 0) {
+ m_loanAmount->setValue(m_wizard->openingBalance().abs());
+ }
+ }
+
+ switch(m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentItem()) {
+ default:
+ m_termUnit->insertItem(i18n("Payments"), MyMoneySchedule::OCCUR_ONCE);
+ m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_ONCE);
+ break;
+ case MyMoneySchedule::OCCUR_MONTHLY:
+ m_termUnit->insertItem(i18n("Months"), MyMoneySchedule::OCCUR_MONTHLY);
+ m_termUnit->insertItem(i18n("Years"), MyMoneySchedule::OCCUR_YEARLY);
+ m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY);
+ break;
+ case MyMoneySchedule::OCCUR_YEARLY:
+ m_termUnit->insertItem(i18n("Years"), MyMoneySchedule::OCCUR_YEARLY);
+ m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_YEARLY);
+ break;
+ }
+}
+
+void LoanDetailsPage::slotValuesChanged(void)
+{
+ m_needCalculate = true;
+ m_wizard->completeStateChanged();
+}
+
+void LoanDetailsPage::slotCalculate(void)
+{
+ MyMoneyFinancialCalculator calc;
+ long double val;
+ int PF, CF;
+ QString result;
+ bool moneyBorrowed = m_wizard->moneyBorrowed();
+ bool moneyLend = !moneyBorrowed;
+
+ // FIXME: for now, we only support interest calculation at the end of the period
+ calc.setBep();
+ // FIXME: for now, we only support periodic compounding
+ calc.setDisc();
+
+ PF = m_wizard->m_generalLoanInfoPage->m_paymentFrequency->eventsPerYear();
+ CF = m_wizard->m_generalLoanInfoPage->m_compoundFrequency->eventsPerYear();
+
+ if(PF == 0 || CF == 0)
+ return;
+
+ calc.setPF(PF);
+ calc.setCF(CF);
+
+
+ if(!m_loanAmount->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_loanAmount->value().abs().toDouble());
+ if(moneyBorrowed)
+ val = -val;
+ calc.setPv(val);
+ }
+
+ if(!m_interestRate->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_interestRate->value().abs().toDouble());
+ calc.setIr(val);
+ }
+
+ if(!m_paymentAmount->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_paymentAmount->value().abs().toDouble());
+ if(moneyLend)
+ val = -val;
+ calc.setPmt(val);
+ }
+
+ if(!m_balloonAmount->lineedit()->text().isEmpty()) {
+ val = static_cast<long double> (m_balloonAmount->value().abs().toDouble());
+ if(moneyLend)
+ val = -val;
+ calc.setFv(val);
+ }
+
+ if(m_termAmount->value() != 0) {
+ calc.setNpp(static_cast<long double>(term()));
+ }
+
+ // setup of parameters is done, now do the calculation
+ try {
+ if(m_loanAmount->lineedit()->text().isEmpty()) {
+ // calculate the amount of the loan out of the other information
+ val = calc.presentValue();
+ m_loanAmount->loadText(MyMoneyMoney(static_cast<double>(val)).abs().formatMoney("", m_wizard->precision()));
+ result = i18n("KMyMoney has calculated the amount of the loan as %1.")
+ .arg(m_loanAmount->lineedit()->text());
+
+ } else if(m_interestRate->lineedit()->text().isEmpty()) {
+ // calculate the interest rate out of the other information
+ val = calc.interestRate();
+ m_interestRate->loadText(MyMoneyMoney(static_cast<double>(val)).abs().formatMoney("", 3));
+ result = i18n("KMyMoney has calculated the interest rate to %1%.")
+ .arg(m_interestRate->lineedit()->text());
+
+ } else if(m_paymentAmount->lineedit()->text().isEmpty()) {
+ // calculate the periodical amount of the payment out of the other information
+ val = calc.payment();
+ m_paymentAmount->setValue(MyMoneyMoney(static_cast<double>(val)).abs());
+ // reset payment as it might have changed due to rounding
+ val = static_cast<long double> (m_paymentAmount->value().abs().toDouble());
+ if(moneyLend)
+ val = -val;
+ calc.setPmt(val);
+
+ result = i18n("KMyMoney has calculated a periodic payment of %1 to cover principal and interest.")
+ .arg(m_paymentAmount->lineedit()->text());
+
+ val = calc.futureValue();
+ if((moneyBorrowed && val < 0 && fabsl(val) >= fabsl(calc.payment()))
+ || (moneyLend && val > 0 && fabs(val) >= fabs(calc.payment()))) {
+ calc.setNpp(calc.npp()-1);
+ // updateTermWidgets(calc.npp());
+ val = calc.futureValue();
+ MyMoneyMoney refVal(static_cast<double>(val));
+ m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision()));
+ result += QString(" ");
+ result += i18n("The number of payments has been decremented and the balloon payment has been modified to %1.")
+ .arg(m_balloonAmount->lineedit()->text());
+ } else if((moneyBorrowed && val < 0 && fabsl(val) < fabsl(calc.payment()))
+ || (moneyLend && val > 0 && fabs(val) < fabs(calc.payment()))) {
+ m_balloonAmount->loadText(MyMoneyMoney(0,1).formatMoney("", m_wizard->precision()));
+ } else {
+ MyMoneyMoney refVal(static_cast<double>(val));
+ m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision()));
+ result += i18n("The balloon payment has been modified to %1.")
+ .arg(m_balloonAmount->lineedit()->text());
+ }
+
+ } else if(m_termAmount->value() == 0) {
+ // calculate the number of payments out of the other information
+ val = calc.numPayments();
+ if(val == 0)
+ throw new MYMONEYEXCEPTION("incorrect fincancial calculation");
+
+ // if the number of payments has a fractional part, then we
+ // round it to the smallest integer and calculate the balloon payment
+ result = i18n("KMyMoney has calculated the term of your loan as %1. ")
+ .arg(updateTermWidgets(floorl(val)));
+
+ if(val != floorl(val)) {
+ calc.setNpp(floorl(val));
+ val = calc.futureValue();
+ MyMoneyMoney refVal(static_cast<double>(val));
+ m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision()));
+ result += i18n("The balloon payment has been modified to %1.")
+ .arg(m_balloonAmount->lineedit()->text());
+ }
+
+ } else {
+ // calculate the future value of the loan out of the other information
+ val = calc.futureValue();
+
+ // we differentiate between the following cases:
+ // a) the future value is greater than a payment
+ // b) the future value is less than a payment or the loan is overpaid
+ // c) all other cases
+ //
+ // a) means, we have paid more than we owed. This can't be
+ // b) means, we paid more than we owed but the last payment is
+ // less in value than regular payments. That means, that the
+ // future value is to be treated as (fully payed back)
+ // c) the loan is not payed back yet
+ if((moneyBorrowed && val < 0 && fabsl(val) > fabsl(calc.payment()))
+ || (moneyLend && val > 0 && fabs(val) > fabs(calc.payment()))) {
+ // case a)
+ qDebug("Future Value is %Lf", val);
+ throw new MYMONEYEXCEPTION("incorrect fincancial calculation");
+
+ } else if((moneyBorrowed && val < 0 && fabsl(val) <= fabsl(calc.payment()))
+ || (moneyLend && val > 0 && fabs(val) <= fabs(calc.payment()))) {
+ // case b)
+ val = 0;
+ }
+
+ MyMoneyMoney refVal(static_cast<double>(val));
+ result = i18n("KMyMoney has calculated a balloon payment of %1 for this loan.")
+ .arg(refVal.abs().formatMoney("", m_wizard->precision()));
+
+ if(!m_balloonAmount->lineedit()->text().isEmpty()) {
+ if((m_balloonAmount->value().abs() - refVal.abs()).abs().toDouble() > 1) {
+ throw new MYMONEYEXCEPTION("incorrect fincancial calculation");
+ }
+ result = i18n("KMyMoney has successfully verified your loan information.");
+ }
+ m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision()));
+ }
+
+ } catch (MyMoneyException *e) {
+ delete e;
+ KMessageBox::error(0,
+ i18n("You have entered mis-matching information. Please modify "
+ "your figures or leave one value empty "
+ "to let KMyMoney calculate it for you"),
+ i18n("Calculation error"));
+ return;
+ }
+
+ result += i18n("\n\nAccept this or modify the loan information and recalculate.");
+
+ KMessageBox::information(0, result, i18n("Calculation successful"));
+ m_needCalculate = false;
+
+ // now update change
+ m_wizard->completeStateChanged();
+}
+
+int LoanDetailsPage::term(void) const
+{
+ int factor = 0;
+
+ if(m_termAmount->value() != 0) {
+ factor = 1;
+ switch(m_termUnit->currentItem()) {
+ case MyMoneySchedule::OCCUR_YEARLY: // years
+ factor = 12;
+ // tricky fall through here
+
+ case MyMoneySchedule::OCCUR_MONTHLY: // months
+ factor *= 30;
+ factor *= m_termAmount->value();
+ // factor now is the duration in days. we divide this by the
+ // payment frequency and get the number of payments
+ factor /= m_wizard->m_generalLoanInfoPage->m_paymentFrequency->daysBetweenEvents();
+ break;
+
+ default:
+ qDebug("Unknown term unit %d in LoanDetailsPage::term(). Using payments.", m_termUnit->currentItem());
+ // tricky fall through here
+
+ case MyMoneySchedule::OCCUR_ONCE: // payments
+ factor = m_termAmount->value();
+ break;
+ }
+ }
+ return factor;
+}
+
+QString LoanDetailsPage::updateTermWidgets(const long double val)
+{
+ long long vl = static_cast<long long>(floorl(val));
+
+ QString valString;
+ MyMoneySchedule::occurenceE unit = m_termUnit->currentItem();
+
+ if((unit == MyMoneySchedule::OCCUR_MONTHLY)
+ && ((vl % 12) == 0)) {
+ vl /= 12;
+ unit = MyMoneySchedule::OCCUR_YEARLY;
+ }
+
+ switch(unit) {
+ case MyMoneySchedule::OCCUR_MONTHLY:
+ valString = i18n("one month", "%n months", vl);
+ m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY);
+ break;
+ case MyMoneySchedule::OCCUR_YEARLY:
+ valString = i18n("one year", "%n years", vl);
+ m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_YEARLY);
+ break;
+ default:
+ valString = i18n("one payment", "%n payments", vl);
+ m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_ONCE);
+ break;
+ }
+ m_termAmount->setValue(vl);
+ return valString;
+}
+
+bool LoanDetailsPage::isComplete(void) const
+{
+ // bool rc = KMyMoneyWizardPage::isComplete();
+
+ int fieldCnt = 0;
+ QWidget* calculatedField = 0;
+
+ if(m_loanAmount->lineedit()->text().length() > 0) {
+ fieldCnt++;
+ } else {
+ calculatedField = m_loanAmount;
+ }
+
+ if(m_interestRate->lineedit()->text().length() > 0) {
+ fieldCnt++;
+ } else {
+ calculatedField = m_interestRate;
+ }
+
+ if(m_termAmount->value() != 0) {
+ fieldCnt++;
+ } else {
+ calculatedField = m_termAmount;
+ }
+
+ if(m_paymentAmount->lineedit()->text().length() > 0) {
+ fieldCnt++;
+ } else {
+ calculatedField = m_paymentAmount;
+ }
+
+ if(m_balloonAmount->lineedit()->text().length() > 0) {
+ fieldCnt++;
+ } else {
+ calculatedField = m_balloonAmount;
+ }
+
+ if(fieldCnt == 5)
+ calculatedField = 0;
+
+ m_calculateButton->setEnabled(fieldCnt == 4 || (fieldCnt == 5 && m_needCalculate));
+
+ m_calculateButton->setAutoDefault(false);
+ m_calculateButton->setDefault(false);
+ if(m_needCalculate && fieldCnt == 4) {
+ QToolTip::add(m_wizard->m_nextButton, i18n("Press Calculate to verify the values"));
+ m_calculateButton->setAutoDefault(true);
+ m_calculateButton->setDefault(true);
+ } else if(fieldCnt != 5) {
+ QToolTip::add(m_wizard->m_nextButton, i18n("Not all details supplied"));
+ m_calculateButton->setAutoDefault(true);
+ m_calculateButton->setDefault(true);
+ }
+ m_wizard->m_nextButton->setAutoDefault(!m_calculateButton->autoDefault());
+ m_wizard->m_nextButton->setDefault(!m_calculateButton->autoDefault());
+
+ return (fieldCnt == 5) && !m_needCalculate;
+}
+
+KMyMoneyWizardPage* LoanDetailsPage::nextPage(void) const
+{
+ return m_wizard->m_loanPaymentPage;
+}
+
+
+class NewAccountWizard::LoanPaymentPage::Private
+{
+public:
+ MyMoneyAccount phonyAccount;
+ MyMoneySplit phonySplit;
+ MyMoneyTransaction additionalFeesTransaction;
+ MyMoneyMoney additionalFees;
+};
+
+LoanPaymentPage::LoanPaymentPage(Wizard* wizard, const char* name) :
+ KLoanPaymentPageDecl(wizard),
+ WizardPage<Wizard>(StepFees, this, wizard, name),
+ d(new Private)
+{
+ d->phonyAccount = MyMoneyAccount(QString("Phony-ID"), MyMoneyAccount());
+
+ d->phonySplit.setAccountId(d->phonyAccount.id());
+ d->phonySplit.setValue(0);
+ d->phonySplit.setShares(0);
+
+ d->additionalFeesTransaction.addSplit(d->phonySplit);
+
+ connect(m_additionalFeesButton, SIGNAL(clicked()), this, SLOT(slotAdditionalFees()));
+}
+
+LoanPaymentPage::~LoanPaymentPage()
+{
+ delete d;
+}
+
+MyMoneyMoney LoanPaymentPage::basePayment(void) const
+{
+ return m_wizard->m_loanDetailsPage->m_paymentAmount->value();
+}
+
+MyMoneyMoney LoanPaymentPage::additionalFees(void) const
+{
+ return d->additionalFees;
+}
+
+void LoanPaymentPage::additionalFeesSplits(QValueList<MyMoneySplit>& list)
+{
+ list.clear();
+
+ QValueList<MyMoneySplit>::ConstIterator it;
+ for(it = d->additionalFeesTransaction.splits().begin(); it != d->additionalFeesTransaction.splits().end(); ++it) {
+ if((*it).accountId() != d->phonyAccount.id()) {
+ list << (*it);
+ }
+ }
+}
+
+void LoanPaymentPage::updateAmounts(void)
+{
+ m_additionalFees->setText(d->additionalFees.formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision()));
+ m_totalPayment->setText((basePayment() + d->additionalFees).formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision()));
+}
+
+void LoanPaymentPage::enterPage(void)
+{
+ const MyMoneySecurity& currency = m_wizard->currency();
+
+ m_basePayment->setText(basePayment().formatMoney(currency.tradingSymbol(), m_wizard->precision()));
+ d->phonyAccount.setCurrencyId(currency.id());
+ d->additionalFeesTransaction.setCommodity(currency.id());
+
+ updateAmounts();
+}
+
+void LoanPaymentPage::slotAdditionalFees(void)
+{
+ QMap<QString, MyMoneyMoney> priceInfo;
+ KSplitTransactionDlg* dlg = new KSplitTransactionDlg(d->additionalFeesTransaction, d->phonySplit, d->phonyAccount, false, !m_wizard->moneyBorrowed(), MyMoneyMoney(0), priceInfo);
+
+ // connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), this, SIGNAL(newCategory(MyMoneyAccount&)));
+
+ if(dlg->exec() == QDialog::Accepted) {
+ d->additionalFeesTransaction = dlg->transaction();
+ // sum up the additional fees
+ QValueList<MyMoneySplit>::ConstIterator it;
+
+ d->additionalFees = MyMoneyMoney(0);
+ for(it = d->additionalFeesTransaction.splits().begin(); it != d->additionalFeesTransaction.splits().end(); ++it) {
+ if((*it).accountId() != d->phonyAccount.id()) {
+ d->additionalFees += (*it).shares();
+ }
+ }
+ updateAmounts();
+ }
+
+ delete dlg;
+}
+
+KMyMoneyWizardPage* LoanPaymentPage::nextPage(void) const
+{
+ return m_wizard->m_loanSchedulePage;
+}
+
+
+LoanSchedulePage::LoanSchedulePage(Wizard* wizard, const char* name) :
+ KLoanSchedulePageDecl(wizard),
+ WizardPage<Wizard>(StepSchedule, this, wizard, name)
+{
+ m_mandatoryGroup->add(m_interestCategory->lineEdit());
+ m_mandatoryGroup->add(m_paymentAccount->lineEdit());
+ connect(m_interestCategory, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateCategory(const QString&, QString&)));
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+}
+
+void LoanSchedulePage::slotCreateCategory(const QString& name, QString& id)
+{
+ MyMoneyAccount acc, parent;
+ acc.setName(name);
+
+ if(m_wizard->moneyBorrowed())
+ parent = MyMoneyFile::instance()->expense();
+ else
+ parent = MyMoneyFile::instance()->income();
+
+ emit m_wizard->createCategory(acc, parent);
+
+ // return id
+ id = acc.id();
+}
+
+QDate LoanSchedulePage::firstPaymentDueDate(void) const
+{
+ if(m_firstPaymentDueDate->isEnabled())
+ return m_firstPaymentDueDate->date();
+ return m_wizard->m_generalLoanInfoPage->m_firstPaymentDate->date();
+}
+
+void LoanSchedulePage::enterPage(void)
+{
+ m_interestCategory->setFocus();
+ m_firstPaymentDueDate->setDisabled(m_wizard->m_generalLoanInfoPage->recordAllPayments());
+ slotLoadWidgets();
+}
+
+void LoanSchedulePage::slotLoadWidgets(void)
+{
+ AccountSet set;
+ if(m_wizard->moneyBorrowed())
+ set.addAccountGroup(MyMoneyAccount::Expense);
+ else
+ set.addAccountGroup(MyMoneyAccount::Income);
+ set.load(m_interestCategory->selector());
+
+ set.clear();
+ set.addAccountGroup(MyMoneyAccount::Asset);
+ set.load(m_paymentAccount->selector());
+}
+
+KMyMoneyWizardPage* LoanSchedulePage::nextPage(void) const
+{
+ // if the balance widget of the general loan info page is enabled and
+ // the value is not zero, then the payout already happened and we don't
+ // aks for it.
+ if(m_wizard->openingBalance().isZero())
+ return m_wizard->m_loanPayoutPage;
+ return m_wizard->m_accountSummaryPage;
+}
+
+LoanPayoutPage::LoanPayoutPage(Wizard* wizard, const char* name) :
+ KLoanPayoutPageDecl(wizard),
+ WizardPage<Wizard>(StepPayout, this, wizard, name)
+{
+ m_mandatoryGroup->add(m_assetAccount->lineEdit());
+ m_mandatoryGroup->add(m_loanAccount->lineEdit());
+
+ KIconLoader* il = KGlobal::iconLoader();
+ KGuiItem createAssetButtenItem( i18n( "&Create..." ),
+ QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)),
+ i18n("Create a new asset account"),
+ i18n("If the asset account does not yet exist, press this button to create it."));
+ m_createAssetButton->setGuiItem(createAssetButtenItem);
+ QToolTip::add(m_createAssetButton, createAssetButtenItem.toolTip());
+ QWhatsThis::add(m_createAssetButton, createAssetButtenItem.whatsThis());
+ connect(m_createAssetButton, SIGNAL(clicked()), this, SLOT(slotCreateAssetAccount()));
+
+ connect(m_noPayoutTransaction, SIGNAL(toggled(bool)), this, SLOT(slotButtonsToggled()));
+ connect(m_refinanceLoan, SIGNAL(toggled(bool)), this, SLOT(slotButtonsToggled()));
+
+ connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets()));
+ slotLoadWidgets();
+}
+
+void LoanPayoutPage::slotButtonsToggled(void)
+{
+ // we don't go directly, as the order of the emission of signals to slots is
+ // not defined. Using a single shot timer postpones the call of m_mandatoryGroup::changed()
+ // until the next round of the main loop so we can be sure to see all relevant changes
+ // that happened in the meantime (eg. widgets are enabled and disabled)
+ QTimer::singleShot(0, m_mandatoryGroup, SLOT(changed()));
+}
+
+void LoanPayoutPage::slotCreateAssetAccount(void)
+{
+ MyMoneyAccount acc;
+ acc.setAccountType(MyMoneyAccount::Asset);
+ acc.setOpeningDate(m_wizard->m_accountTypePage->m_openingDate->date());
+
+ emit m_wizard->createAccount(acc);
+
+ if(!acc.id().isEmpty()) {
+ m_assetAccount->setSelectedItem(acc.id());
+ }
+}
+
+void LoanPayoutPage::slotLoadWidgets(void)
+{
+ AccountSet set;
+ set.addAccountGroup(MyMoneyAccount::Asset);
+ set.load(m_assetAccount->selector());
+
+ set.clear();
+ set.addAccountType(MyMoneyAccount::Loan);
+ set.load(m_loanAccount->selector());
+}
+
+void LoanPayoutPage::enterPage(void)
+{
+ // only allow to create new asset accounts for liability loans
+ m_createAssetButton->setEnabled(m_wizard->moneyBorrowed());
+ m_refinanceLoan->setEnabled(m_wizard->moneyBorrowed());
+ if(!m_wizard->moneyBorrowed()) {
+ m_refinanceLoan->setChecked(false);
+ }
+ m_payoutDetailFrame->setDisabled(m_noPayoutTransaction->isChecked());
+}
+
+KMyMoneyWizardPage* LoanPayoutPage::nextPage(void) const
+{
+ return m_wizard->m_accountSummaryPage;
+}
+
+bool LoanPayoutPage::isComplete(void) const
+{
+ return KMyMoneyWizardPage::isComplete() | m_noPayoutTransaction->isChecked();
+}
+
+const QString& LoanPayoutPage::payoutAccountId(void) const
+{
+ if(m_refinanceLoan->isChecked()) {
+ return m_loanAccount->selectedItem();
+ } else {
+ return m_assetAccount->selectedItem();
+ }
+}
+
+HierarchyPage::HierarchyPage(Wizard* wizard, const char* name) :
+ KHierarchyPageDecl(wizard),
+ WizardPage<Wizard>(StepParentAccount, this, wizard, name)
+{
+ // the next line causes a warning to be shown in the console output
+ // since at least one of the major groups is selected, and the user
+ // cannot deselect an account, at least one is selected all the time
+ // and we don't need this check
+ // m_mandatoryGroup->add(m_qlistviewParentAccounts);
+ m_qlistviewParentAccounts->setEnabled(true);
+ m_qlistviewParentAccounts->setRootIsDecorated(true);
+ m_qlistviewParentAccounts->setAllColumnsShowFocus(true);
+ m_qlistviewParentAccounts->addColumn("Accounts");
+ m_qlistviewParentAccounts->setMultiSelection(false);
+ m_qlistviewParentAccounts->header()->setResizeEnabled(true);
+ m_qlistviewParentAccounts->setColumnWidthMode(0, QListView::Maximum);
+ // never show the horizontal scroll bar
+ // m_qlistviewParentAccounts->setHScrollBarMode(QScrollView::AlwaysOff);
+}
+
+void HierarchyPage::enterPage(void)
+{
+ // Ensure that the list reflects the Account Type
+ // - if the type has changed
+ // - - clear the list
+ // - - populate the account list (also occurs first time we come here)
+ MyMoneyAccount topAccount = m_wizard->m_accountTypePage->parentAccount();
+
+ // If the list was not populated with this top account we populate it now
+ if ( &m_topAccount == NULL || m_topAccount.id() != topAccount.id())
+ {
+ if ( &m_topAccount != NULL )
+ {
+ // If the list has alrady been populated clear it
+ if ( (*m_qlistviewParentAccounts).childCount() > 0 )
+ (*m_qlistviewParentAccounts).clear();
+ }
+
+ // Add the Tree for the Top Account
+ KMyMoneyAccountTreeItem *topAccountTree = buildAccountTree(m_qlistviewParentAccounts, topAccount, false);
+ topAccountTree->setOpen(true);
+ // Record the top account used to populate the list
+ m_topAccount = topAccount;
+ }
+}
+
+KMyMoneyAccountTreeItem* HierarchyPage::buildAccountTree
+ ( KMyMoneyAccountTreeBase* parent
+ , const MyMoneyAccount& account
+ , bool open ) const
+{
+ // Recursively add child accounts to the list
+ if ( account.accountType() == MyMoneyAccount::Investment)
+ return NULL;
+ KMyMoneyAccountTreeItem* childItem = new KMyMoneyAccountTreeItem( parent, account );
+ if ( open )
+ childItem->setOpen(true);
+ for ( QStringList::ConstIterator it = account.accountList().begin();
+ it != account.accountList().end();
+ ++it )
+ {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it);
+ if(acc.isClosed())
+ continue;
+ if(acc.accountType() == MyMoneyAccount::Investment)
+ continue;
+ buildAccountTree( childItem, acc, open );
+ }
+ return childItem;
+}
+
+KMyMoneyAccountTreeItem* HierarchyPage::buildAccountTree
+ ( KMyMoneyAccountTreeItem* parent
+ , const MyMoneyAccount& account
+ , bool open ) const
+{
+ // Recursively add child accounts to the list
+ if ( account.accountType() == MyMoneyAccount::Investment)
+ return NULL;
+ KMyMoneyAccountTreeItem* childItem = new KMyMoneyAccountTreeItem( parent, account );
+ if ( open )
+ childItem->setOpen(true);
+ for ( QStringList::ConstIterator it = account.accountList().begin();
+ it != account.accountList().end();
+ ++it )
+ {
+ MyMoneyAccount acc = MyMoneyFile::instance()->account(*it);
+ if(acc.isClosed())
+ continue;
+ if (account.accountType() == MyMoneyAccount::Investment)
+ continue;
+ buildAccountTree( childItem, acc, open );
+ }
+ return childItem;
+}
+
+KMyMoneyWizardPage* HierarchyPage::nextPage(void) const
+{
+ return m_wizard->m_accountSummaryPage;
+}
+
+const MyMoneyAccount& HierarchyPage::parentAccount(void)
+{
+ // TODO
+ // Instead of returning the Parent Account we can simply
+ // return the account associated with the current item
+ // in the ListView
+ KMyMoneyAccountTreeItem* item = dynamic_cast<KMyMoneyAccountTreeItem*>(m_qlistviewParentAccounts->currentItem());
+ return dynamic_cast<const MyMoneyAccount&>(item->itemObject());
+}
+
+AccountSummaryPage::AccountSummaryPage(Wizard* wizard, const char* name) :
+ KAccountSummaryPageDecl(wizard),
+ WizardPage<Wizard>(StepFinish, this, wizard, name)
+{
+ m_dataList->setSorting(-1);
+ m_dataList->setColumnWidthMode(1, QListView::Maximum);
+ m_dataList->setResizeMode(QListView::LastColumn);
+}
+
+void AccountSummaryPage::enterPage(void)
+{
+ MyMoneyAccount acc = m_wizard->account();
+ MyMoneySecurity sec = m_wizard->currency();
+ acc.fraction(sec);
+
+ // assign an id to the account inside the wizard which is required for a schedule
+ // get the schedule and clear the id again in the wizards object.
+ MyMoneyAccount tmp(QString("Phony-ID"), acc);
+ m_wizard->setAccount(tmp);
+ MyMoneySchedule sch = m_wizard->schedule();
+ m_wizard->setAccount(acc);
+
+ m_dataList->clear();
+
+ // Account data
+ QListViewItem* group = new KMyMoneyCheckListItem(m_dataList, i18n("Account information"), QString(), QString(), QCheckListItem::RadioButtonController);
+ group->setOpen(true);
+ QListViewItem* p;
+ p = new KListViewItem(group, i18n("Name"), acc.name());
+ if(!acc.isLoan())
+ p = new KListViewItem(group, p, i18n("Subaccount of"),
+ m_wizard->parentAccount().name());
+ if(acc.accountType() == MyMoneyAccount::AssetLoan)
+ p = new KListViewItem(group, p, i18n("Type"), i18n("Loan"));
+ else
+ p = new KListViewItem(group, p, i18n("Type"), m_wizard->m_accountTypePage->m_typeSelection->currentText());
+ p = new KListViewItem(group, p, i18n("Currency"), m_wizard->currency().name());
+ p = new KListViewItem(group, p, i18n("Opening date"), KGlobal::locale()->formatDate(acc.openingDate()));
+ if(m_wizard->currency().id() != MyMoneyFile::instance()->baseCurrency().id()) {
+ p = new KListViewItem(group, p, i18n("Conversion rate"), m_wizard->conversionRate().rate(QString()).formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
+ }
+ if(!acc.isLoan() || !m_wizard->openingBalance().isZero())
+ p = new KListViewItem(group, p, i18n("Opening balance"), m_wizard->openingBalance().formatMoney(acc, sec));
+
+ if(!m_wizard->m_institutionPage->institution().id().isEmpty()) {
+ p = new KListViewItem(group, p, i18n("Institution"), m_wizard->m_institutionPage->institution().name());
+ if(!acc.number().isEmpty()) {
+ p = new KListViewItem(group, p, i18n("Number"), acc.number());
+ }
+ if(!acc.value("IBAN").isEmpty()) {
+ p = new KListViewItem(group, p, i18n("IBAN"), acc.value("IBAN"));
+ }
+ }
+
+ if(acc.accountType() == MyMoneyAccount::Investment) {
+ if(m_wizard->m_brokeragepage->m_createBrokerageButton->isChecked()) {
+ group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Brokerage Account"), QString(), QString(), QCheckListItem::RadioButtonController);
+ group->setOpen(true);
+ p = new KListViewItem(group, p, i18n("Name"), QString("%1 (Brokerage)").arg(acc.name()));
+ p = new KListViewItem(group, p, i18n("Currency"), m_wizard->m_brokeragepage->m_brokerageCurrency->security().name());
+ if(m_wizard->m_brokeragepage->m_accountNumber->isEnabled() && !m_wizard->m_brokeragepage->m_accountNumber->text().isEmpty())
+ p = new KListViewItem(group, p, i18n("Number"), m_wizard->m_brokeragepage->m_accountNumber->text());
+ if(m_wizard->m_brokeragepage->m_iban->isEnabled() && !m_wizard->m_brokeragepage->m_iban->text().isEmpty())
+ p = new KListViewItem(group, p, i18n("IBAN"), m_wizard->m_brokeragepage->m_iban->text());
+ }
+ }
+
+ // Loan
+ if(acc.isLoan()) {
+ group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Loan information"), QString(), QString(), QCheckListItem::RadioButtonController);
+ group->setOpen(true);
+ if(m_wizard->moneyBorrowed()) {
+ p = new KListViewItem(group, p, i18n("Amount borrowed"), m_wizard->m_loanDetailsPage->m_loanAmount->value().formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision()));
+ } else {
+ p = new KListViewItem(group, p, i18n("Amount lent"), m_wizard->m_loanDetailsPage->m_loanAmount->value().formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision()));
+ }
+ p = new KListViewItem(group, p, i18n("Interest rate"), QString("%1 %").arg(m_wizard->m_loanDetailsPage->m_interestRate->value().formatMoney("", -1)));
+ p = new KListViewItem(group, p, i18n("Interest rate is"), m_wizard->m_generalLoanInfoPage->m_interestType->currentText());
+ p = new KListViewItem(group, p, i18n("Principal and interest"), m_wizard->m_loanDetailsPage->m_paymentAmount->value().formatMoney(acc, sec));
+ p = new KListViewItem(group, p, i18n("Additional fees"), m_wizard->m_loanPaymentPage->additionalFees().formatMoney(acc, sec));
+ p = new KListViewItem(group, p, i18n("Payment frequency"), m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentText());
+ p = new KListViewItem(group, p, i18n("Payment account"), m_wizard->m_loanSchedulePage->m_paymentAccount->currentText());
+
+ if(!m_wizard->m_loanPayoutPage->m_noPayoutTransaction->isChecked() && m_wizard->openingBalance().isZero()) {
+ group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Payout information"), QString(), QString(), QCheckListItem::RadioButtonController);
+ group->setOpen(true);
+ if(m_wizard->m_loanPayoutPage->m_refinanceLoan->isChecked()) {
+ p = new KListViewItem(group, p, i18n("Refinance"), m_wizard->m_loanPayoutPage->m_loanAccount->currentText());
+ } else {
+ if(m_wizard->moneyBorrowed())
+ p = new KListViewItem(group, p, i18n("Transfer amount to"), m_wizard->m_loanPayoutPage->m_assetAccount->currentText());
+ else
+ p = new KListViewItem(group, p, i18n("Transfer amount from"), m_wizard->m_loanPayoutPage->m_assetAccount->currentText());
+ }
+ p = new KListViewItem(group, p, i18n("Payment date"), KGlobal::locale()->formatDate(m_wizard->m_loanPayoutPage->m_payoutDate->date()));
+ }
+ }
+
+ // Schedule
+ if(!(sch == MyMoneySchedule())) {
+ group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Schedule information"), QString(), QString(), QCheckListItem::RadioButtonController);
+ group->setOpen(true);
+ p = new KListViewItem(group, i18n("Name"), sch.name());
+ if(acc.accountType() == MyMoneyAccount::CreditCard) {
+ MyMoneyAccount paymentAccount = MyMoneyFile::instance()->account(m_wizard->m_schedulePage->m_paymentAccount->selectedItem());
+ p = new KListViewItem(group, p, i18n("Occurence"), i18n("Monthly"));
+ p = new KListViewItem(group, p, i18n("Paid from"), paymentAccount.name());
+ p = new KListViewItem(group, p, i18n("Pay to"), m_wizard->m_schedulePage->m_payee->currentText());
+ p = new KListViewItem(group, p, i18n("Amount"), m_wizard->m_schedulePage->m_amount->value().formatMoney(acc, sec));
+ p = new KListViewItem(group, p, i18n("First payment due"), KGlobal::locale()->formatDate(sch.nextDueDate()));
+ p = new KListViewItem(group, p, i18n("Payment method"), m_wizard->m_schedulePage->m_method->currentText());
+ }
+ if(acc.isLoan()) {
+ p = new KListViewItem(group, p, i18n("Occurence"), m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentText());
+ p = new KListViewItem(group, p, i18n("Amount"), (m_wizard->m_loanPaymentPage->basePayment() + m_wizard->m_loanPaymentPage->additionalFees()).formatMoney(acc, sec));
+ p = new KListViewItem(group, p, i18n("First payment due"), KGlobal::locale()->formatDate(m_wizard->m_loanSchedulePage->firstPaymentDueDate()));
+ }
+ }
+}
+
+#include "knewaccountwizard.moc"
diff --git a/kmymoney2/wizards/newaccountwizard/knewaccountwizard.h b/kmymoney2/wizards/newaccountwizard/knewaccountwizard.h
new file mode 100644
index 0000000..c8a149c
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/knewaccountwizard.h
@@ -0,0 +1,182 @@
+/***************************************************************************
+ knewaccountwizard.h
+ -------------------
+ begin : Tue Sep 25 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWACCOUNTWIZARD_H
+#define KNEWACCOUNTWIZARD_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QString;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneywizard.h>
+class MyMoneyPrice;
+
+/**
+ * @author Thomas Baumgart
+ */
+namespace NewAccountWizard {
+
+class AccountTypePage;
+class InstitutionPage;
+class BrokeragePage;
+class CreditCardSchedulePage;
+class GeneralLoanInfoPage;
+class LoanDetailsPage;
+class LoanPaymentPage;
+class LoanSchedulePage;
+class LoanPayoutPage;
+class HierarchyPage;
+class AccountSummaryPage;
+
+/**
+ * @author Thomas Baumgart
+ *
+ * This class implements the new account wizard which is used to gather
+ * the required information from the user to create a new account
+ */
+class Wizard : public KMyMoneyWizard
+{
+ friend class AccountTypePage;
+ friend class InstitutionPage;
+ friend class BrokeragePage;
+ friend class CreditCardSchedulePage;
+ friend class GeneralLoanInfoPage;
+ friend class LoanDetailsPage;
+ friend class LoanPaymentPage;
+ friend class LoanSchedulePage;
+ friend class LoanPayoutPage;
+ friend class HierarchyPage;
+ friend class AccountSummaryPage;
+
+ Q_OBJECT
+public:
+ Wizard(QWidget* parent = 0, const char* name = 0, bool modal = false, WFlags flags = 0);
+
+ /**
+ * Returns the information about the account as entered by
+ * the user.
+ */
+ const MyMoneyAccount& account(void);
+
+ /**
+ * Method to load the generated account information back into the widget
+ */
+ void setAccount(const MyMoneyAccount& acc);
+
+ /**
+ * Returns the information about the parent account as entered by
+ * the user.
+ * @note For now it's either fixed as Asset or Liability. We will provide
+ * user selected parent accounts later.
+ */
+ const MyMoneyAccount& parentAccount(void);
+
+ /**
+ * Returns information about the schedule. If the returned value
+ * equals MyMoneySchedule() then the user did not select to create
+ * a schedule.
+ */
+ const MyMoneySchedule& schedule(void);
+
+ /**
+ * This method returns the value of the opening balance
+ * entered by the user
+ */
+ MyMoneyMoney openingBalance(void) const;
+
+ /**
+ * This method returns the interest rate as factor, ie an
+ * interest rate of 6.5% will be returned as 0.065
+ */
+ MyMoneyMoney interestRate(void) const;
+
+ /**
+ * This method returns the payout transaction for loans.
+ * If the account to be created is not a loan or no
+ * payout transaction should be generated, this method
+ * returns an emtpy transaction.
+ */
+ MyMoneyTransaction payoutTransaction(void);
+
+ /**
+ * This method returns a MyMoneyAccount() object filled
+ * with the data to create a brokerage account. If the
+ * user selected not to create a brokerage account or
+ * the account type is not able to create a brokerage
+ * account, an empty MyMoneyAccount() object is returned.
+ *
+ * @note Make sure to call the account() method before you call this method.
+ * Otherwise the returned object might contain unexpected results.
+ */
+ MyMoneyAccount brokerageAccount(void) const;
+
+ /**
+ * This method returns the conversion rate
+ */
+ MyMoneyPrice conversionRate(void) const;
+
+protected:
+ /**
+ * This method returns the currently selected currency for the account
+ */
+ const MyMoneySecurity& currency(void) const;
+
+ /**
+ * This method returns the precision in digits for the selected currency.
+ * @sa currency()
+ */
+ int precision(void) const;
+
+ /**
+ * This method returns information about the selection of the user
+ * if the loan is for borrowing or lending money.
+ *
+ * @retval true loan is for money borrowed
+ * @retval false loan is for money lent
+ */
+ bool moneyBorrowed() const;
+
+signals:
+ void createInstitution(MyMoneyInstitution& institution);
+ void createAccount(MyMoneyAccount& account);
+ void createCategory(MyMoneyAccount&, const MyMoneyAccount&);
+
+private:
+ InstitutionPage* m_institutionPage;
+ AccountTypePage* m_accountTypePage;
+ BrokeragePage* m_brokeragepage;
+ CreditCardSchedulePage* m_schedulePage;
+ GeneralLoanInfoPage* m_generalLoanInfoPage;
+ LoanDetailsPage* m_loanDetailsPage;
+ LoanPaymentPage* m_loanPaymentPage;
+ LoanSchedulePage* m_loanSchedulePage;
+ LoanPayoutPage* m_loanPayoutPage;
+ HierarchyPage* m_hierarchyPage;
+ AccountSummaryPage* m_accountSummaryPage;
+
+ MyMoneyAccountLoan m_account;
+ MyMoneySchedule m_schedule;
+};
+
+}; // namespace
+
+
+#endif
diff --git a/kmymoney2/wizards/newaccountwizard/knewaccountwizard_p.h b/kmymoney2/wizards/newaccountwizard/knewaccountwizard_p.h
new file mode 100644
index 0000000..b8a7cb1
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/knewaccountwizard_p.h
@@ -0,0 +1,327 @@
+/***************************************************************************
+ knewaccountwizard_p.h
+ -------------------
+ begin : Tue Sep 25 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWACCOUNTWIZARD_P_H
+#define KNEWACCOUNTWIZARD_P_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qcheckbox.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneywizard.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneycurrencyselector.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kmymoneycategory.h>
+#include <kmymoney/kmymoneyaccounttreebase.h>
+
+#include "kinstitutionpagedecl.h"
+#include "kaccounttypepagedecl.h"
+#include "kbrokeragepagedecl.h"
+#include "kschedulepagedecl.h"
+#include "kgeneralloaninfopagedecl.h"
+#include "kloandetailspagedecl.h"
+#include "kloanpaymentpagedecl.h"
+#include "kloanschedulepagedecl.h"
+#include "kloanpayoutpagedecl.h"
+#include "khierarchypagedecl.h"
+#include "kaccountsummarypagedecl.h"
+
+class Wizard;
+class MyMoneyInstitution;
+class KMyMoneyAccountTreeItem;
+
+namespace NewAccountWizard {
+
+class InstitutionPage : public KInstitutionPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ InstitutionPage(Wizard* parent, const char* name = 0);
+ ~InstitutionPage();
+ KMyMoneyWizardPage* nextPage(void) const;
+
+ QWidget* initialFocusWidget(void) const { return m_institutionComboBox; }
+
+ /**
+ * Returns the information about an institution if entered by
+ * the user. If the id field is empty, then he did not enter
+ * such information.
+ */
+ const MyMoneyInstitution& institution(void) const;
+
+private slots:
+ void slotLoadWidgets(void);
+ void slotNewInstitution(void);
+ void slotSelectInstitution(int id);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+class AccountTypePage : public KAccountTypePageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ AccountTypePage(Wizard* parent, const char* name = 0);
+ virtual bool isComplete(void) const;
+ KMyMoneyWizardPage* nextPage(void) const;
+
+ QWidget* initialFocusWidget(void) const { return m_accountName; }
+
+ MyMoneyAccount::accountTypeE accountType(void) const;
+ const MyMoneyAccount& parentAccount(void);
+ bool allowsParentAccount(void) const;
+ const MyMoneySecurity& currency(void) const;
+
+ void setAccount(const MyMoneyAccount& acc);
+
+private:
+ void hideShowPages(MyMoneyAccount::accountTypeE i) const;
+ void priceWarning(bool);
+
+private slots:
+ void slotLoadWidgets(void);
+ void slotUpdateType(int i);
+ void slotUpdateCurrency(void);
+ void slotUpdateConversionRate(const QString&);
+ void slotGetOnlineQuote(void);
+ void slotPriceWarning(void);
+
+private:
+ bool m_showPriceWarning;
+};
+
+class BrokeragePage : public KBrokeragePageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ BrokeragePage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+ void enterPage(void);
+
+ QWidget* initialFocusWidget(void) const { return m_createBrokerageButton; }
+
+private slots:
+ void slotLoadWidgets(void);
+};
+
+class CreditCardSchedulePage : public KSchedulePageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ CreditCardSchedulePage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+ virtual bool isComplete(void) const;
+ void enterPage(void);
+
+ QWidget* initialFocusWidget(void) const { return m_reminderCheckBox; }
+
+private slots:
+ void slotLoadWidgets(void);
+};
+
+class GeneralLoanInfoPage : public KGeneralLoanInfoPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ GeneralLoanInfoPage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+ virtual bool isComplete(void) const;
+ void enterPage(void);
+ const MyMoneyAccount& parentAccount(void);
+
+ QWidget* initialFocusWidget(void) const { return m_loanDirection; }
+
+ /**
+ * Returns @p true if the user decided to record all payments, @p false otherwise.
+ */
+ bool recordAllPayments(void) const;
+
+private slots:
+ void slotLoadWidgets(void);
+
+private:
+ bool m_firstTime;
+};
+
+class LoanDetailsPage : public KLoanDetailsPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ LoanDetailsPage(Wizard* parent, const char* name = 0);
+ void enterPage(void);
+ KMyMoneyWizardPage* nextPage(void) const;
+ virtual bool isComplete(void) const;
+
+ QWidget* initialFocusWidget(void) const { return m_paymentDue; }
+
+ /**
+ * This method returns the number of payments depending on
+ * the settings of m_termAmount and m_termUnit widgets
+ */
+ int term(void) const;
+
+private:
+ /**
+ * This method is used to update the term widgets
+ * according to the length of the given @a term.
+ * The term is also converted into a string and returned.
+ */
+ QString updateTermWidgets(const long double term);
+
+private:
+ bool m_needCalculate;
+
+private slots:
+ void slotValuesChanged(void);
+ void slotCalculate(void);
+};
+
+class LoanPaymentPage : public KLoanPaymentPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ LoanPaymentPage(Wizard* parent, const char* name = 0);
+ ~LoanPaymentPage();
+
+ KMyMoneyWizardPage* nextPage(void) const;
+
+ void enterPage(void);
+
+ /**
+ * This method returns the sum of the additional fees
+ */
+ MyMoneyMoney additionalFees(void) const;
+
+ /**
+ * This method returns the base payment, that's principal and interest
+ */
+ MyMoneyMoney basePayment(void) const;
+
+ /**
+ * This method returns the splits that make up the additional fees in @p list.
+ * @note The splits may contain assigned ids which the caller must remove before
+ * adding the splits to a MyMoneyTransaction object.
+ */
+ void additionalFeesSplits(QValueList<MyMoneySplit>& list);
+
+protected slots:
+ void slotAdditionalFees(void);
+
+protected:
+ void updateAmounts(void);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+class LoanSchedulePage : public KLoanSchedulePageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ LoanSchedulePage(Wizard* parent, const char* name = 0);
+ void enterPage(void);
+
+ KMyMoneyWizardPage* nextPage(void) const;
+
+ /**
+ * This method returns the due date of the first payment to be recorded.
+ */
+ QDate firstPaymentDueDate(void) const;
+
+ QWidget* initialFocusWidget(void) const { return m_interestCategory; }
+
+private slots:
+ void slotLoadWidgets(void);
+ void slotCreateCategory(const QString& name, QString& id);
+};
+
+
+class LoanPayoutPage : public KLoanPayoutPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ LoanPayoutPage(Wizard* parent, const char* name = 0);
+ void enterPage(void);
+ virtual bool isComplete(void) const;
+
+ KMyMoneyWizardPage* nextPage(void) const;
+
+ QWidget* initialFocusWidget(void) const { return m_noPayoutTransaction; }
+
+ const QString& payoutAccountId(void) const;
+
+private slots:
+ void slotLoadWidgets(void);
+ void slotCreateAssetAccount(void);
+ void slotButtonsToggled(void);
+};
+
+class HierarchyPage : public KHierarchyPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ HierarchyPage(Wizard* parent, const char* name = 0);
+ void enterPage(void);
+ KMyMoneyWizardPage* nextPage(void) const;
+ QWidget* initialFocusWidget(void) const { return m_qlistviewParentAccounts; }
+ const MyMoneyAccount& parentAccount(void);
+
+private:
+ KMyMoneyAccountTreeItem* buildAccountTree
+ ( KMyMoneyAccountTreeBase* parent
+ , const MyMoneyAccount& account
+ , bool open = false ) const;
+ KMyMoneyAccountTreeItem* buildAccountTree
+ ( KMyMoneyAccountTreeItem* parent
+ , const MyMoneyAccount& account
+ , bool open = false ) const;
+ MyMoneyAccount m_topAccount; // Last populated top account
+ bool bFirstTime;
+};
+
+class AccountSummaryPage : public KAccountSummaryPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ AccountSummaryPage(Wizard* parent, const char* name = 0);
+ void enterPage(void);
+ QWidget* initialFocusWidget(void) const { return m_dataList; }
+};
+
+} // namespace
+
+#endif
diff --git a/kmymoney2/wizards/newaccountwizard/kschedulepagedecl.ui b/kmymoney2/wizards/newaccountwizard/kschedulepagedecl.ui
new file mode 100644
index 0000000..fd4f886
--- /dev/null
+++ b/kmymoney2/wizards/newaccountwizard/kschedulepagedecl.ui
@@ -0,0 +1,187 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSchedulePageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSchedulePageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>544</width>
+ <height>391</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel16</cstring>
+ </property>
+ <property name="text">
+ <string>For credit card accounts you can create a monthly schedule which will automatically remind you about the payment. Please fill in the details about this payment here.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_reminderCheckBox</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="text">
+ <string>Yes, remind me when the payment is due</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_paymentFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>180</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Name of schedule</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_name</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Payee</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyPayeeCombo" row="1" column="1">
+ <property name="name">
+ <cstring>m_payee</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Estimated monthly payment</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_amount</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel4_3</cstring>
+ </property>
+ <property name="text">
+ <string>Due date of next payment</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyDateInput" row="3" column="1">
+ <property name="name">
+ <cstring>m_date</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Payment should be made
+from account</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="KMyMoneyCategory" row="4" column="1">
+ <property name="name">
+ <cstring>m_paymentAccount</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Payment method</string>
+ </property>
+ </widget>
+ <widget class="KMyMoneyGeneralCombo" row="5" column="1">
+ <property name="name">
+ <cstring>m_method</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_reminderCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_paymentFrame</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/Makefile.am b/kmymoney2/wizards/newuserwizard/Makefile.am
new file mode 100644
index 0000000..36b9fdd
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LIBRARIES = libnewuserwizard.a
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I../wizardpages -I$(top_srcdir) -I.
+
+libnewuserwizard_a_METASOURCES = AUTO
+
+libnewuserwizard_a_SOURCES = knewuserwizard.cpp kgeneralpagedecl.ui kcurrencypagedecl.ui kpasswordpagedecl.ui kaccountpagedecl.ui kpreferencepagedecl.ui kfilepagedecl.ui kintropagedecl.ui
+
+EXTRA_DIST = kgeneralpagedecl.ui kcurrencypagedecl.ui kpasswordpagedecl.ui kaccountpagedecl.ui kpreferencepagedecl.ui kfilepagedecl.ui kintropagedecl.ui
+
+DISTCLEANFILES= kgeneralpagedecl.cpp kgeneralpagedecl.h kcurrencypagedecl.cpp kcurrencypagedecl.h kpasswordpagedecl.cpp kpasswordpagedecl.h kaccountpagedecl.cpp kaccountpagedecl.h kpreferencepagedecl.cpp kpreferencepagedecl.h kfilepagedecl.cpp kfilepagedecl.h kintropagedecl.cpp kintropagedecl.h
+
+noinst_HEADERS = knewuserwizard.h knewuserwizard_p.h
+
+SUBDIRS =
+
+messages: rc.cpp
diff --git a/kmymoney2/wizards/newuserwizard/kaccountpagedecl.ui b/kmymoney2/wizards/newuserwizard/kaccountpagedecl.ui
new file mode 100644
index 0000000..e0e3620
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kaccountpagedecl.ui
@@ -0,0 +1,268 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAccountPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAccountPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>481</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>A typical KMyMoney user maintains a checking a account with some institution and uses it to receive money or pay bills. If this is not the case, please deselect the checkbox below and continue on the next page.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_haveCheckingAccountButton</cstring>
+ </property>
+ <property name="text">
+ <string>I have a checking account that I want to manage with KMyMoney</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>m_accountDataFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KLineEdit" row="5" column="1">
+ <property name="name">
+ <cstring>m_institutionNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The name of the instititution that issued the account.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="6" column="1">
+ <property name="name">
+ <cstring>m_institutionNumberEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Each institution has a routing number. Enter it here. If uncertain, leave the field blank. You can modify it later.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Name of the institution</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Routing number</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_accountNumberEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>In general the institution that issued the account also issued a number for it. Enter it here. If uncertain, you can modify this entry later.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_accountNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter a descriptive name that will be used by KMyMoney to identify your checking account.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Opening date</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="1">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="kMyMoneyDateInput">
+ <property name="name">
+ <cstring>m_openingDateEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the date from when on you plan to keep track of the transactions in that account. This is usually the date of the last statement. If uncertain, leave as is.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>81</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Number of the account</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Name of the account</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Opening balance</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="4" column="1">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_accountCurrencyLabel</cstring>
+ </property>
+ <property name="text">
+ <string>xxx</string>
+ </property>
+ </widget>
+ <widget class="kMyMoneyEdit">
+ <property name="name">
+ <cstring>m_openingBalanceEdit</cstring>
+ </property>
+ <property name="resetButtonVisibility" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the opening balance of the account. This is usually the ending balance of the last statement. If uncertain, leave as is.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>200</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="KActiveLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>The fields below allow you to enter some information about your checking account. Once this wizard finishes, the account will be created for you within KMyMoney.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_haveCheckingAccountButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_accountDataFrame</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>m_accountNameEdit</tabstop>
+ <tabstop>m_accountNumberEdit</tabstop>
+ <tabstop>m_openingDateEdit</tabstop>
+ <tabstop>m_openingBalanceEdit</tabstop>
+ <tabstop>m_institutionNameEdit</tabstop>
+ <tabstop>m_institutionNumberEdit</tabstop>
+ <tabstop>m_haveCheckingAccountButton</tabstop>
+ <tabstop>kActiveLabel2</tabstop>
+ <tabstop>kActiveLabel1</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/kcurrencypagedecl.ui b/kmymoney2/wizards/newuserwizard/kcurrencypagedecl.ui
new file mode 100644
index 0000000..579bf1e
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kcurrencypagedecl.ui
@@ -0,0 +1,82 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KCurrencyPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KCurrencyPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>626</width>
+ <height>186</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel3</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>KMyMoney supports multiple currencies. Your reports will be based on a default curreny which you can select here. The default for new accounts is also the currency you select here.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KMyMoneySecuritySelector">
+ <property name="name">
+ <cstring>m_baseCurrencyEdit</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/kfilepagedecl.ui b/kmymoney2/wizards/newuserwizard/kfilepagedecl.ui
new file mode 100644
index 0000000..dcae784
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kfilepagedecl.ui
@@ -0,0 +1,86 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KFilePageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KFilePageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>350</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>KMyMoney will store your financial data in a file on the disk. A standard filename within your KDE user environment will be the default. This is just provided for convenience and you can choose any other location here.</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_dataFileEdit</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>m_existingFileLabel</cstring>
+ </property>
+ <property name="paletteForegroundColor">
+ <color>
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ <property name="text">
+ <string>Either the currently selected file exists or the selected directory does not exist. Please make sure, that
+
+&lt;ul&gt;
+&lt;li&gt;the selected directory exists and&lt;/li&gt;
+&lt;li&gt;the filename is not currently used in this directory.&lt;/li&gt;
+&lt;/ul&gt;</string>
+ </property>
+ </widget>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>m_finishLabel</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>This finishes the setup of your KMyMoney environment. You can now press the Finish button and start using KMyMoney to record your financial transactions.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/kgeneralpagedecl.ui b/kmymoney2/wizards/newuserwizard/kgeneralpagedecl.ui
new file mode 100644
index 0000000..916493d
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kgeneralpagedecl.ui
@@ -0,0 +1,258 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KGeneralPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KGeneralPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>415</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Please enter some information about yourself.&lt;br&gt;&lt;br&gt;
+
+This information will be seen and used only by you. The information is used to personalize KMyMoney, to encrypt your file, etc.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame8</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>25</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>County/State:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_userNameEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>m_countyEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>m_townEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Street:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_streetEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Email:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Your name:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Telephone:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Town:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="6" column="1">
+ <property name="name">
+ <cstring>m_emailEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Zip code</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="5" column="1">
+ <property name="name">
+ <cstring>m_telephoneEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_zipcodeEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_loadAddressButton</cstring>
+ </property>
+ <property name="text">
+ <string>Load from Addressbook</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame8_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>25</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/kintropagedecl.ui b/kmymoney2/wizards/newuserwizard/kintropagedecl.ui
new file mode 100644
index 0000000..d9dd326
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kintropagedecl.ui
@@ -0,0 +1,66 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KIntroPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KIntroPageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>415</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>16</pointsize>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Welcome to KMyMoney!</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>You have started KMyMoney for the first time on this computer. Before this program can help you to manage your finances, it needs to collect some data from you.&lt;p&gt;
+
+On the next few pages you will be guided through the steps necessary to setup the program. This will happen only once.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/knewuserwizard.cpp b/kmymoney2/wizards/newuserwizard/knewuserwizard.cpp
new file mode 100644
index 0000000..608afb6
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/knewuserwizard.cpp
@@ -0,0 +1,363 @@
+/***************************************************************************
+ knewuserwizard.cpp
+ -------------------
+ begin : Sat Feb 18 2006
+ copyright : (C) 2006 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <locale.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qdir.h>
+#include <qlabel.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <klistview.h>
+#include <kstandarddirs.h>
+#include <klineedit.h>
+#include <ktextedit.h>
+#include <kuser.h>
+#include <kurlrequester.h>
+#include <kio/netaccess.h>
+#include <kurl.h>
+#include <kabc/addressee.h>
+#include <kabc/stdaddressbook.h>
+#include <kmessagebox.h>
+#include <kactivelabel.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "knewuserwizard.h"
+#include "knewuserwizard_p.h"
+#include <kmymoney/mymoneysecurity.h>
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/kguiutils.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+#include <kmymoney/mymoneypayee.h>
+#include <kmymoney/mymoneymoney.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/kmymoneydateinput.h>
+#include <kmymoney/kmymoneyedit.h>
+#include <kmymoney/kaccounttemplateselector.h>
+
+#include "../../kmymoney2.h"
+#include "../../kmymoneyglobalsettings.h"
+
+using namespace NewUserWizard;
+
+static int stepCount;
+
+NewUserWizard::Wizard::Wizard(QWidget *parent, const char *name, bool modal, WFlags flags) :
+ KMyMoneyWizard(parent, name, modal, flags),
+ m_introPage(0)
+{
+ bool isFirstTime = KMyMoneyGlobalSettings::firstTimeRun();
+
+ stepCount = 1;
+
+ setTitle(i18n("KMyMoney New File Setup"));
+ if(isFirstTime)
+ addStep(i18n("Introduction"));
+ addStep(i18n("Personal Data"));
+ addStep(i18n("Select Currency"));
+ addStep(i18n("Select Accounts"));
+ addStep(i18n("Set preferences"));
+ addStep(i18n("Finish"));
+
+ if(isFirstTime)
+ m_introPage = new IntroPage(this);
+ m_generalPage = new GeneralPage(this);
+ m_currencyPage = new CurrencyPage(this);
+ m_accountPage = new AccountPage(this);
+ m_categoriesPage = new CategoriesPage(this);
+ m_preferencePage = new PreferencePage(this);
+ m_filePage = new FilePage(this);
+
+ m_accountPage->m_haveCheckingAccountButton->setChecked(true);
+ if(isFirstTime)
+ setFirstPage(m_introPage);
+ else
+ setFirstPage(m_generalPage);
+
+ setHelpContext("firsttime-3");
+}
+
+MyMoneyPayee NewUserWizard::Wizard::user(void) const
+{
+ return m_generalPage->user();
+}
+
+QString NewUserWizard::Wizard::url(void) const
+{
+ return m_filePage->m_dataFileEdit->url();
+}
+
+MyMoneyInstitution NewUserWizard::Wizard::institution(void) const
+{
+ MyMoneyInstitution inst;
+ if(m_accountPage->m_haveCheckingAccountButton->isChecked()) {
+ if(m_accountPage->m_institutionNameEdit->text().length()) {
+ inst.setName(m_accountPage->m_institutionNameEdit->text());
+ if(m_accountPage->m_institutionNumberEdit->text().length())
+ inst.setSortcode(m_accountPage->m_institutionNumberEdit->text());
+ }
+ }
+ return inst;
+}
+
+MyMoneyAccount NewUserWizard::Wizard::account(void) const
+{
+ MyMoneyAccount acc;
+ if(m_accountPage->m_haveCheckingAccountButton->isChecked()) {
+ acc.setName(m_accountPage->m_accountNameEdit->text());
+ if(m_accountPage->m_accountNumberEdit->text().length())
+ acc.setNumber(m_accountPage->m_accountNumberEdit->text());
+ acc.setOpeningDate(m_accountPage->m_openingDateEdit->date());
+ acc.setCurrencyId(m_baseCurrency.id());
+ acc.setAccountType(MyMoneyAccount::Checkings);
+ }
+ return acc;
+}
+
+MyMoneyMoney NewUserWizard::Wizard::openingBalance(void) const
+{
+ return m_accountPage->m_openingBalanceEdit->value();
+}
+
+MyMoneySecurity NewUserWizard::Wizard::baseCurrency(void) const
+{
+ return m_baseCurrency;
+}
+
+QValueList<MyMoneyTemplate> NewUserWizard::Wizard::templates(void) const
+{
+ return m_categoriesPage->selectedTemplates();
+}
+
+IntroPage::IntroPage(Wizard* wizard, const char* name) :
+ KIntroPageDecl(wizard),
+ WizardPage<Wizard>(stepCount++, this, wizard, name)
+{
+}
+
+KMyMoneyWizardPage* IntroPage::nextPage(void) const
+{
+ return m_wizard->m_generalPage;
+}
+
+GeneralPage::GeneralPage(Wizard* wizard, const char* name) :
+ UserInfo(wizard),
+ WizardPage<Wizard>(stepCount++, this, wizard, name)
+{
+ m_userNameEdit->setFocus();
+ KABC::StdAddressBook *ab = KABC::StdAddressBook::self(true);
+ connect(ab, SIGNAL(addressBookChanged(AddressBook*)), this, SLOT(slotAddressBookLoaded()));
+ connect(m_loadAddressButton, SIGNAL(clicked()), this, SLOT(slotLoadFromKABC()));
+ m_loadAddressButton->setEnabled(false);
+}
+
+void GeneralPage::slotAddressBookLoaded(void)
+{
+ KABC::StdAddressBook *ab = KABC::StdAddressBook::self();
+ if (!ab)
+ return;
+
+ m_loadAddressButton->setEnabled(!ab->whoAmI().isEmpty());
+}
+
+void GeneralPage::slotLoadFromKABC(void)
+{
+ KABC::StdAddressBook *ab = KABC::StdAddressBook::self();
+ if (!ab)
+ return;
+
+ KABC::Addressee addr = ab->whoAmI();
+ if ( addr.isEmpty() ) {
+ KMessageBox::sorry(this, i18n("Unable to load data, because no contact has been associated with the owner of the standard addressbook."), i18n("Addressbook import"));
+ return;
+ }
+
+ m_userNameEdit->setText( addr.formattedName() );
+ m_emailEdit->setText( addr.preferredEmail() );
+
+ KABC::PhoneNumber phone = addr.phoneNumber( KABC::PhoneNumber::Home );
+ m_telephoneEdit->setText( phone.number() );
+
+ KABC::Address a = addr.address( KABC::Address::Home );
+ QString sep;
+ if(!a.country().isEmpty() && !a.region().isEmpty())
+ sep = " / ";
+ m_countyEdit->setText(QString("%1%2%3").arg(a.country(), sep, a.region()));
+ m_postcodeEdit->setText( a.postalCode() );
+ m_townEdit->setText( a.locality() );
+ m_streetEdit->setText( a.street() );
+}
+
+KMyMoneyWizardPage* GeneralPage::nextPage(void) const
+{
+ return m_wizard->m_currencyPage;
+}
+
+CurrencyPage::CurrencyPage(Wizard* wizard, const char* name) :
+ Currency(wizard),
+ WizardPage<Wizard>(stepCount++, this, wizard, name)
+{
+ QListViewItem *first = 0;
+ QValueList<MyMoneySecurity> list = MyMoneyFile::instance()->currencyList();
+ QValueList<MyMoneySecurity>::const_iterator it;
+
+ QString localCurrency(localeconv()->int_curr_symbol);
+ localCurrency.truncate(3);
+
+ QString baseCurrency = MyMoneyFile::instance()->baseCurrency().id();
+
+ // construct a transparent 16x16 pixmap
+ QPixmap empty(16, 16);
+ empty.setMask(QBitmap(16, 16, true));
+
+ m_currencyList->clear();
+ for(it = list.begin(); it != list.end(); ++it) {
+ QListViewItem* p = insertCurrency(*it);
+ if((*it).id() == baseCurrency) {
+ first = p;
+ p->setPixmap(0, QPixmap( locate("icon","hicolor/16x16/apps/kmymoney2.png")));
+ } else {
+ p->setPixmap(0, empty);
+ }
+ if(!first && (*it).id() == localCurrency)
+ first = p;
+ }
+
+ if(first == 0)
+ first = m_currencyList->firstChild();
+ if(first != 0) {
+ m_currencyList->setCurrentItem(first);
+ m_currencyList->setSelected(first, true);
+ m_currencyList->ensureItemVisible(first);
+ }
+}
+
+void CurrencyPage::enterPage(void)
+{
+ m_currencyList->setFocus();
+}
+
+
+KMyMoneyWizardPage* CurrencyPage::nextPage(void) const
+{
+ m_wizard->m_baseCurrency = MyMoneyFile::instance()->security(selectedCurrency());
+ m_wizard->m_accountPage->m_accountCurrencyLabel->setText(m_wizard->m_baseCurrency.tradingSymbol());
+ return m_wizard->m_accountPage;
+}
+
+AccountPage::AccountPage(Wizard* wizard, const char* name) :
+ KAccountPageDecl(wizard, name),
+ WizardPage<Wizard>(stepCount, this, wizard, name) // don't inc. the step count here
+{
+ m_mandatoryGroup->add(m_accountNameEdit);
+ connect(m_mandatoryGroup, SIGNAL(stateChanged()), object(), SIGNAL(completeStateChanged()));
+ connect(m_haveCheckingAccountButton, SIGNAL(toggled(bool)), object(), SIGNAL(completeStateChanged()));
+ m_accountNameEdit->setFocus();
+ m_openingDateEdit->setDate(QDate(QDate::currentDate().year(),1,1));
+}
+
+KMyMoneyWizardPage* AccountPage::nextPage(void) const
+{
+ return m_wizard->m_categoriesPage;
+}
+
+bool AccountPage::isComplete(void) const
+{
+ return !m_haveCheckingAccountButton->isChecked() || m_mandatoryGroup->isEnabled();
+}
+
+CategoriesPage::CategoriesPage(Wizard* wizard, const char* name) :
+ Accounts(wizard),
+ WizardPage<Wizard>(stepCount++, this, wizard, name)
+{
+}
+
+KMyMoneyWizardPage* CategoriesPage::nextPage(void) const
+{
+ return m_wizard->m_preferencePage;
+}
+
+QValueList<MyMoneyTemplate> CategoriesPage::selectedTemplates(void) const
+{
+ return m_templateSelector->selectedTemplates();
+}
+
+PreferencePage::PreferencePage(Wizard* wizard, const char* name) :
+ KPreferencePageDecl(wizard),
+ WizardPage<Wizard>(stepCount++, this, wizard, name)
+{
+ connect(m_openConfigButton, SIGNAL(clicked()), kmymoney2, SLOT(slotSettings()));
+}
+
+KMyMoneyWizardPage* PreferencePage::nextPage(void) const
+{
+ return m_wizard->m_filePage;
+}
+
+FilePage::FilePage(Wizard* wizard, const char* name) :
+ KFilePageDecl(wizard),
+ WizardPage<Wizard>(stepCount++, this, wizard, name)
+{
+ m_mandatoryGroup->add(m_dataFileEdit->lineEdit());
+ connect(m_mandatoryGroup, SIGNAL(stateChanged()), object(), SIGNAL(completeStateChanged()));
+
+ KUser user;
+ m_dataFileEdit->setShowLocalProtocol(false);
+ m_dataFileEdit->setURL(QString("%1/%2.kmy").arg(QDir::homeDirPath(), user.loginName()));
+
+ // allow selection of non-existing files
+ m_dataFileEdit->setMode(KFile::File);
+}
+
+bool FilePage::isComplete(void) const
+{
+ bool rc = m_mandatoryGroup->isEnabled();
+ m_existingFileLabel->hide();
+ m_finishLabel->show();
+ if(rc) {
+ // if a filename is present, check that
+ // a) the file does not exist
+ // b) the directory does exist
+ rc = !KIO::NetAccess::exists(m_dataFileEdit->url(), false, m_wizard);
+ if(rc) {
+ QRegExp exp("(.*)/(.*)");
+ rc = false;
+ if(exp.search(m_dataFileEdit->url()) != -1) {
+ if(exp.cap(2).length() > 0) {
+ rc = KIO::NetAccess::exists(exp.cap(1), true, m_wizard);
+ }
+ }
+ }
+ m_existingFileLabel->setHidden(rc);
+ m_finishLabel->setShown(rc);
+ }
+ return rc;
+}
+
+#include "knewuserwizard.moc"
diff --git a/kmymoney2/wizards/newuserwizard/knewuserwizard.h b/kmymoney2/wizards/newuserwizard/knewuserwizard.h
new file mode 100644
index 0000000..a8cd8d5
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/knewuserwizard.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ knewuserwizard.h
+ -------------------
+ begin : Sat Feb 18 2006
+ copyright : (C) 2006 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWUSERWIZARD_H
+#define KNEWUSERWIZARD_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QString;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneywizard.h>
+#include <kmymoney/mymoneysecurity.h>
+class MyMoneyPayee;
+class MyMoneyInstitution;
+class MyMoneyAccount;
+class MyMoneyMoney;
+class MyMoneyTemplate;
+
+/**
+ * @author Thomas Baumgart
+ */
+namespace NewUserWizard {
+
+class IntroPage;
+class GeneralPage;
+class CurrencyPage;
+class AccountPage;
+class CategoriesPage;
+class PreferencePage;
+class FilePage;
+
+/**
+ * @author Thomas Baumgart
+ *
+ * This class implements the new user wizard which is used to gather
+ * some initial information from the user who creates a new KMyMoney
+ * 'file'.
+ */
+class Wizard : public KMyMoneyWizard
+{
+ friend class IntroPage;
+ friend class GeneralPage;
+ friend class CurrencyPage;
+ friend class AccountPage;
+ friend class CategoriesPage;
+ friend class PreferencePage;
+ friend class FilePage;
+
+ Q_OBJECT
+public:
+ Wizard(QWidget* parent = 0, const char* name = 0, bool modal = false, WFlags flags = 0);
+ /**
+ * Returns the personal information of the user (e.g. name, address, etc.)
+ */
+ MyMoneyPayee user(void) const;
+
+ /**
+ * Returns the URL that the user has chosen to store the file
+ */
+ QString url(void) const;
+
+ /**
+ * Returns the information about an institution if entered by
+ * the user. If the name field is empty, then he did not enter
+ * such information.
+ */
+ MyMoneyInstitution institution(void) const;
+
+ /**
+ * Returns the information about a checking account if entered by
+ * the user. If the name field is empty, then he did not enter
+ * such information.
+ */
+ MyMoneyAccount account(void) const;
+
+ /**
+ * Returns the opening balance value provided by the user. not enter
+ */
+ MyMoneyMoney openingBalance(void) const;
+
+ /**
+ * Returns the security to be used as base currency.
+ */
+ MyMoneySecurity baseCurrency(void) const;
+
+ /**
+ * Returns a list of templates including accounts to be created
+ */
+ QValueList<MyMoneyTemplate> templates(void) const;
+
+private:
+ MyMoneySecurity m_baseCurrency;
+ IntroPage* m_introPage;
+ GeneralPage* m_generalPage;
+ CurrencyPage* m_currencyPage;
+ AccountPage* m_accountPage;
+ CategoriesPage* m_categoriesPage;
+ PreferencePage* m_preferencePage;
+ FilePage* m_filePage;
+};
+
+}; // namespace
+
+
+#endif
diff --git a/kmymoney2/wizards/newuserwizard/knewuserwizard_p.h b/kmymoney2/wizards/newuserwizard/knewuserwizard_p.h
new file mode 100644
index 0000000..aa62725
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/knewuserwizard_p.h
@@ -0,0 +1,140 @@
+/***************************************************************************
+ knewuserwizard_p.h
+ -------------------
+ begin : Sat Feb 18 2006
+ copyright : (C) 2006 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNEWUSERWIZARD_P_H
+#define KNEWUSERWIZARD_P_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/kmymoneywizard.h>
+
+#include "kintropagedecl.h"
+#include "kaccountpagedecl.h"
+#include "kpreferencepagedecl.h"
+#include "kfilepagedecl.h"
+
+#include "../wizardpages/userinfo.h"
+#include "../wizardpages/currency.h"
+#include "../wizardpages/accounts.h"
+
+#include <kmymoney/mymoneytemplate.h>
+
+class Wizard;
+
+namespace NewUserWizard {
+
+class IntroPage : public KIntroPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ IntroPage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+};
+
+/**
+ * Wizard page collecting information about the user
+ *
+ * @author Thomas Baumgart
+ */
+class GeneralPage : public UserInfo, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ GeneralPage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+
+protected slots:
+ void slotLoadFromKABC(void);
+ void slotAddressBookLoaded(void);
+
+};
+
+/**
+ * Wizard page collecting information about the base currency
+ *
+ * @author Thomas Baumgart
+ */
+class CurrencyPage : public Currency, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ CurrencyPage(Wizard* parent, const char* name = 0);
+ void enterPage(void);
+ KMyMoneyWizardPage* nextPage(void) const;
+};
+
+/**
+ * Wizard page collecting information about the checking account
+ */
+class AccountPage : public KAccountPageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ AccountPage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+
+ virtual bool isComplete(void) const;
+};
+
+/**
+ * Wizard page collecting information about the account templates.
+ *
+ * @author Thomas Baumgart
+ */
+class CategoriesPage : public Accounts, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ CategoriesPage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+ QValueList<MyMoneyTemplate> selectedTemplates(void) const;
+};
+
+/**
+ * Wizard page to allow changing the preferences during setup
+ *
+ * @author Thomas Baumgart
+ */
+class PreferencePage : public KPreferencePageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ PreferencePage(Wizard* parent, const char* name = 0);
+ KMyMoneyWizardPage* nextPage(void) const;
+};
+
+/**
+ * Wizard page to allow selecting the filename
+ *
+ * @author Thomas Baumgart
+ */
+class FilePage : public KFilePageDecl, public WizardPage<Wizard>
+{
+ Q_OBJECT
+public:
+ FilePage(Wizard* parent, const char* name = 0);
+
+ virtual bool isComplete(void) const;
+};
+
+} // namespace
+
+#endif
diff --git a/kmymoney2/wizards/newuserwizard/kpasswordpagedecl.ui b/kmymoney2/wizards/newuserwizard/kpasswordpagedecl.ui
new file mode 100644
index 0000000..3d3c062
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kpasswordpagedecl.ui
@@ -0,0 +1,33 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPasswordPageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KPasswordPageDecl</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>599</width>
+ <height>149</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;p&gt;KMyMoney can encrypt your datafile using GPG Encryption. GPG encryption is one of the most secure methods in the world for protecting data. All of your account numbers and other important financial information will be very secure.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/newuserwizard/kpreferencepagedecl.ui b/kmymoney2/wizards/newuserwizard/kpreferencepagedecl.ui
new file mode 100644
index 0000000..bfe6446
--- /dev/null
+++ b/kmymoney2/wizards/newuserwizard/kpreferencepagedecl.ui
@@ -0,0 +1,96 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KPreferencePageDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KPreferencePageDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>288</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>If you would like to review or change any preference settings for KMyMoney at this time, you can do so here. If not just click &lt;b&gt;Next&lt;/b&gt;.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_openConfigButton</cstring>
+ </property>
+ <property name="text">
+ <string>Configure preferences now</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>You can change the configuration options at any time using the configuration dialog. Just select the &lt;b&gt;Configure KMyMoney...&lt;/b&gt; option in the &lt;b&gt;Settings&lt;/b&gt; menu.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/wizardpages/Makefile.am b/kmymoney2/wizards/wizardpages/Makefile.am
new file mode 100644
index 0000000..65ea6a7
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LIBRARIES = libwizardpages.a
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+
+libwizardpages_a_METASOURCES = AUTO
+
+libwizardpages_a_SOURCES = userinfodecl.ui userinfo.cpp currencydecl.ui currency.cpp accountsdecl.ui accounts.cpp
+
+EXTRA_DIST = userinfodecl.ui currencydecl.ui accountsdecl.ui
+
+DISTCLEANFILES= userinfodecl.cpp userinfodecl.h currencydecl.cpp currencydecl.h accountsdecl.cpp accountsdecl.h
+
+noinst_HEADERS = userinfo.h currency.h accounts.h
+
+SUBDIRS =
+
+messages: rc.cpp
diff --git a/kmymoney2/wizards/wizardpages/accounts.cpp b/kmymoney2/wizards/wizardpages/accounts.cpp
new file mode 100644
index 0000000..0a6c82b
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/accounts.cpp
@@ -0,0 +1,39 @@
+/***************************************************************************
+ accounts.cpp
+ -------------------
+ begin : Fri Jun 1 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qheader.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klistview.h>
+#include <kmymoney/kmymoneyaccounttree.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "accounts.h"
+
+Accounts::Accounts(QWidget* parent, const char* name) :
+ AccountsDecl(parent, name)
+{
+}
+
+#include "accounts.moc"
diff --git a/kmymoney2/wizards/wizardpages/accounts.h b/kmymoney2/wizards/wizardpages/accounts.h
new file mode 100644
index 0000000..d1f3175
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/accounts.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ accounts.h
+ -------------------
+ begin : Fri Jun 1 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef ACCOUNTS_H
+#define ACCOUNTS_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "accountsdecl.h"
+
+/**
+ * @author Thomas Baumgart
+ */
+class Accounts : public AccountsDecl
+{
+ Q_OBJECT
+public:
+ Accounts(QWidget* parent = 0, const char* name = 0);
+
+private:
+};
+
+
+#endif
diff --git a/kmymoney2/wizards/wizardpages/accountsdecl.ui b/kmymoney2/wizards/wizardpages/accountsdecl.ui
new file mode 100644
index 0000000..9e7b7c9
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/accountsdecl.ui
@@ -0,0 +1,54 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AccountsDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>AccountsDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>550</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Select groups of accounts that correspond to the ways that you will use KMyMoney. Each group you select will cause several accounts and categories to be created. Select the groups that are relevant to you. You can always create additional accounts manually later.</string>
+ </property>
+ </widget>
+ <widget class="KAccountTemplateSelector">
+ <property name="name">
+ <cstring>m_templateSelector</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/wizardpages/currency.cpp b/kmymoney2/wizards/wizardpages/currency.cpp
new file mode 100644
index 0000000..8693089
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/currency.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ userinfo.cpp
+ -------------------
+ begin : Fri Jun 1 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <klistview.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "currency.h"
+
+Currency::Currency(QWidget* parent, const char* name) :
+ CurrencyDecl(parent, name)
+{
+ m_currencyList->setAllColumnsShowFocus(true);
+ m_currencyList->setMultiSelection(false);
+}
+
+QListViewItem* Currency::insertCurrency(const MyMoneySecurity& sec)
+{
+ return new KListViewItem(m_currencyList, sec.name(), QString(sec.id()), sec.tradingSymbol());
+}
+
+void Currency::selectCurrency(const MyMoneySecurity& sec)
+{
+ QListViewItem* it_v;
+ QListViewItemIterator it(m_currencyList);
+ while((it_v = it.current()) != 0) {
+ if(it_v->text(1) == QString(sec.id())) {
+ m_currencyList->setSelected(it_v, true);
+ m_currencyList->ensureItemVisible(it_v);
+ break;
+ }
+ }
+}
+
+QString Currency::selectedCurrency(void) const
+{
+ QString id;
+ if(m_currencyList->selectedItem()) {
+ id = m_currencyList->selectedItem()->text(1);
+ }
+ return id;
+}
+
+#include "currency.moc"
diff --git a/kmymoney2/wizards/wizardpages/currency.h b/kmymoney2/wizards/wizardpages/currency.h
new file mode 100644
index 0000000..1ce2649
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/currency.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ currency.h
+ -------------------
+ begin : Fri Jun 1 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CURRENCY_H
+#define CURRENCY_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class KListViewItem;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "currencydecl.h"
+#include <kmymoney/mymoneysecurity.h>
+
+/**
+ * @author Thomas Baumgart
+ */
+class Currency : public CurrencyDecl
+{
+ Q_OBJECT
+public:
+ Currency(QWidget* parent = 0, const char* name = 0);
+ QListViewItem* insertCurrency(const MyMoneySecurity& sec);
+ void selectCurrency(const MyMoneySecurity& sec);
+ QString selectedCurrency(void) const;
+};
+
+#endif
diff --git a/kmymoney2/wizards/wizardpages/currencydecl.ui b/kmymoney2/wizards/wizardpages/currencydecl.ui
new file mode 100644
index 0000000..f2b857a
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/currencydecl.ui
@@ -0,0 +1,96 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>CurrencyDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CurrencyDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>573</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;p&gt;KMyMoney supports multiple currencies, nevertheless one of them will be used as your base currency. The base currency is used as default for new accounts and reports. Please select the base currency from the following list.</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>ISO Code</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Symbol</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_currencyList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/wizards/wizardpages/userinfo.cpp b/kmymoney2/wizards/wizardpages/userinfo.cpp
new file mode 100644
index 0000000..412c5a1
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/userinfo.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+ userinfo.cpp
+ -------------------
+ begin : Fri Jun 1 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <klineedit.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "userinfo.h"
+#include <kmymoney/mymoneypayee.h>
+
+UserInfo::UserInfo(QWidget* parent, const char* name) :
+ UserInfoDecl(parent, name)
+{
+ m_userNameEdit->setFocus();
+}
+
+MyMoneyPayee UserInfo::user(void) const
+{
+ MyMoneyPayee user;
+ user.setName(m_userNameEdit->text());
+ user.setAddress(m_streetEdit->text());
+ user.setCity(m_townEdit->text());
+ user.setState(m_countyEdit->text());
+ user.setPostcode(m_postcodeEdit->text());
+ user.setTelephone(m_telephoneEdit->text());
+ user.setEmail(m_emailEdit->text());
+ return user;
+}
+
+#include "userinfo.moc"
diff --git a/kmymoney2/wizards/wizardpages/userinfo.h b/kmymoney2/wizards/wizardpages/userinfo.h
new file mode 100644
index 0000000..9242868
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/userinfo.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ userinfo.h
+ -------------------
+ begin : Fri Jun 1 2007
+ copyright : (C) 2007 Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef USERINFO_H
+#define USERINFO_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "userinfodecl.h"
+class MyMoneyPayee;
+
+/**
+ * @author Thomas Baumgart
+ */
+class UserInfo : public UserInfoDecl
+{
+ Q_OBJECT
+public:
+ UserInfo(QWidget* parent = 0, const char* name = 0);
+ MyMoneyPayee user(void) const;
+
+private:
+};
+
+
+#endif
diff --git a/kmymoney2/wizards/wizardpages/userinfodecl.ui b/kmymoney2/wizards/wizardpages/userinfodecl.ui
new file mode 100644
index 0000000..4240d49
--- /dev/null
+++ b/kmymoney2/wizards/wizardpages/userinfodecl.ui
@@ -0,0 +1,225 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>UserInfoDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>UserInfoDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>603</width>
+ <height>374</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KActiveLabel" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p&gt;Use the fields below to enter some information about yourself.&lt;/p&gt;
+
+&lt;p&gt;All information is optional and only used to personalize your KMyMoney file.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_userNameEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Town:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>County/State:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Street:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_streetEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="6" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_emailEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_townEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="5" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_telephoneEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Email:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Telephone:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Your name:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="7" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>layout22</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_loadAddressButton</cstring>
+ </property>
+ <property name="text">
+ <string>Load from Addressbook</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>305</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer row="8" column="2">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>m_countyEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Postal Code:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="3">
+ <property name="name">
+ <cstring>m_postcodeEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>m_userNameEdit</tabstop>
+ <tabstop>m_streetEdit</tabstop>
+ <tabstop>m_townEdit</tabstop>
+ <tabstop>m_countyEdit</tabstop>
+ <tabstop>m_postcodeEdit</tabstop>
+ <tabstop>m_telephoneEdit</tabstop>
+ <tabstop>m_emailEdit</tabstop>
+ <tabstop>m_loadAddressButton</tabstop>
+ <tabstop>kActiveLabel1</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/x-kmymoney2.desktop b/kmymoney2/x-kmymoney2.desktop
new file mode 100644
index 0000000..2ec91ef
--- /dev/null
+++ b/kmymoney2/x-kmymoney2.desktop
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Encoding=UTF-8
+Comment=KMyMoney File
+Comment[de]=KMyMoney-Datei
+Comment[fr]=Fichier KMyMoney
+Comment[tr]=KMyMoney Dosyası
+Comment[ro]=Fișier KMyMoney
+Comment[ru]=Финансовые данные KMyMoney
+Comment[zh_CN]=KMyMoney文件
+Icon=kmy
+Type=MimeType
+MimeType=application/x-kmymoney
+Patterns=*.kmy;*.kmt;